Initial commit
This commit is contained in:
parent
7fb0a74b7e
commit
3dcaf6df81
126
Makefile
Normal file
126
Makefile
Normal file
|
@ -0,0 +1,126 @@
|
|||
MAKEFLAGS := --jobs=$(shell nproc)
|
||||
|
||||
TARGET := game
|
||||
INFO :=
|
||||
|
||||
EDITOR := 1
|
||||
DEBUG := 1
|
||||
|
||||
UNAME := $(shell uname)
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
UNAME := Windows_NT
|
||||
endif
|
||||
|
||||
UNAME_P := $(shell uname -m)
|
||||
|
||||
#CC specifies which compiler we're using
|
||||
CC = clang -x c --std=c99
|
||||
CXX = clang++
|
||||
|
||||
DEFFLAGS :=
|
||||
|
||||
ifeq ($(EDITOR), 1)
|
||||
DEFFLAGS += -DEDITOR
|
||||
TARGET = editor
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
DEFFALGS += -DDEBUG
|
||||
INFO = dbg
|
||||
endif
|
||||
|
||||
BINDIR := ./bin
|
||||
BUILDDIR := ./obj
|
||||
|
||||
THIRDPARTY_DIR := ./source/thirdparty
|
||||
THIRDPARTY_DIRS := ${sort ${dir ${wildcard ${THIRDPARTY_DIR}/*/}}}
|
||||
THIRDPARTY_I := $(addsuffix include, ${THIRDPARTY_DIRS}) $(addsuffix src, $(THIRDPARTY_DIRS)) $(THIRDPARTY_DIRS) $(addsuffix build/include, $(THIRDPARTY_DIRS)) $(addsuffix include/chipmunk, $(THIRDPARTY_DIRS))
|
||||
THIRDPARTY_L := $(addsuffix build/lib, $(THIRDPARTY_DIRS)) $(addsuffix build, ${THIRDPARTY_DIRS}) $(addsuffix build/bin, $(THIRDPARTY_DIRS) $(addsuffix build/src, $(THIRDPARTY_DIRS)))
|
||||
|
||||
# imgui sources
|
||||
IMGUI_DIR := ${THIRDPARTY_DIR}/imgui
|
||||
imgui = $(addprefix ${IMGUI_DIR}/, imgui imgui_draw imgui_widgets imgui_tables)
|
||||
imguibackends = $(addprefix ${IMGUI_DIR}/backends/, imgui_impl_sdl imgui_impl_opengl3)
|
||||
imguiobjs := $(addsuffix .cpp, $(imgui) $(imguibackends))
|
||||
|
||||
plmpeg_objs := ${THIRDPARTY_DIR}/pl_mpeg/pl_mpeg_extract_frames.c
|
||||
cpobjs := $(wildcard ${THIRDPARTY_DIR}/Chipmunk2D/src/*.c)
|
||||
s7objs := ${THIRDPARTY_DIR}/s7/s7.c
|
||||
|
||||
includeflag := $(addprefix -I, $(THIRDPARTY_I) ./source/engine ./source/editor $(IMGUI_DIR) $(IMGUI_DIR)/backends)
|
||||
|
||||
#LIBRARY_PATHS specifies the additional library paths we'll need
|
||||
LIB_PATHS := $(addprefix -L, $(THIRDPARTY_L))
|
||||
|
||||
# Engine sources
|
||||
sources := $(wildcard ./source/engine/*.cpp ./source/engine/*.c ./source/editor/*.c ./source/editor/*.cpp) $(imguiobjs) $(s7objs) $(cpobjs)
|
||||
|
||||
#COMPILER_FLAGS specifies the additional compilation options we're using
|
||||
WARNING_FLAGS := -w #-pedantic -Wall -Wextra -Wwrite-strings
|
||||
COMPILER_FLAGS := -g -O0 $(WARNING_FLAGS)
|
||||
|
||||
|
||||
ifeq ($(UNAME), Windows_NT)
|
||||
LINKER_FLAGS:= -static
|
||||
# DYNAMIC LIBS: SDL2 opengl32
|
||||
ELIBS := glew32 mingw32 SDL2main SDL2 m dinput8 dxguid dxerr8 user32 gdi32 winmm imm32 ole32 oleaut32 shell32 version uuid setupapi opengl32 stdc++ winpthread
|
||||
CLIBS :=
|
||||
EXT := .exe
|
||||
else
|
||||
LINKER_FLAGS :=
|
||||
ELIBS :=
|
||||
CLIBS := SDL2 GLEW GL dl pthread
|
||||
EXT :=
|
||||
endif
|
||||
|
||||
LELIBS := -Wl,-Bstatic $(addprefix -l, ${ELIBS}) -Wl,-Bdynamic $(addprefix -l, $(CLIBS))
|
||||
|
||||
BUILDD = -DGLEW_STATIC
|
||||
|
||||
dir_guard = @mkdir -p $(@D)
|
||||
|
||||
objprefix = ./obj/$(UNAME)/$(UNAME_P)/$(TARGET)$(INFO)
|
||||
|
||||
objects := $(patsubst .%.cpp, $(objprefix)%.o, $(filter %.cpp, $(sources))) $(patsubst .%.c, $(objprefix)%.o, $(filter %.c, $(sources)))
|
||||
objects := $(sort $(objects))
|
||||
depends := $(patsubst %.o, %.d, $(objects))
|
||||
|
||||
FILENAME = $(TARGET)$(INFO)_$(UNAME_P)$(EXT)
|
||||
|
||||
all: install
|
||||
|
||||
$(TARGET): $(objects)
|
||||
@echo Linking $(TARGET)
|
||||
@$(CXX) $^ -DGLEW_STATIC $(LINKER_FLAGS) $(LIB_PATHS) $(LELIBS) -o $@
|
||||
|
||||
install: $(TARGET)
|
||||
mkdir -p bin/$(UNAME) && cp $(TARGET) bin/$(UNAME)/$(FILENAME)
|
||||
cp $(TARGET) yugine/$(FILENAME)
|
||||
rm $(TARGET)
|
||||
|
||||
-include $(depends)
|
||||
|
||||
$(objprefix)/%.o:%.cpp
|
||||
$(dir_guard)
|
||||
@echo Making C++ object $(notdir $@)
|
||||
-@$(CXX) $(BUILDD) $(DEFFLAGS) $(includeflag) $(COMPILER_FLAGS) -MD -c $< -o $@
|
||||
|
||||
$(objprefix)/%.o:%.c
|
||||
$(dir_guard)
|
||||
@echo Making C object $(notdir $@)
|
||||
-@$(CC) $(BUILDD) $(DEFFLAGS) $(includeflag) $(COMPILER_FLAGS) -MD -c $< -o $@
|
||||
|
||||
clean:
|
||||
@echo Cleaning project
|
||||
@rm -f $(objects) $(depends)
|
||||
|
||||
bsclean:
|
||||
rm -f $(bsobjects)
|
||||
|
||||
gameclean:
|
||||
rm -f $(gameobjects)
|
||||
|
||||
TAGS: $(sources) $(edsources)
|
||||
@echo Generating TAGS file
|
||||
@ctags -eR $^
|
8
source/editor/debug.c
Normal file
8
source/editor/debug.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "debug.h"
|
||||
|
||||
unsigned long long triCount = 0;
|
||||
|
||||
void resetTriangles()
|
||||
{
|
||||
triCount = 0;
|
||||
}
|
9
source/editor/debug.h
Normal file
9
source/editor/debug.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef DEBUG_GUI_H
|
||||
#define DEBUG_GUI_H
|
||||
|
||||
extern unsigned long long triCount;
|
||||
|
||||
void resetTriangles();
|
||||
|
||||
|
||||
#endif
|
154
source/editor/debugdraw.c
Normal file
154
source/editor/debugdraw.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
#include "debugdraw.h"
|
||||
|
||||
#include "openglrender.h"
|
||||
|
||||
#include "shader.h"
|
||||
|
||||
static uint32_t circleVBO;
|
||||
static uint32_t circleVAO;
|
||||
static struct mShader *circleShader;
|
||||
|
||||
static uint32_t gridVBO;
|
||||
static uint32_t gridVAO;
|
||||
static struct mShader *gridShader;
|
||||
|
||||
static uint32_t rectVBO;
|
||||
static uint32_t rectVAO;
|
||||
static struct mShader *rectShader;
|
||||
|
||||
void debugdraw_init()
|
||||
{
|
||||
circleShader = MakeShader("circlevert.glsl", "circlefrag.glsl");
|
||||
shader_setUBO(circleShader, "Projection", 0);
|
||||
glGenBuffers(1, &circleVBO);
|
||||
glGenVertexArrays(1, &circleVAO);
|
||||
|
||||
|
||||
float gridverts[] = {
|
||||
-1.f, -1.f,
|
||||
1.f, -1.f,
|
||||
-1.f, 1.f,
|
||||
1.f, 1.f
|
||||
};
|
||||
|
||||
gridShader = MakeShader("gridvert.glsl", "gridfrag.glsl");
|
||||
shader_setUBO(gridShader, "Projection", 0);
|
||||
glGenBuffers(1, &gridVBO);
|
||||
glGenVertexArrays(1, &gridVAO);
|
||||
glBindVertexArray(gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(gridverts), &gridverts,
|
||||
GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
|
||||
rectShader = MakeShader("linevert.glsl", "linefrag.glsl");
|
||||
shader_setUBO(rectShader, "Projection", 0);
|
||||
glGenBuffers(1, &rectVBO);
|
||||
glGenVertexArrays(1, &rectVAO);
|
||||
}
|
||||
|
||||
void draw_line(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
shader_use(rectShader);
|
||||
float verts[] = {
|
||||
x1, y1,
|
||||
x2, y2
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
|
||||
glBindVertexArray(rectVAO);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, 2);
|
||||
}
|
||||
|
||||
void draw_edge(float *points, int n)
|
||||
{
|
||||
shader_use(rectShader);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * n * 2, points,
|
||||
GL_DYNAMIC_DRAW);
|
||||
glBindVertexArray(rectVAO);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, n);
|
||||
}
|
||||
|
||||
void draw_circle(int x, int y, float radius, int pixels)
|
||||
{
|
||||
shader_use(circleShader);
|
||||
|
||||
float verts[] = {
|
||||
x - radius, y - radius, -1.f, -1.f,
|
||||
x + radius, y - radius, 1.f, -1.f,
|
||||
x - radius, y + radius, -1.f, 1.f,
|
||||
x + radius, y + radius, 1.f, 1.f
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, circleVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
|
||||
|
||||
shader_setfloat(circleShader, "radius", radius);
|
||||
shader_setint(circleShader, "thickness", pixels);
|
||||
|
||||
glBindVertexArray(circleVAO);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
void draw_rect(int x, int y, int w, int h)
|
||||
{
|
||||
float hw = w / 2.f;
|
||||
float hh = h / 2.f;
|
||||
|
||||
float verts[] = {
|
||||
x - hw, y - hh,
|
||||
x + hw, y - hh,
|
||||
x + hw, y + hh,
|
||||
x - hw, y + hh
|
||||
};
|
||||
|
||||
shader_use(rectShader);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts, GL_DYNAMIC_DRAW);
|
||||
glBindVertexArray(rectVAO);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, 4);
|
||||
}
|
||||
|
||||
void draw_grid(int width, int span)
|
||||
{
|
||||
shader_use(gridShader);
|
||||
shader_setint(gridShader, "thickness", width);
|
||||
shader_setint(gridShader, "span", span);
|
||||
glBindVertexArray(gridVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void draw_point(int x, int y, float r)
|
||||
{
|
||||
draw_circle(x, y, r, r);
|
||||
}
|
||||
|
||||
void draw_poly(float *points, int n)
|
||||
{
|
||||
shader_use(rectShader);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, rectVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * n * 2, points,
|
||||
GL_DYNAMIC_DRAW);
|
||||
glBindVertexArray(rectVAO);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, n);
|
||||
}
|
||||
|
||||
void debugdraw_flush()
|
||||
{
|
||||
|
||||
}
|
16
source/editor/debugdraw.h
Normal file
16
source/editor/debugdraw.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef DEBUGDRAW_H
|
||||
#define DEBUGDRAW_H
|
||||
|
||||
void debugdraw_init();
|
||||
void draw_line(int x1, int y1, int x2, int y2);
|
||||
void draw_edge(float *points, int n);
|
||||
void draw_circle(int x, int y, float radius, int pixels);
|
||||
void draw_grid(int width, int span);
|
||||
void draw_rect(int x, int y, int w, int h);
|
||||
void draw_point(int x, int y, float r);
|
||||
void draw_poly(float *points, int n);
|
||||
|
||||
void debugdraw_flush(); /* This is called once per frame to draw all queued elements */
|
||||
|
||||
|
||||
#endif
|
1432
source/editor/editor.cpp
Normal file
1432
source/editor/editor.cpp
Normal file
File diff suppressed because it is too large
Load diff
98
source/editor/editor.h
Normal file
98
source/editor/editor.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#ifndef EDITOR_H
|
||||
#define EDITOR_H
|
||||
|
||||
#include "config.h"
|
||||
#include <SDL.h>
|
||||
#include <stdbool.h>
|
||||
#include "resources.h"
|
||||
|
||||
|
||||
struct mCamera;
|
||||
|
||||
#define ASSET_TYPE_NULL 0
|
||||
#define ASSET_TYPE_IMAGE 1
|
||||
#define ASSET_TYPE_TEXT 2
|
||||
|
||||
struct fileasset {
|
||||
char *filename;
|
||||
short extension_len;
|
||||
short filename_len;
|
||||
bool searched;
|
||||
short type;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct editorVars {
|
||||
bool showStats;
|
||||
bool showHierarchy;
|
||||
bool showLighting;
|
||||
bool showGameSettings;
|
||||
bool showViewmode;
|
||||
bool showDebugMenu;
|
||||
bool showAssetMenu;
|
||||
bool showREPL;
|
||||
bool showExport;
|
||||
bool showLevel;
|
||||
};
|
||||
|
||||
struct gameproject {
|
||||
char name[127];
|
||||
char path[MAXPATH];
|
||||
};
|
||||
|
||||
struct Texture;
|
||||
|
||||
void pickGameObject(int pickID);
|
||||
int is_allowed_extension(const char *ext);
|
||||
|
||||
void editor_init(struct mSDLWindow *mwindow);
|
||||
void editor_input(SDL_Event * e);
|
||||
void editor_render();
|
||||
int editor_wantkeyboard();
|
||||
void editor_save();
|
||||
void editor_makenewobject();
|
||||
|
||||
void editor_project_gui();
|
||||
|
||||
void editor_init_project(struct gameproject *gp);
|
||||
void editor_save_projects();
|
||||
void editor_load_projects();
|
||||
void editor_proj_select_gui();
|
||||
void editor_import_project(char *path);
|
||||
void editor_make_project(char *path);
|
||||
|
||||
void editor_selectasset(struct fileasset *asset);
|
||||
void editor_selectasset_str(char *path);
|
||||
void editor_asset_gui(struct fileasset *asset);
|
||||
void editor_asset_tex_gui(struct Texture *tex);
|
||||
void editor_asset_text_gui(char *text);
|
||||
|
||||
void editor_level_btn(char *level);
|
||||
void editor_prefab_btn(char *prefab);
|
||||
|
||||
void game_start();
|
||||
void game_resume();
|
||||
void game_stop();
|
||||
void game_pause();
|
||||
|
||||
void get_levels();
|
||||
|
||||
///////// Object GUIs
|
||||
void light_gui(struct mLight *light);
|
||||
void pointlight_gui(struct mPointLight *light);
|
||||
void spotlight_gui(struct mSpotLight *spot);
|
||||
void staticactor_gui(struct mStaticActor *sa);
|
||||
void trans_drawgui(struct mTransform *T);
|
||||
void object_gui(struct mGameObject *go);
|
||||
void sprite_gui(struct mSprite *sprite);
|
||||
void circle_gui(struct phys2d_circle *circle);
|
||||
void segment_gui(struct phys2d_segment *seg);
|
||||
void box_gui(struct phys2d_box *box);
|
||||
void poly_gui(struct phys2d_poly *poly);
|
||||
void edge_gui(struct phys2d_edge *edge);
|
||||
void shape_gui(struct phys2d_shape *shape);
|
||||
void pinball_flipper_gui(struct flipper *flip);
|
||||
|
||||
int obj_gui_hierarchy(struct mGameObject *selected);
|
||||
|
||||
#endif
|
19
source/editor/editorstate.c
Normal file
19
source/editor/editorstate.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "editorstate.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
void (*asset_command)(char *asset) = print_file;
|
||||
|
||||
void print_file(char *file)
|
||||
{
|
||||
printf("File path: %s\n", file);
|
||||
}
|
||||
|
||||
void set_new_model(char *modelPath)
|
||||
{
|
||||
printf("Loading new model: %s\n", modelPath);
|
||||
curActor->model = GetExistingModel(modelPath);
|
||||
strcpy(curActor->currentModelPath, modelPath);
|
||||
}
|
||||
|
||||
*/
|
10
source/editor/editorstate.h
Normal file
10
source/editor/editorstate.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef EDITORSTATE_H
|
||||
#define EDITORSTATE_H
|
||||
|
||||
void set_new_model(char *modelPath);
|
||||
|
||||
extern void (*asset_command)(char *asset);
|
||||
|
||||
void print_file(char *file);
|
||||
|
||||
#endif
|
4
source/engine/2dcamera.h
Normal file
4
source/engine/2dcamera.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef TWODCAMERA_H
|
||||
#define TWODCAMERA_H
|
||||
|
||||
#endif
|
385
source/engine/2dphysics.c
Normal file
385
source/engine/2dphysics.c
Normal file
|
@ -0,0 +1,385 @@
|
|||
#include "2dphysics.h"
|
||||
|
||||
#include "gameobject.h"
|
||||
#include <string.h>
|
||||
#include "mathc.h"
|
||||
|
||||
cpBody *ballBody = NULL;
|
||||
cpSpace *space = NULL;
|
||||
float phys2d_gravity = -50.f;
|
||||
int physOn = 0;
|
||||
|
||||
void phys2d_init()
|
||||
{
|
||||
space = cpSpaceNew();
|
||||
cpSpaceSetGravity(space, cpv(0, phys2d_gravity));
|
||||
}
|
||||
|
||||
void phys2d_update(float deltaT)
|
||||
{
|
||||
cpSpaceStep(space, deltaT * physOn);
|
||||
}
|
||||
|
||||
void phys2d_apply()
|
||||
{
|
||||
cpSpaceSetGravity(space, cpv(0, phys2d_gravity));
|
||||
}
|
||||
|
||||
void phys2d_shape_apply(struct phys2d_shape *shape)
|
||||
{
|
||||
cpShapeSetFriction(shape->shape, shape->go->f);
|
||||
cpShapeSetElasticity(shape->shape, shape->go->e);
|
||||
}
|
||||
|
||||
void init_phys2dshape(struct phys2d_shape *shape, struct mGameObject *go)
|
||||
{
|
||||
shape->go = go;
|
||||
phys2d_shape_apply(shape);
|
||||
}
|
||||
|
||||
struct phys2d_circle *Make2DCircle(struct mGameObject *go)
|
||||
{
|
||||
struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle));
|
||||
|
||||
new->radius = 10.f;
|
||||
new->offset[0] = 0.f;
|
||||
new->offset[1] = 0.f;
|
||||
phys2d_circleinit(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void phys2d_circleinit(struct phys2d_circle *circle,
|
||||
struct mGameObject *go)
|
||||
{
|
||||
circle->shape.shape =
|
||||
cpSpaceAddShape(space,
|
||||
cpCircleShapeNew(go->body, circle->radius,
|
||||
cpvzero));
|
||||
init_phys2dshape(&circle->shape, go);
|
||||
}
|
||||
|
||||
struct phys2d_segment *Make2DSegment(struct mGameObject *go)
|
||||
{
|
||||
struct phys2d_segment *new = malloc(sizeof(struct phys2d_segment));
|
||||
|
||||
new->thickness = 1.f;
|
||||
new->a[0] = 0.f;
|
||||
new->a[1] = 0.f;
|
||||
new->b[0] = 0.f;
|
||||
new->b[1] = 0.f;
|
||||
phys2d_seginit(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void phys2d_seginit(struct phys2d_segment *seg, struct mGameObject *go)
|
||||
{
|
||||
seg->shape.shape =
|
||||
cpSpaceAddShape(space,
|
||||
cpSegmentShapeNew(go->body, cpvzero, cpvzero,
|
||||
seg->thickness));
|
||||
init_phys2dshape(&seg->shape, go);
|
||||
}
|
||||
|
||||
struct phys2d_box *Make2DBox(struct mGameObject *go)
|
||||
{
|
||||
struct phys2d_box *new = malloc(sizeof(struct phys2d_box));
|
||||
|
||||
new->w = 50.f;
|
||||
new->h = 50.f;
|
||||
new->r = 0.f;
|
||||
new->offset[0] = 0.f;
|
||||
new->offset[1] = 0.f;
|
||||
|
||||
phys2d_boxinit(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void phys2d_boxinit(struct phys2d_box *box, struct mGameObject *go)
|
||||
{
|
||||
cpVect verts[4] =
|
||||
{ { -5.f, -5.f }, { 5.f, -5.f }, { 5.f, 5.f }, { -5.f, 5.f } };
|
||||
cpTransform T = { 0 };
|
||||
box->shape.shape =
|
||||
cpSpaceAddShape(space,
|
||||
cpBoxShapeNew(go->body, box->w, box->h, box->r));
|
||||
init_phys2dshape(&box->shape, go);
|
||||
phys2d_applybox(box);
|
||||
}
|
||||
|
||||
struct phys2d_poly *Make2DPoly(struct mGameObject *go)
|
||||
{
|
||||
struct phys2d_poly *new = malloc(sizeof(struct phys2d_poly));
|
||||
|
||||
new->n = 0;
|
||||
new->points = NULL;
|
||||
new->radius = 0.f;
|
||||
|
||||
phys2d_polyinit(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void phys2d_polyinit(struct phys2d_poly *poly, struct mGameObject *go)
|
||||
{
|
||||
cpTransform T = { 0 };
|
||||
poly->shape.shape =
|
||||
cpSpaceAddShape(space,
|
||||
cpPolyShapeNew(go->body, 0, NULL, T,
|
||||
poly->radius));
|
||||
init_phys2dshape(&poly->shape, go);
|
||||
phys2d_applypoly(poly);
|
||||
}
|
||||
|
||||
void phys2d_polyaddvert(struct phys2d_poly *poly)
|
||||
{
|
||||
poly->n++;
|
||||
float *oldpoints = poly->points;
|
||||
poly->points = calloc(2 * poly->n, sizeof(float));
|
||||
memcpy(poly->points, oldpoints, sizeof(float) * 2 * (poly->n - 1));
|
||||
free(oldpoints);
|
||||
}
|
||||
|
||||
struct phys2d_edge *Make2DEdge(struct mGameObject *go)
|
||||
{
|
||||
struct phys2d_edge *new = malloc(sizeof(struct phys2d_edge));
|
||||
|
||||
new->n = 2;
|
||||
new->points = calloc(2 * 2, sizeof(float));
|
||||
new->thickness = 0.f;
|
||||
new->shapes = malloc(sizeof(cpShape *));
|
||||
|
||||
phys2d_edgeinit(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void phys2d_edgeinit(struct phys2d_edge *edge, struct mGameObject *go)
|
||||
{
|
||||
edge->shapes[0] =
|
||||
cpSpaceAddShape(space,
|
||||
cpSegmentShapeNew(go->body, cpvzero, cpvzero,
|
||||
edge->thickness));
|
||||
edge->shape.go = go;
|
||||
phys2d_edgeshapeapply(&edge->shape, edge->shapes[0]);
|
||||
|
||||
|
||||
|
||||
phys2d_applyedge(edge);
|
||||
}
|
||||
|
||||
void phys2d_edgeshapeapply(struct phys2d_shape *mshape, cpShape * shape)
|
||||
{
|
||||
cpShapeSetFriction(shape, mshape->go->f);
|
||||
cpShapeSetElasticity(shape, mshape->go->e);
|
||||
}
|
||||
|
||||
void phys2d_edgeaddvert(struct phys2d_edge *edge)
|
||||
{
|
||||
edge->n++;
|
||||
float *oldp = edge->points;
|
||||
edge->points = calloc(edge->n * 2, sizeof(float));
|
||||
memcpy(edge->points, oldp, sizeof(float) * 2 * (edge->n - 1));
|
||||
|
||||
cpShape **oldshapes = edge->shapes;
|
||||
edge->shapes = malloc(sizeof(cpShape *) * (edge->n - 1));
|
||||
memcpy(edge->shapes, oldshapes, sizeof(cpShape *) * (edge->n - 2));
|
||||
cpVect a =
|
||||
{ edge->points[(edge->n - 2) * 2],
|
||||
edge->points[(edge->n - 2) * 2 + 1] };
|
||||
cpVect b =
|
||||
{ edge->points[(edge->n - 1) * 2],
|
||||
edge->points[(edge->n - 1) * 2 + 1] };
|
||||
edge->shapes[edge->n - 2] =
|
||||
cpSpaceAddShape(space,
|
||||
cpSegmentShapeNew(edge->shape.go->body, a, b,
|
||||
edge->thickness));
|
||||
phys2d_edgeshapeapply(&edge->shape, edge->shapes[edge->n - 2]);
|
||||
|
||||
free(oldp);
|
||||
free(oldshapes);
|
||||
}
|
||||
|
||||
#include "debugdraw.h"
|
||||
#include "gameobject.h"
|
||||
#include <math.h>
|
||||
#include <chipmunk_unsafe.h>
|
||||
|
||||
void phys2d_applycircle(struct phys2d_circle *circle)
|
||||
{
|
||||
float radius = circle->radius * circle->shape.go->scale;
|
||||
float s = circle->shape.go->scale;
|
||||
cpVect offset = { circle->offset[0] * s, circle->offset[1] * s };
|
||||
|
||||
cpCircleShapeSetRadius(circle->shape.shape, radius);
|
||||
cpCircleShapeSetOffset(circle->shape.shape, offset);
|
||||
cpBodySetMoment(circle->shape.go->body,
|
||||
cpMomentForCircle(circle->shape.go->mass, 0, radius,
|
||||
offset));
|
||||
}
|
||||
|
||||
void phys2d_applyseg(struct phys2d_segment *seg)
|
||||
{
|
||||
float s = seg->shape.go->scale;
|
||||
cpVect a = { seg->a[0] * s, seg->a[1] * s };
|
||||
cpVect b = { seg->b[0] * s, seg->b[1] * s };
|
||||
cpSegmentShapeSetEndpoints(seg->shape.shape, a, b);
|
||||
cpSegmentShapeSetRadius(seg->shape.shape, seg->thickness * s);
|
||||
}
|
||||
|
||||
void phys2d_applybox(struct phys2d_box *box)
|
||||
{
|
||||
float s = box->shape.go->scale;
|
||||
cpTransform T = { 0 };
|
||||
T.a = s;
|
||||
T.d = s;
|
||||
T.tx = box->offset[0] * s;
|
||||
T.ty = box->offset[1] * s;
|
||||
float hh = box->h / 2.f;
|
||||
float hw = box->w / 2.f;
|
||||
cpVect verts[4] =
|
||||
{ { -hw, -hh }, { hw, -hh }, { hw, hh }, { -hw, hh } };
|
||||
cpPolyShapeSetVerts(box->shape.shape, 4, verts, T);
|
||||
cpPolyShapeSetRadius(box->shape.shape, box->r);
|
||||
}
|
||||
|
||||
void phys2d_applypoly(struct phys2d_poly *poly)
|
||||
{
|
||||
cpVect verts[poly->n];
|
||||
|
||||
for (int i = 0; i < poly->n; i++) {
|
||||
verts[i].x = poly->points[i * 2];
|
||||
verts[i].y = poly->points[i * 2 + 1];
|
||||
}
|
||||
|
||||
CP_CONVEX_HULL(poly->n, verts, hullCount, hullVerts);
|
||||
|
||||
float s = poly->shape.go->scale;
|
||||
cpTransform T = { 0 };
|
||||
T.a = s;
|
||||
T.d = s;
|
||||
|
||||
cpPolyShapeSetVerts(poly->shape.shape, hullCount, hullVerts, T);
|
||||
cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
|
||||
}
|
||||
|
||||
void phys2d_applyedge(struct phys2d_edge *edge)
|
||||
{
|
||||
float s = edge->shape.go->scale;
|
||||
|
||||
for (int i = 0; i < edge->n - 1; i++) {
|
||||
cpVect a =
|
||||
{ edge->points[i * 2] * s, edge->points[i * 2 + 1] * s };
|
||||
cpVect b =
|
||||
{ edge->points[i * 2 + 2] * s, edge->points[i * 2 + 3] * s };
|
||||
cpSegmentShapeSetEndpoints(edge->shapes[i], a, b);
|
||||
cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness);
|
||||
}
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle)
|
||||
{
|
||||
cpVect p = cpBodyGetPosition(circle->shape.go->body);
|
||||
cpVect o = cpCircleShapeGetOffset(circle->shape.shape);
|
||||
float d = sqrt(pow(o.x, 2.f) + pow(o.y, 2.f));
|
||||
float a = atan2(o.y, o.x) + cpBodyGetAngle(circle->shape.go->body);
|
||||
draw_circle(p.x + (d * cos(a)), p.y + (d * sin(a)),
|
||||
cpCircleShapeGetRadius(circle->shape.shape), 1);
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawseg(struct phys2d_segment *seg)
|
||||
{
|
||||
cpVect p = cpBodyGetPosition(seg->shape.go->body);
|
||||
float s = seg->shape.go->scale;
|
||||
cpVect a = cpSegmentShapeGetA(seg->shape.shape);
|
||||
cpVect b = cpSegmentShapeGetB(seg->shape.shape);
|
||||
|
||||
float angle = cpBodyGetAngle(seg->shape.go->body);
|
||||
float ad = sqrt(pow(a.x, 2.f) + pow(a.y, 2.f));
|
||||
float bd = sqrt(pow(b.x, 2.f) + pow(b.y, 2.f));
|
||||
float aa = atan2(a.y, a.x) + angle;
|
||||
float ba = atan2(b.y, b.x) + angle;
|
||||
draw_line(ad * cos(aa) + p.x, ad * sin(aa) + p.y, bd * cos(ba) + p.x,
|
||||
bd * sin(ba) + p.y);
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawbox(struct phys2d_box *box)
|
||||
{
|
||||
int n = cpPolyShapeGetCount(box->shape.shape);
|
||||
cpVect b = cpBodyGetPosition(box->shape.go->body);
|
||||
float angle = cpBodyGetAngle(box->shape.go->body);
|
||||
float points[n * 2];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
cpVect p = cpPolyShapeGetVert(box->shape.shape, i);
|
||||
float d = sqrt(pow(p.x, 2.f) + pow(p.y, 2.f));
|
||||
float a = atan2(p.y, p.x) + angle;
|
||||
points[i * 2] = d * cos(a) + b.x;
|
||||
points[i * 2 + 1] = d * sin(a) + b.y;
|
||||
}
|
||||
|
||||
draw_poly(points, n);
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawpoly(struct phys2d_poly *poly)
|
||||
{
|
||||
cpVect b = cpBodyGetPosition(poly->shape.go->body);
|
||||
float angle = cpBodyGetAngle(poly->shape.go->body);
|
||||
|
||||
float s = poly->shape.go->scale;
|
||||
for (int i = 0; i < poly->n; i++) {
|
||||
float point[2];
|
||||
float d =
|
||||
sqrt(pow(poly->points[i * 2] * s, 2.f) +
|
||||
pow(poly->points[i * 2 + 1] * s, 2.f));
|
||||
float a =
|
||||
atan2(poly->points[i * 2 + 1], poly->points[i * 2]) + angle;
|
||||
draw_point(b.x + d * cos(a), b.y + d * sin(a), 3);
|
||||
}
|
||||
|
||||
if (poly->n >= 3) {
|
||||
int n = cpPolyShapeGetCount(poly->shape.shape);
|
||||
float points[n * 2];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
cpVect p = cpPolyShapeGetVert(poly->shape.shape, i);
|
||||
float d = sqrt(pow(p.x, 2.f) + pow(p.y, 2.f));
|
||||
float a = atan2(p.y, p.x) + angle;
|
||||
points[i * 2] = d * cos(a) + b.x;
|
||||
points[i * 2 + 1] = d * sin(a) + b.y;
|
||||
}
|
||||
|
||||
draw_poly(points, n);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void phys2d_dbgdrawedge(struct phys2d_edge *edge)
|
||||
{
|
||||
cpVect p = cpBodyGetPosition(edge->shape.go->body);
|
||||
float s = edge->shape.go->scale;
|
||||
float angle = cpBodyGetAngle(edge->shape.go->body);
|
||||
|
||||
for (int i = 0; i < edge->n; i++) {
|
||||
float point[2];
|
||||
float d =
|
||||
sqrt(pow(edge->points[i * 2] * s, 2.f) +
|
||||
pow(edge->points[i * 2 + 1] * s, 2.f));
|
||||
float a =
|
||||
atan2(edge->points[i * 2 + 1], edge->points[i * 2]) + angle;
|
||||
draw_point(p.x + d * cos(a), p.y + d * sin(a), 3);
|
||||
}
|
||||
|
||||
for (int i = 0; i < edge->n - 1; i++) {
|
||||
cpVect a = cpSegmentShapeGetA(edge->shapes[i]);
|
||||
cpVect b = cpSegmentShapeGetB(edge->shapes[i]);
|
||||
float ad = sqrt(pow(a.x, 2.f) + pow(a.y, 2.f));
|
||||
float bd = sqrt(pow(b.x, 2.f) + pow(b.y, 2.f));
|
||||
float aa = atan2(a.y, a.x) + angle;
|
||||
float ba = atan2(b.y, b.x) + angle;
|
||||
draw_line(ad * cos(aa) + p.x, ad * sin(aa) + p.y,
|
||||
bd * cos(ba) + p.x, bd * sin(ba) + p.y);
|
||||
}
|
||||
}
|
90
source/engine/2dphysics.h
Normal file
90
source/engine/2dphysics.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef TWODPHYSICS_H
|
||||
#define TWODPHYSICS_H
|
||||
|
||||
#include <chipmunk.h>
|
||||
|
||||
|
||||
struct mGameObject;
|
||||
|
||||
extern cpBody *ballBody;
|
||||
extern float phys2d_gravity;
|
||||
extern int physOn;
|
||||
extern cpSpace *space;
|
||||
|
||||
struct phys2d_shape {
|
||||
cpShape *shape;
|
||||
struct mGameObject *go;
|
||||
};
|
||||
|
||||
struct phys2d_circle {
|
||||
float radius;
|
||||
float offset[2];
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_segment {
|
||||
float a[2];
|
||||
float b[2];
|
||||
float thickness;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_box {
|
||||
float w;
|
||||
float h;
|
||||
float r;
|
||||
float offset[2];
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_edge {
|
||||
int n;
|
||||
float *points;
|
||||
float thickness;
|
||||
cpShape **shapes;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_poly {
|
||||
int n;
|
||||
float *points;
|
||||
float radius;
|
||||
struct phys2d_shape shape;
|
||||
};
|
||||
|
||||
struct phys2d_circle *Make2DCircle(struct mGameObject *go);
|
||||
void phys2d_circleinit(struct phys2d_circle *circle,
|
||||
struct mGameObject *go);
|
||||
void phys2d_applycircle(struct phys2d_circle *circle);
|
||||
void phys2d_dbgdrawcircle(struct phys2d_circle *circle);
|
||||
|
||||
struct phys2d_segment *Make2DSegment(struct mGameObject *go);
|
||||
void phys2d_seginit(struct phys2d_segment *seg, struct mGameObject *go);
|
||||
void phys2d_applyseg(struct phys2d_segment *seg);
|
||||
void phys2d_dbgdrawseg(struct phys2d_segment *seg);
|
||||
|
||||
struct phys2d_box *Make2DBox(struct mGameObject *go);
|
||||
void phys2d_boxinit(struct phys2d_box *box, struct mGameObject *go);
|
||||
void phys2d_applybox(struct phys2d_box *box);
|
||||
void phys2d_dbgdrawbox(struct phys2d_box *box);
|
||||
|
||||
struct phys2d_poly *Make2DPoly(struct mGameObject *go);
|
||||
void phys2d_polyinit(struct phys2d_poly *poly, struct mGameObject *go);
|
||||
void phys2d_applypoly(struct phys2d_poly *poly);
|
||||
void phys2d_dbgdrawpoly(struct phys2d_poly *poly);
|
||||
void phys2d_polyaddvert(struct phys2d_poly *poly);
|
||||
|
||||
struct phys2d_edge *Make2DEdge(struct mGameObject *go);
|
||||
void phys2d_edgeinit(struct phys2d_edge *edge, struct mGameObject *go);
|
||||
void phys2d_applyedge(struct phys2d_edge *edge);
|
||||
void phys2d_edgeshapeapply(struct phys2d_shape *mshape, cpShape * shape);
|
||||
void phys2d_dbgdrawedge(struct phys2d_edge *edge);
|
||||
void phys2d_edgeaddvert(struct phys2d_edge *edge);
|
||||
|
||||
|
||||
void phys2d_init();
|
||||
void phys2d_update(float deltaT);
|
||||
void phys2d_apply();
|
||||
|
||||
|
||||
#endif
|
47
source/engine/3dphysics.c
Normal file
47
source/engine/3dphysics.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <3dphysics.h>
|
||||
|
||||
/*
|
||||
btDefaultCollisionConfiguration *collisionConfig {
|
||||
NULL};
|
||||
btCollisionDispatcher *dispatcher {
|
||||
NULL};
|
||||
btBroadphaseInterface *overlappingPairCache {
|
||||
NULL};
|
||||
btSequentialImpulseConstraintSolver *solver {
|
||||
NULL};
|
||||
btDiscreteDynamicsWorld *dynamicsWorld {
|
||||
NULL};
|
||||
btRigidBody *worldFloor {
|
||||
NULL};
|
||||
|
||||
void btUpdate()
|
||||
{
|
||||
// dynamicsWorld->stepSimulation(deltaT);
|
||||
}
|
||||
|
||||
void btInit()
|
||||
{
|
||||
// collisionConfig = new btDefaultCollisionConfiguration();
|
||||
// dispatcher = new btCollisionDispatcher(collisionConfig);
|
||||
// overlappingPairCache = new btDbvtBroadphase();
|
||||
// solver = new btSequentialImpulseConstraintSolver;
|
||||
// dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfig);
|
||||
// dynamicsWorld->setGravity(btVector3(0.f, -9.8f, 0.f));
|
||||
// btDebugDrawer = new BulletDebugDrawer_OpenGL();
|
||||
// dynamicsWorld->setDebugDrawer(btDebugDrawer);
|
||||
|
||||
|
||||
//btDebugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb);
|
||||
// Add camera and plane to world
|
||||
// dynamicsWorld->addRigidBody(camera.body);
|
||||
// camera.body->setGravity(btVector3(0.f, 0.f, 0.f));
|
||||
|
||||
// Create and add plane
|
||||
// btStaticPlaneShape* floorShape = new btStaticPlaneShape(btVector3(0.f, 1.f, 0.f), 0.f);
|
||||
// btDefaultMotionState* motionState = new btDefaultMotionState();
|
||||
// btVector3 bodyInertia;
|
||||
// btRigidBody::btRigidBodyConstructionInfo bodyCI = btRigidBody::btRigidBodyConstructionInfo(0.f, motionState, floorShape, bodyInertia);
|
||||
// worldFloor = new btRigidBody(bodyCI);
|
||||
// dynamicsWorld->addRigidBody(worldFloor);
|
||||
}
|
||||
*/
|
4
source/engine/3dphysics.h
Normal file
4
source/engine/3dphysics.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef THREEDPHYSICS_H
|
||||
#define THREEDPHYSICS_H
|
||||
|
||||
#endif
|
4
source/engine/billboard.h
Normal file
4
source/engine/billboard.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef BILLBOARD_H
|
||||
#define BILLBOARD_H
|
||||
|
||||
#endif
|
137
source/engine/camera.c
Normal file
137
source/engine/camera.c
Normal file
|
@ -0,0 +1,137 @@
|
|||
#include "camera.h"
|
||||
|
||||
#include "gameobject.h"
|
||||
#include "input.h"
|
||||
#include <SDL.h>
|
||||
|
||||
const float CAMERA_MINSPEED = 1.f;
|
||||
const float CAMERA_MAXSPEED = 300.f;
|
||||
const float CAMERA_ROTATESPEED = 6.f;
|
||||
|
||||
void cam_goto_object(struct mCamera *cam, struct mTransform *transform)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
vec3_subtract(cam->transform.position, transform->position,
|
||||
vec3_multiply_f(fwd, trans_forward(fwd, transform),
|
||||
10.f));
|
||||
}
|
||||
|
||||
void cam_inverse_goto(struct mCamera *cam, struct mTransform *transform)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
vec3_add(transform->position, cam->transform.position,
|
||||
vec3_multiply_f(fwd, trans_forward(fwd, &cam->transform),
|
||||
10.f));
|
||||
}
|
||||
|
||||
mfloat_t *getviewmatrix(mfloat_t view[16],
|
||||
const struct mCamera *const camera)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
mfloat_t look[3] = { 0.f };
|
||||
vec3_rotate_quat(fwd, FORWARD, camera->transform.rotation);
|
||||
vec3_add(look, camera->transform.position, fwd);
|
||||
mat4_look_at(view, camera->transform.position, look, UP);
|
||||
return view;
|
||||
/*return mat4_look_at(view, ncam.transform.position,
|
||||
vec3_add(look, ncam.transform.position,
|
||||
trans_forward(fwd, &ncam.transform)),
|
||||
UP); */
|
||||
}
|
||||
|
||||
void camera_2d_update(struct mCamera *camera, float deltaT)
|
||||
{
|
||||
static mfloat_t holdvec[3];
|
||||
static mfloat_t frame[3];
|
||||
vec3_zero(frame);
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_W])
|
||||
vec3_add(frame, frame, UP);
|
||||
if (currentKeystates[SDL_SCANCODE_S])
|
||||
vec3_add(frame, frame, DOWN);
|
||||
if (currentKeystates[SDL_SCANCODE_A])
|
||||
vec3_add(frame, frame, LEFT);
|
||||
if (currentKeystates[SDL_SCANCODE_D])
|
||||
vec3_add(frame, frame, RIGHT);
|
||||
|
||||
float speedMult = currentKeystates[SDL_SCANCODE_LSHIFT] ? 2.f : 1.f;
|
||||
|
||||
if (!vec3_is_zero(frame)) {
|
||||
vec3_normalize(frame, frame);
|
||||
vec3_add(camera->transform.position, camera->transform.position,
|
||||
vec3_multiply_f(frame, frame,
|
||||
camera->speed * speedMult * deltaT));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
void camera_update(struct mCamera * camera, float mouseX, float mouseY,
|
||||
const uint8_t * keystate, int32_t mouseWheelY,
|
||||
float deltaTime)
|
||||
{
|
||||
// if (SDL_GetRelativeMouseMode()) vec3_zero(camera->frame_move);
|
||||
|
||||
static mfloat_t holdvec[VEC3_SIZE];
|
||||
vec3_zero(camera->frame_move);
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_W])
|
||||
vec3_add(camera->frame_move, camera->frame_move,
|
||||
trans_forward(holdvec, &camera->transform));
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_S])
|
||||
vec3_subtract(camera->frame_move, camera->frame_move,
|
||||
trans_forward(holdvec, &camera->transform));
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_A])
|
||||
vec3_subtract(camera->frame_move, camera->frame_move,
|
||||
trans_right(holdvec, &camera->transform));
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_D])
|
||||
vec3_add(camera->frame_move, camera->frame_move,
|
||||
trans_right(holdvec, &camera->transform));
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_E])
|
||||
vec3_add(camera->frame_move, camera->frame_move,
|
||||
trans_up(holdvec, &camera->transform));
|
||||
|
||||
if (currentKeystates[SDL_SCANCODE_Q])
|
||||
vec3_subtract(camera->frame_move, camera->frame_move,
|
||||
trans_up(holdvec, &camera->transform));
|
||||
|
||||
camera->speedMult = currentKeystates[SDL_SCANCODE_LSHIFT] ? 2.f : 1.f;
|
||||
|
||||
|
||||
if (!vec3_is_zero(camera->frame_move)) {
|
||||
vec3_normalize(camera->frame_move, camera->frame_move);
|
||||
vec3_add(camera->transform.position, camera->transform.position,
|
||||
vec3_multiply_f(camera->frame_move, camera->frame_move,
|
||||
camera->speed * camera->speedMult *
|
||||
deltaTime));
|
||||
}
|
||||
// Adjust speed based on mouse wheel
|
||||
camera->speed =
|
||||
clampf(camera->speed + mouseWheelY, CAMERA_MINSPEED,
|
||||
CAMERA_MAXSPEED);
|
||||
|
||||
|
||||
// TODO: Handle this as additive quaternions
|
||||
|
||||
camera->yaw -= mouseX * CAMERA_ROTATESPEED * deltaTime;
|
||||
camera->pitch -= mouseY * CAMERA_ROTATESPEED * deltaTime;
|
||||
|
||||
|
||||
if (camera->pitch > 89.f)
|
||||
camera->pitch = 89.f;
|
||||
if (camera->pitch < -89.f)
|
||||
camera->pitch = -89.f;
|
||||
|
||||
mfloat_t qyaw[4] = {0.f};
|
||||
mfloat_t qpitch[4] = {0.f};
|
||||
|
||||
quat_from_axis_angle(qyaw, UP, camera->yaw);
|
||||
quat_from_axis_angle(qpitch, RIGHT, camera->pitch);
|
||||
quat_multiply(camera->transform.rotation, qyaw, qpitch);
|
||||
|
||||
}
|
||||
*/
|
24
source/engine/camera.h
Normal file
24
source/engine/camera.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include "transform.h"
|
||||
|
||||
extern const float CAMERA_MINSPEED;
|
||||
extern const float CAMERA_MAXSPEED;
|
||||
extern const float CAMERA_ROTATESPEED;
|
||||
|
||||
struct mCamera {
|
||||
struct mTransform transform;
|
||||
float speed;
|
||||
float speedMult;
|
||||
mfloat_t frame_move[VEC3_SIZE];
|
||||
};
|
||||
|
||||
void camera_2d_update(struct mCamera *camera, float deltaT);
|
||||
|
||||
mfloat_t *getviewmatrix(mfloat_t view[MAT4_SIZE],
|
||||
const struct mCamera *const camera);
|
||||
void cam_goto_object(struct mCamera *cam, struct mTransform *transform);
|
||||
void cam_inverse_goto(struct mCamera *cam, struct mTransform *transform);
|
||||
|
||||
#endif
|
1
source/engine/component.h
Normal file
1
source/engine/component.h
Normal file
|
@ -0,0 +1 @@
|
|||
#pragma once
|
18
source/engine/config.h
Normal file
18
source/engine/config.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
|
||||
#define MAXPATH 256 /* 255 chars + null */
|
||||
#define MAXNAME 50
|
||||
|
||||
|
||||
|
||||
#define SCREEN_WIDTH 1280
|
||||
#define SCREEN_HEIGHT 720
|
||||
#define PI 3.14159265358979323846264338327950288f
|
||||
#define DEG2RADS 0.0174532925199432957692369076848861271344287188854172545609719144f
|
||||
#define RAD2DEGS 57.2958f
|
||||
#define MSAA_SAMPLES 2
|
||||
|
||||
|
||||
#endif
|
173
source/engine/datastream.c
Normal file
173
source/engine/datastream.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
#include "datastream.h"
|
||||
|
||||
#include <pl_mpeg.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "shader.h"
|
||||
#include "resources.h"
|
||||
#include <GL/glew.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static void ds_update_texture(uint32_t unit, uint32_t texture,
|
||||
plm_plane_t * plane)
|
||||
{
|
||||
glActiveTexture(unit);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, plane->width, plane->height, 0,
|
||||
GL_RED, GL_UNSIGNED_BYTE, plane->data);
|
||||
}
|
||||
|
||||
static void render_frame(plm_t * mpeg, plm_frame_t * frame, void *user)
|
||||
{
|
||||
struct datastream *ds = user;
|
||||
shader_use(ds->shader);
|
||||
ds_update_texture(GL_TEXTURE0, ds->texture_y, &frame->y);
|
||||
ds_update_texture(GL_TEXTURE1, ds->texture_cb, &frame->cb);
|
||||
ds_update_texture(GL_TEXTURE2, ds->texture_cr, &frame->cr);
|
||||
}
|
||||
|
||||
static void render_audio(plm_t * mpeg, plm_samples_t * samples, void *user)
|
||||
{
|
||||
struct datastream *ds = (struct datastream *) user;
|
||||
int size = sizeof(float) * samples->count * 2;
|
||||
SDL_QueueAudio(ds->audio_device, samples->interleaved, size);
|
||||
}
|
||||
|
||||
void ds_openvideo(struct datastream *ds, const char *video,
|
||||
const char *adriver)
|
||||
{
|
||||
ds_stop(ds);
|
||||
char buf[MAXPATH] = {'\0'};
|
||||
sprintf(buf, "%s%s", DATA_PATH, video);
|
||||
ds->plm = plm_create_with_filename(buf);
|
||||
|
||||
if (!ds->plm) {
|
||||
SDL_Log("Couldn't open %s", video);
|
||||
}
|
||||
|
||||
int samplerate = plm_get_samplerate(ds->plm);
|
||||
|
||||
SDL_Log("Opened %s - framerate: %f, samplerate: %d, duration: %f",
|
||||
video,
|
||||
plm_get_framerate(ds->plm),
|
||||
plm_get_samplerate(ds->plm), plm_get_duration(ds->plm)
|
||||
);
|
||||
|
||||
plm_set_video_decode_callback(ds->plm, render_frame, ds);
|
||||
plm_set_audio_decode_callback(ds->plm, render_audio, ds);
|
||||
plm_set_loop(ds->plm, false);
|
||||
|
||||
plm_set_audio_enabled(ds->plm, true);
|
||||
plm_set_audio_stream(ds->plm, 0);
|
||||
SDL_AudioSpec audio_spec;
|
||||
SDL_memset(&audio_spec, 0, sizeof(audio_spec));
|
||||
audio_spec.freq = samplerate;
|
||||
audio_spec.format = AUDIO_F32;
|
||||
audio_spec.channels = 2;
|
||||
audio_spec.samples = 4096;
|
||||
|
||||
ds->audio_device =
|
||||
SDL_OpenAudioDevice(adriver, 0, &audio_spec, NULL, 0);
|
||||
printf("Opened audio device %d on driver %s\n", ds->audio_device,
|
||||
adriver);
|
||||
// if (audio_device == 0) {
|
||||
// SDL_Log("Failed to open audio device: %s", SDL_GetError());
|
||||
// }
|
||||
SDL_PauseAudioDevice(ds->audio_device, 0);
|
||||
|
||||
|
||||
|
||||
|
||||
// Adjust the audio lead time according to the audio_spec buffer size
|
||||
//plm_set_audio_lead_time(plm, (double)audio_spec.samples / (double)samplerate);
|
||||
|
||||
ds->playing = true;
|
||||
}
|
||||
|
||||
struct datastream *MakeDatastream(struct mShader *shader)
|
||||
{
|
||||
struct datastream *newds =
|
||||
(struct datastream *) malloc(sizeof(struct datastream));
|
||||
newds->shader = shader;
|
||||
shader_use(newds->shader);
|
||||
glGenTextures(1, &newds->texture_y);
|
||||
glBindTexture(GL_TEXTURE_2D, newds->texture_y);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
shader_setint(newds->shader, "texture_y", 0);
|
||||
|
||||
glGenTextures(1, &newds->texture_cb);
|
||||
glBindTexture(GL_TEXTURE_2D, newds->texture_cb);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
shader_setint(newds->shader, "texture_cb", 1);
|
||||
|
||||
glGenTextures(1, &newds->texture_cr);
|
||||
glBindTexture(GL_TEXTURE_2D, newds->texture_cr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
shader_setint(newds->shader, "texture_cr", 2);
|
||||
|
||||
return newds;
|
||||
}
|
||||
|
||||
void ds_advance(struct datastream *ds, uint32_t ms)
|
||||
{
|
||||
if (ds->playing) {
|
||||
double advanceTime = ms / 1000.f;
|
||||
plm_decode(ds->plm, advanceTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ds_seek(struct datastream *ds, uint32_t time)
|
||||
{
|
||||
SDL_ClearQueuedAudio(0);
|
||||
plm_seek(ds->plm, time, false);
|
||||
}
|
||||
|
||||
void ds_fwdframes(struct datastream *ds, int frames)
|
||||
{
|
||||
for (int i = 0; i < frames; i++) {
|
||||
plm_frame_t *frame = plm_decode_video(ds->plm);
|
||||
render_frame(ds->plm, frame, ds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ds_pause(struct datastream *ds)
|
||||
{
|
||||
ds->playing = false;
|
||||
}
|
||||
|
||||
void ds_stop(struct datastream *ds)
|
||||
{
|
||||
if (ds->plm != NULL) {
|
||||
plm_destroy(ds->plm);
|
||||
ds->plm = NULL;
|
||||
}
|
||||
if (ds->audio_device)
|
||||
SDL_CloseAudioDevice(ds->audio_device);
|
||||
ds->playing = false;
|
||||
}
|
||||
|
||||
// TODO: Must be a better way
|
||||
int ds_videodone(struct datastream *ds)
|
||||
{
|
||||
return (ds->plm == NULL)
|
||||
|| plm_get_time(ds->plm) >= plm_get_duration(ds->plm);
|
||||
}
|
||||
|
||||
double ds_remainingtime(struct datastream *ds)
|
||||
{
|
||||
if (ds->plm != NULL)
|
||||
return plm_get_duration(ds->plm) - plm_get_time(ds->plm);
|
||||
else
|
||||
return 0.f;
|
||||
}
|
30
source/engine/datastream.h
Normal file
30
source/engine/datastream.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef DATASTREAM_H
|
||||
#define DATASTREAM_H
|
||||
|
||||
#include <SDL_audio.h>
|
||||
|
||||
typedef struct plm_t plm_t;
|
||||
|
||||
|
||||
struct datastream {
|
||||
plm_t *plm;
|
||||
struct mShader *shader;
|
||||
double last_time;
|
||||
int playing;
|
||||
SDL_AudioDeviceID audio_device;
|
||||
uint32_t texture_y;
|
||||
uint32_t texture_cb;
|
||||
uint32_t texture_cr;
|
||||
};
|
||||
|
||||
struct datastream *MakeDatastream(struct mShader *shader);
|
||||
void ds_openvideo(struct datastream *ds, const char *path,
|
||||
const char *adriver);
|
||||
void ds_advance(struct datastream *ds, uint32_t ms);
|
||||
void ds_seek(struct datastream *ds, uint32_t time);
|
||||
void ds_pause(struct datastream *ds);
|
||||
void ds_stop(struct datastream *ds);
|
||||
int ds_videodone(struct datastream *ds);
|
||||
double ds_remainingtime(struct datastream *ds);
|
||||
|
||||
#endif
|
122
source/engine/engine.c
Normal file
122
source/engine/engine.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#define PL_MPEG_IMPLEMENTATION
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
|
||||
//#define MATHC_USE_INT16
|
||||
//#define MATHC_FLOATING_POINT_TYPE GLfloat
|
||||
//#define MATHC_USE_DOUBLE_FLOATING_POINT
|
||||
|
||||
#define STB_DS_IMPLEMENTATION
|
||||
#include <stb_ds.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#include <pl_mpeg.h>
|
||||
|
||||
#ifdef EDITOR
|
||||
#include "editor.h"
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
#include "openglrender.h"
|
||||
#include "window.h"
|
||||
#include "camera.h"
|
||||
#include "input.h"
|
||||
#include "sprite.h"
|
||||
#include "2dphysics.h"
|
||||
#include "gameobject.h"
|
||||
#include "registry.h"
|
||||
|
||||
#define FPS30 33
|
||||
#define FPS60 17
|
||||
#define FPS120 8;
|
||||
#define FPS144 7
|
||||
#define FPS300 3
|
||||
|
||||
unsigned int frameCount = 0;
|
||||
Uint32 lastTick = 0;
|
||||
Uint32 frameTick = 0;
|
||||
Uint32 elapsed = 0;
|
||||
|
||||
Uint32 physMS = FPS144;
|
||||
Uint32 physlag = 0;
|
||||
Uint32 renderMS = FPS144;
|
||||
Uint32 renderlag = 0;
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
|
||||
script_init();
|
||||
|
||||
registry_init();
|
||||
gameobjects = vec_make(sizeof(struct mGameObject), 100);
|
||||
prefabs = vec_make(MAXNAME, 25);
|
||||
|
||||
// TODO: Init these on the heap instead
|
||||
struct mCamera camera = { 0 };
|
||||
camera.speed = 500;
|
||||
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
|
||||
resources_init();
|
||||
openglInit();
|
||||
sprite_initialize();
|
||||
|
||||
#ifdef EDITOR
|
||||
editor_init(window);
|
||||
#endif
|
||||
|
||||
phys2d_init();
|
||||
|
||||
quit = false;
|
||||
SDL_Event e;
|
||||
|
||||
//While application is running
|
||||
while (!quit) {
|
||||
frameTick = SDL_GetTicks();
|
||||
elapsed = frameTick - lastTick;
|
||||
lastTick = frameTick;
|
||||
deltaT = elapsed / 1000.f;
|
||||
|
||||
physlag += elapsed;
|
||||
renderlag += elapsed;
|
||||
|
||||
input_poll();
|
||||
|
||||
if (physlag >= physMS) {
|
||||
phys2d_update(physMS / 1000.f);
|
||||
|
||||
physlag -= physMS;
|
||||
}
|
||||
|
||||
|
||||
if (renderlag >= renderMS) {
|
||||
if (physOn) {
|
||||
vec_walk(gameobjects, gameobject_update);
|
||||
}
|
||||
|
||||
|
||||
camera_2d_update(&camera, renderMS / 1000.f);
|
||||
|
||||
openglRender(&camera);
|
||||
|
||||
|
||||
#ifdef EDITOR
|
||||
editor_render();
|
||||
#endif
|
||||
|
||||
window_swap(window);
|
||||
|
||||
renderlag -= renderMS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SDL_StopTextInput();
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
240
source/engine/font.c
Normal file
240
source/engine/font.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
#include "font.h"
|
||||
|
||||
#include <shader.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <stb_truetype.h>
|
||||
|
||||
static struct Character Characters[127] = { '\0' };
|
||||
|
||||
static uint32_t VBO = 0;
|
||||
static uint32_t VAO = 0;
|
||||
|
||||
unsigned char ttf_buffer[24 << 20];
|
||||
unsigned char temp_bitmap[512 * 512];
|
||||
|
||||
struct sFont MakeFont(const char *fontfile, int height)
|
||||
{
|
||||
struct sFont newfont = { 0 };
|
||||
newfont.height = height;
|
||||
|
||||
char fontpath[256];
|
||||
snprintf(fontpath, 256, "fonts/%s", fontfile);
|
||||
|
||||
stbtt_fontinfo fontinfo = { 0 };
|
||||
int i, j, ascent, baseline, ch = 0;
|
||||
|
||||
stbtt_InitFont(&fontinfo, ttf_buffer, 0);
|
||||
stbtt_GetFontVMetrics(&fontinfo, &ascent, 0, 0);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
for (unsigned char c = 0; c < 128; c++) {
|
||||
unsigned char *bitmap;
|
||||
int advance, lsb, w, h;
|
||||
stbtt_GetCodepointHMetrics(&fontinfo, c, &advance, &lsb);
|
||||
bitmap =
|
||||
stbtt_GetCodepointBitmap(&fontinfo, 0,
|
||||
stbtt_ScaleForPixelHeight(&fontinfo,
|
||||
newfont.
|
||||
height), c,
|
||||
&w, &h, 0, 0);
|
||||
|
||||
GLuint ftexture;
|
||||
glGenTextures(1, &ftexture);
|
||||
glBindTexture(GL_TEXTURE_2D, ftexture);
|
||||
glTexImage2D(GL_TEXTURE_2D,
|
||||
0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, bitmap);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
|
||||
Characters[c].TextureID = ftexture;
|
||||
Characters[c].Advance = advance;
|
||||
Characters[c].Size[0] = w;
|
||||
Characters[c].Size[1] = h;
|
||||
Characters[c].Bearing[0] = lsb;
|
||||
Characters[c].Bearing[1] = 0;
|
||||
}
|
||||
|
||||
// configure VAO/VBO for texture quads
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * 4, NULL,
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
|
||||
return newfont;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale,
|
||||
struct mShader *shader, float color[3])
|
||||
{
|
||||
float xpos = cursor[0] + c.Bearing[0] * scale;
|
||||
float ypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale;
|
||||
|
||||
float w = c.Size[0] * scale;
|
||||
float h = c.Size[1] * scale;
|
||||
|
||||
float verts[4 * 4] = {
|
||||
xpos, ypos + h, 0.f, 0.f,
|
||||
xpos, ypos, 0.f, 1.f,
|
||||
xpos + w, ypos + h, 1.f, 0.f,
|
||||
xpos + w, ypos, 1.f, 1.f
|
||||
};
|
||||
|
||||
// float outlineWidth = 1.1;
|
||||
|
||||
// float ow = c.Size[0] * scale * outlineWidth;
|
||||
// float oh = c.Size[1] * scale * outlineWidth;
|
||||
|
||||
// float oxpos = cursor[0] + c.Bearing[0] * scale * outlineWidth - ((ow-w)/2);
|
||||
// float oypos = cursor[1] - (c.Size[1] - c.Bearing[1]) * scale * outlineWidth - ((oh-h)/2);
|
||||
|
||||
|
||||
|
||||
// float overts[4*4] = {
|
||||
// oxpos, oypos + oh, 0.f, 0.f,
|
||||
// oxpos, oypos, 0.f, 1.f,
|
||||
// oxpos + ow, oypos + oh, 1.f, 0.f,
|
||||
// oxpos + ow, oypos, 1.f, 1.f
|
||||
// };
|
||||
|
||||
float shadowOffset = 6.f;
|
||||
float sxpos =
|
||||
cursor[0] + c.Bearing[0] * scale + (scale * shadowOffset);
|
||||
float sypos =
|
||||
cursor[1] - (c.Size[1] - c.Bearing[1]) * scale -
|
||||
(scale * shadowOffset);
|
||||
|
||||
float sverts[4 * 4] = {
|
||||
sxpos, sypos + h, 0.f, 0.f,
|
||||
sxpos, sypos, 0.f, 1.f,
|
||||
sxpos + w, sypos + h, 1.f, 0.f,
|
||||
sxpos + w, sypos, 1.f, 1.f
|
||||
};
|
||||
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, c.TextureID);
|
||||
|
||||
//// Shadow pass
|
||||
float black[3] = { 0, 0, 0 };
|
||||
shader_setvec3(shader, "textColor", black);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(sverts), sverts);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
//// Outline pass
|
||||
|
||||
|
||||
|
||||
shader_setvec3(shader, "textColor", color);
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verts), verts);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
}
|
||||
|
||||
void renderText(struct sFont font, struct mShader *shader,
|
||||
const char *text, mfloat_t pos[2], float scale,
|
||||
mfloat_t color[3], float lw)
|
||||
{
|
||||
shader_use(shader);
|
||||
shader_setvec3(shader, "textColor", color);
|
||||
|
||||
mfloat_t cursor[2] = { 0.f };
|
||||
cursor[0] = pos[0];
|
||||
cursor[1] = pos[1];
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
|
||||
char modText[sizeof(*text)];
|
||||
strcpy(modText, text);
|
||||
|
||||
char *line, *wordstart;
|
||||
line = strtok(modText, "\n");
|
||||
|
||||
while (line != NULL) {
|
||||
cursor[0] = pos[0];
|
||||
|
||||
int wordWidth = 0;
|
||||
|
||||
// iterate through all characters
|
||||
while (*line != '\0') {
|
||||
|
||||
wordstart = line;
|
||||
if (!isspace(*line)) {
|
||||
struct Character ch = Characters[*line];
|
||||
|
||||
if (lw > 0
|
||||
&& (cursor[0] + ((ch.Advance >> 6) * scale) - pos[0] >=
|
||||
lw)) {
|
||||
cursor[0] = pos[0];
|
||||
cursor[1] -= scale * font.height;
|
||||
|
||||
} else {
|
||||
// now advance cursors for next glyph (note that advance is number of 1/64 pixels)
|
||||
cursor[0] += (ch.Advance >> 6) * scale; // bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
|
||||
}
|
||||
|
||||
sdrawCharacter(ch, cursor, scale, shader, color);
|
||||
++line;
|
||||
} else {
|
||||
while (!isspace(*line) || *line != '\0') { // Seek line to the end of the word
|
||||
++line;
|
||||
wordWidth += (Characters[*line].Advance >> 6) * scale;
|
||||
}
|
||||
|
||||
// Now wordStart and stringPos surround the word, go through them. If the word that's about to be drawn goes past the line width, go to next line
|
||||
if (lw > 0 && (cursor[0] + wordWidth - pos[0] >= lw)) {
|
||||
cursor[0] = pos[0];
|
||||
cursor[1] -= scale * font.height;
|
||||
}
|
||||
|
||||
while (wordstart < line) { // Go through
|
||||
|
||||
|
||||
struct Character ch = Characters[*wordstart];
|
||||
sdrawCharacter(Characters[*wordstart], cursor, scale,
|
||||
shader, color);
|
||||
|
||||
cursor[0] += (ch.Advance >> 6) * scale;
|
||||
++wordstart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
cursor[1] -= scale * font.height;
|
||||
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
29
source/engine/font.h
Normal file
29
source/engine/font.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef FONT_H
|
||||
#define FONT_H
|
||||
|
||||
#include "mathc.h"
|
||||
|
||||
struct mShader;
|
||||
|
||||
/// Holds all state information relevant to a character as loaded using FreeType
|
||||
struct Character {
|
||||
uint32_t TextureID; // ID handle of the glyph texture
|
||||
mfloat_t Size[2]; // Size of glyph
|
||||
mfloat_t Bearing[2]; // Offset from baseline to left/top of glyph
|
||||
unsigned int Advance; // Horizontal offset to advance to next glyph
|
||||
};
|
||||
|
||||
struct sFont {
|
||||
uint32_t fontTexture;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct sFont MakeFont(const char *fontfile, int height);
|
||||
void sdrawCharacter(struct Character c, mfloat_t cursor[2], float scale,
|
||||
struct mShader *shader, float color[3]);
|
||||
void renderText(struct sFont font, struct mShader *shader,
|
||||
const char *text, mfloat_t pos[2], float scale,
|
||||
mfloat_t color[3], float lw);
|
||||
|
||||
|
||||
#endif
|
200
source/engine/gameobject.c
Normal file
200
source/engine/gameobject.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
#include "gameobject.h"
|
||||
|
||||
#include "shader.h"
|
||||
#include "sprite.h"
|
||||
#include "registry.h"
|
||||
#include "2dphysics.h"
|
||||
#include "script.h"
|
||||
#include "vec.h"
|
||||
#include "input.h"
|
||||
#include <string.h>
|
||||
#include <chipmunk.h>
|
||||
|
||||
struct vec *gameobjects = NULL;
|
||||
struct mGameObject *updateGO = NULL;
|
||||
|
||||
const int nameBuf[MAXNAME] = { 0 };
|
||||
const int prefabNameBuf[MAXNAME] = { 0 };
|
||||
|
||||
struct mGameObject *get_gameobject_from_id(int id)
|
||||
{
|
||||
return vec_get(gameobjects, id - 1);
|
||||
}
|
||||
|
||||
static void gameobject_setpickcolor(struct mGameObject *go)
|
||||
{
|
||||
float r = ((go->editor.id & 0x000000FF) >> 0) / 255.f;
|
||||
float g = ((go->editor.id & 0x0000FF00) >> 8) / 255.f;
|
||||
float b = ((go->editor.id & 0x00FF0000) >> 16) / 255.f;
|
||||
|
||||
go->editor.color[0] = r;
|
||||
go->editor.color[1] = g;
|
||||
go->editor.color[2] = b;
|
||||
}
|
||||
|
||||
struct mGameObject *MakeGameobject()
|
||||
{
|
||||
struct mGameObject *go = vec_add(gameobjects, NULL);
|
||||
go->editor.id = gameobjects->len - 1;
|
||||
go->transform.scale = 1.f;
|
||||
gameobject_setpickcolor(go);
|
||||
strncpy(go->editor.mname, "New object", MAXNAME);
|
||||
go->scale = 1.f;
|
||||
go->bodytype = CP_BODY_TYPE_STATIC;
|
||||
go->mass = 1.f;
|
||||
go->body = cpSpaceAddBody(space, cpBodyNew(go->mass, 1.f));
|
||||
|
||||
go->components = vec_make(sizeof(struct component), 10);
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
void gameobject_addcomponent(struct mGameObject *go, struct component *c)
|
||||
{
|
||||
struct component *newc = vec_add(go->components, c);
|
||||
newc->go = go;
|
||||
newc->data = newc->make(newc->go);
|
||||
}
|
||||
|
||||
void gameobject_delete(int id)
|
||||
{
|
||||
vec_delete(gameobjects, id);
|
||||
}
|
||||
|
||||
void gameobject_delcomponent(struct mGameObject *go, int n)
|
||||
{
|
||||
vec_del_order(go->components, n);
|
||||
}
|
||||
|
||||
void setup_model_transform(struct mTransform *t, struct mShader *s,
|
||||
float scale)
|
||||
{
|
||||
mfloat_t modelT[16] = { 0.f };
|
||||
mfloat_t matbuff[16] = { 0.f };
|
||||
memcpy(modelT, UNITMAT4, sizeof(modelT));
|
||||
mat4_translate_vec3(modelT, t->position);
|
||||
mat4_multiply(modelT, modelT,
|
||||
mat4_rotation_quat(matbuff, t->rotation));
|
||||
mat4_scale_vec3f(modelT, scale);
|
||||
shader_setmat4(s, "model", modelT);
|
||||
|
||||
}
|
||||
|
||||
void gameobject_save(struct mGameObject *go, FILE * file)
|
||||
{
|
||||
fwrite(go, sizeof(*go), 1, file);
|
||||
|
||||
vec_store(go->components, file);
|
||||
|
||||
for (int i = 0; i < go->components->len; i++) {
|
||||
struct component *c = vec_get(go->components, i);
|
||||
fwrite(c, c->datasize, 1, file);
|
||||
}
|
||||
}
|
||||
|
||||
void gameobject_saveprefab(struct mGameObject *go)
|
||||
{
|
||||
char prefabfname[60] = { '\0' };
|
||||
strncat(prefabfname, go->editor.prefabName, MAXNAME);
|
||||
strncat(prefabfname, ".yugh", 10);
|
||||
FILE *pfile = fopen(prefabfname, "w+");
|
||||
gameobject_save(go, pfile);
|
||||
fclose(pfile);
|
||||
|
||||
findPrefabs();
|
||||
}
|
||||
|
||||
void gameobject_makefromprefab(char *path)
|
||||
{
|
||||
FILE *fprefab = fopen(path, "r");
|
||||
if (fprefab == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct mGameObject *new = MakeGameobject();
|
||||
fread(new, sizeof(*new), 1, fprefab);
|
||||
|
||||
new->editor.id = gameobjects->len - 1;
|
||||
new->body = cpSpaceAddBody(space, cpBodyNew(new->mass, 1.f));
|
||||
|
||||
gameobject_init(new, fprefab);
|
||||
|
||||
fclose(fprefab);
|
||||
}
|
||||
|
||||
void gameobject_init(struct mGameObject *go, FILE * fprefab)
|
||||
{
|
||||
go->body = cpSpaceAddBody(space, cpBodyNew(go->mass, 1.f));
|
||||
|
||||
vec_load(go->components, fprefab);
|
||||
|
||||
for (int i = 0; i < go->components->len; i++) {
|
||||
struct component *newc =
|
||||
vec_set(go->components, i,
|
||||
&components[((struct component *)
|
||||
vec_get(go->components, i))->id]);
|
||||
newc->go = go;
|
||||
newc->data = malloc(newc->datasize);
|
||||
fread(newc->data, newc->datasize, 1, fprefab);
|
||||
newc->init(newc->data, go);
|
||||
}
|
||||
}
|
||||
|
||||
void gameobject_syncprefabs(char *revertPath)
|
||||
{
|
||||
/*
|
||||
struct mGameObject **go = objects;
|
||||
int i = 0;
|
||||
while(i != nobjects) {
|
||||
if ((*go)->editor.curPrefabPath && !strcmp((*go)->editor.curPrefabPath, revertPath)) { ; }//objectRevertPrefab(go); //TODO: revertprefab
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void gameobject_revertprefab(struct mGameObject *go)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void toggleprefab(struct mGameObject *go)
|
||||
{
|
||||
go->editor.prefabSync = !go->editor.prefabSync;
|
||||
|
||||
if (go->editor.prefabSync) {
|
||||
strcpy(go->editor.prefabName, go->editor.rootPrefabName);
|
||||
gameobject_revertprefab(go); //TODO: object revert prefab
|
||||
} else {
|
||||
go->editor.prefabName[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void component_update(struct component *c)
|
||||
{
|
||||
if (c->update)
|
||||
c->update(c->data, c->go);
|
||||
}
|
||||
|
||||
void gameobject_update(struct mGameObject *go)
|
||||
{
|
||||
if (go->update) {
|
||||
updateGO = go;
|
||||
script_run(updateGO->update);
|
||||
}
|
||||
|
||||
vec_walk(go->components, component_update);
|
||||
}
|
||||
|
||||
void gameobject_move(struct mGameObject *go, float xs, float ys)
|
||||
{
|
||||
cpVect p = cpBodyGetPosition(go->body);
|
||||
p.x += xs * deltaT;
|
||||
p.y += ys * deltaT;
|
||||
cpBodySetPosition(go->body, p);
|
||||
}
|
||||
|
||||
void gameobject_rotate(struct mGameObject *go, float as)
|
||||
{
|
||||
cpFloat a = cpBodyGetAngle(go->body);
|
||||
a += as * deltaT;
|
||||
cpBodySetAngle(go->body, a);
|
||||
}
|
73
source/engine/gameobject.h
Normal file
73
source/engine/gameobject.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef GAMEOBJECT_H
|
||||
#define GAMEOBJECT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mathc.h"
|
||||
#include "transform.h"
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
#include <chipmunk.h>
|
||||
|
||||
struct mShader;
|
||||
struct mSprite;
|
||||
struct component;
|
||||
struct vec;
|
||||
|
||||
extern struct mGameObject *updateGO;
|
||||
extern struct vec *gameobjects;
|
||||
|
||||
struct editor {
|
||||
mfloat_t color[3];
|
||||
int id;
|
||||
bool active;
|
||||
bool prefabSync;
|
||||
char mname[MAXNAME];
|
||||
char *curPrefabPath;
|
||||
char prefabName[MAXNAME];
|
||||
char rootPrefabName[MAXNAME];
|
||||
};
|
||||
|
||||
struct mGameObject {
|
||||
struct mTransform transform;
|
||||
struct editor editor;
|
||||
cpBodyType bodytype;
|
||||
float scale;
|
||||
float mass;
|
||||
cpBody *body;
|
||||
float f; /* friction */
|
||||
float e; /* elasticity */
|
||||
struct vec *components;
|
||||
char *start;
|
||||
char *update;
|
||||
char *fixedupdate;
|
||||
char *stop;
|
||||
};
|
||||
|
||||
struct mGameObject *MakeGameobject();
|
||||
void gameobject_delete(int id);
|
||||
void clear_gameobjects();
|
||||
int number_of_gameobjects();
|
||||
void set_n_gameobjects(int n);
|
||||
void setup_model_transform(struct mTransform *t, struct mShader *s,
|
||||
float scale);
|
||||
void toggleprefab(struct mGameObject *go);
|
||||
struct mGameObject *get_gameobject_from_id(int id);
|
||||
void gameobject_save(struct mGameObject *go, FILE * file);
|
||||
void gameobject_addcomponent(struct mGameObject *go, struct component *c);
|
||||
void gameobject_delcomponent(struct mGameObject *go, int n);
|
||||
void gameobject_loadcomponent(struct mGameObject *go, int id);
|
||||
|
||||
void gameobject_saveprefab(struct mGameObject *go);
|
||||
void gameobject_makefromprefab(char *path);
|
||||
void gameobject_syncprefabs(char *revertPath);
|
||||
void gameobject_revertprefab(struct mGameObject *go);
|
||||
|
||||
void gameobject_init(struct mGameObject *go, FILE * fprefab);
|
||||
|
||||
void gameobject_update(struct mGameObject *go);
|
||||
void update_gameobjects();
|
||||
|
||||
void gameobject_move(struct mGameObject *go, float xs, float ys);
|
||||
void gameobject_rotate(struct mGameObject *go, float as);
|
||||
|
||||
#endif
|
1
source/engine/gizmo.c
Normal file
1
source/engine/gizmo.c
Normal file
|
@ -0,0 +1 @@
|
|||
#include <gizmo.h>
|
4
source/engine/gizmo.h
Normal file
4
source/engine/gizmo.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef GIZMO_H
|
||||
#define GIZMO_H
|
||||
|
||||
#endif
|
33
source/engine/input.c
Normal file
33
source/engine/input.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "input.h"
|
||||
|
||||
#include "window.h"
|
||||
#include <SDL.h>
|
||||
|
||||
int32_t mouseWheelX = 0;
|
||||
int32_t mouseWheelY = 0;
|
||||
int ychange = 0;
|
||||
int xchange = 0;
|
||||
float deltaT = 0;
|
||||
int quit = 0;
|
||||
SDL_Event e = { 0 };
|
||||
|
||||
uint8_t *currentKeystates = NULL;
|
||||
|
||||
void input_poll()
|
||||
{
|
||||
ychange = 0;
|
||||
xchange = 0;
|
||||
mouseWheelX = 0;
|
||||
mouseWheelY = 0;
|
||||
currentKeystates = SDL_GetKeyboardState(NULL);
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
window_handle_event(window, &e);
|
||||
|
||||
#ifdef EDITOR
|
||||
editor_input(&e);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
18
source/engine/input.h
Normal file
18
source/engine/input.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef INPUT_H
|
||||
#define INPUT_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern int32_t mouseWheelX;
|
||||
extern int32_t mouseWheelY;
|
||||
extern int ychange;
|
||||
extern int xchange;
|
||||
extern float deltaT;
|
||||
extern int quit;
|
||||
extern SDL_Event e;
|
||||
extern uint8_t *currentKeystates;
|
||||
|
||||
void input_poll();
|
||||
|
||||
#endif
|
50
source/engine/level.c
Normal file
50
source/engine/level.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "level.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "vec.h"
|
||||
#include "gameobject.h"
|
||||
|
||||
void save_level(char name[MAXNAME])
|
||||
{
|
||||
FILE *lfile = res_open(name, "w+");
|
||||
|
||||
if (!lfile) return;
|
||||
|
||||
|
||||
int objs = gameobjects->len;
|
||||
fwrite(&objs, sizeof(objs), 1, lfile);
|
||||
|
||||
for (int i = 0; i < objs; i++) {
|
||||
gameobject_save(vec_get(gameobjects, i), lfile);
|
||||
}
|
||||
|
||||
fclose(lfile);
|
||||
}
|
||||
|
||||
void load_level(char name[MAXNAME])
|
||||
{
|
||||
FILE *lfile = fopen(name, "r");
|
||||
|
||||
if (!lfile) return;
|
||||
|
||||
|
||||
int objs;
|
||||
fread(&objs, sizeof(objs), 1, lfile);
|
||||
|
||||
vec_clear(gameobjects);
|
||||
|
||||
|
||||
for (int i = 0; i < objs; i++) {
|
||||
struct mGameObject *go = vec_add(gameobjects, NULL);
|
||||
fread(go, sizeof(struct mGameObject), 1, lfile);
|
||||
gameobject_init(go, lfile);
|
||||
}
|
||||
|
||||
fclose(lfile);
|
||||
|
||||
}
|
||||
|
||||
void new_level()
|
||||
{
|
||||
vec_clear(gameobjects);
|
||||
}
|
17
source/engine/level.h
Normal file
17
source/engine/level.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef LEVEL_H
|
||||
#define LEVEL_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// This class holds all of the entities and options for a level. Really it's nothing more than a container and access point for all the entities currently loaded into the game.
|
||||
|
||||
struct level {
|
||||
char name[MAXNAME];
|
||||
};
|
||||
|
||||
void save_level(char name[MAXNAME]);
|
||||
void load_level(char name[MAXNAME]);
|
||||
void new_level();
|
||||
|
||||
|
||||
#endif
|
160
source/engine/light.c
Normal file
160
source/engine/light.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include <light.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/*
|
||||
void Light::serialize(FILE * file)
|
||||
{
|
||||
GameObject::serialize(file);
|
||||
|
||||
SerializeFloat(file, &strength);
|
||||
SerializeVec3(file, (float *) &color);
|
||||
SerializeBool(file, &dynamic);
|
||||
}
|
||||
|
||||
void Light::deserialize(FILE * file)
|
||||
{
|
||||
GameObject::deserialize(file);
|
||||
|
||||
DeserializeFloat(file, &strength);
|
||||
DeserializeVec3(file, (float *) &color);
|
||||
DeserializeBool(file, &dynamic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const mfloat_t dlight_init_rot[3] = { 80.f, 120.f, 165.f };
|
||||
|
||||
struct mDirectionalLight *dLight = NULL;
|
||||
|
||||
struct mDirectionalLight *MakeDLight()
|
||||
{
|
||||
if (dLight != NULL) {
|
||||
dLight =
|
||||
(struct mDirectionalLight *)
|
||||
malloc(sizeof(struct mDirectionalLight));
|
||||
quat_from_euler(dLight->light.obj.transform.rotation,
|
||||
dlight_init_rot);
|
||||
|
||||
return dLight;
|
||||
}
|
||||
|
||||
return dLight;
|
||||
}
|
||||
|
||||
void dlight_prepshader(struct mDirectionalLight *light,
|
||||
struct mShader *shader)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
trans_forward(fwd, &light->light.obj.transform);
|
||||
shader_setvec3(shader, "dirLight.direction", fwd);
|
||||
shader_setvec3(shader, "dirLight.color", light->light.color);
|
||||
shader_setfloat(shader, "dirLight.strength", light->light.strength);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct mPointLight *pointLights[4];
|
||||
static int numLights = 0;
|
||||
|
||||
|
||||
struct mPointLight *MakePointlight()
|
||||
{
|
||||
if (numLights < 4) {
|
||||
struct mPointLight *light =
|
||||
(struct mPointLight *) malloc(sizeof(struct mPointLight));
|
||||
pointLights[numLights++] = light;
|
||||
light->light.strength = 0.2f;
|
||||
light->constant = 1.f;
|
||||
light->linear = 0.9f;
|
||||
light->quadratic = 0.032f;
|
||||
return light;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void prepstring(char *buffer, char *prepend, const char *append)
|
||||
{
|
||||
snprintf(buffer, 100, "%s%s", prepend, append);
|
||||
}
|
||||
|
||||
void pointlights_prepshader(struct mShader *shader)
|
||||
{
|
||||
for (int i = 0; i < numLights; i++)
|
||||
pointlight_prepshader(pointLights[i], shader, i);
|
||||
}
|
||||
|
||||
void pointlight_prepshader(struct mPointLight *light,
|
||||
struct mShader *shader, int num)
|
||||
{
|
||||
shader_use(shader);
|
||||
char prepend[100] = { '\0' };
|
||||
snprintf(prepend, 100, "%s%d%s", "pointLights[", num, "].");
|
||||
char str[100] = { '\0' };
|
||||
|
||||
prepstring(str, prepend, "position");
|
||||
shader_setvec3(shader, str, light->light.obj.transform.position);
|
||||
|
||||
prepstring(str, prepend, "constant");
|
||||
shader_setfloat(shader, str, light->constant);
|
||||
|
||||
prepstring(str, prepend, "linear");
|
||||
shader_setfloat(shader, str, light->linear);
|
||||
|
||||
prepstring(str, prepend, "quadratic");
|
||||
shader_setfloat(shader, str, light->quadratic);
|
||||
|
||||
prepstring(str, prepend, "strength");
|
||||
shader_setfloat(shader, str, light->light.strength);
|
||||
|
||||
prepstring(str, prepend, "color");
|
||||
shader_setvec3(shader, str, light->light.color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static struct mSpotLight *spotLights[4];
|
||||
static int numSpots = 0;
|
||||
|
||||
struct mSpotLight *MakeSpotlight()
|
||||
{
|
||||
if (numSpots < 4) {
|
||||
struct mSpotLight *light =
|
||||
(struct mSpotLight *) malloc(sizeof(struct mSpotLight));
|
||||
spotLights[numSpots++] = light;
|
||||
return light;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void spotlights_prepshader(struct mShader *shader)
|
||||
{
|
||||
for (int i = 0; i < numSpots; i++)
|
||||
spotlight_prepshader(spotLights[i], shader, i);
|
||||
}
|
||||
|
||||
void spotlight_prepshader(struct mSpotLight *light, struct mShader *shader,
|
||||
int num)
|
||||
{
|
||||
mfloat_t fwd[3] = { 0.f };
|
||||
trans_forward(fwd, &light->light.obj.transform);
|
||||
shader_use(shader);
|
||||
shader_setvec3(shader, "spotLight.position",
|
||||
light->light.obj.transform.position);
|
||||
shader_setvec3(shader, "spotLight.direction", fwd);
|
||||
shader_setvec3(shader, "spotLight.color", light->light.color);
|
||||
shader_setfloat(shader, "spotLight.strength", light->light.strength);
|
||||
shader_setfloat(shader, "spotLight.cutoff", light->cutoff);
|
||||
shader_setfloat(shader, "spotLight.distance", light->distance);
|
||||
shader_setfloat(shader, "spotLight.outerCutoff", light->outerCutoff);
|
||||
shader_setfloat(shader, "spotLight.linear", light->linear);
|
||||
shader_setfloat(shader, "spotLight.quadratic", light->quadratic);
|
||||
shader_setfloat(shader, "spotLight.constant", light->constant);
|
||||
}
|
||||
|
||||
*/
|
58
source/engine/light.h
Normal file
58
source/engine/light.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
#ifndef LIGHT_H
|
||||
#define LIGHT_H
|
||||
|
||||
/*
|
||||
struct mLight {
|
||||
struct mGameObject obj;
|
||||
mfloat_t color[3];
|
||||
float strength;
|
||||
int dynamic;
|
||||
int on;
|
||||
};
|
||||
|
||||
|
||||
struct mPointLight {
|
||||
struct mLight light;
|
||||
float constant;
|
||||
float linear;
|
||||
float quadratic;
|
||||
};
|
||||
|
||||
struct mPointLight *MakePointlight();
|
||||
void pointlight_prepshader(struct mPointLight *light,
|
||||
struct mShader *shader, int num);
|
||||
void pointlights_prepshader(struct mShader *shader);
|
||||
|
||||
|
||||
struct mSpotLight {
|
||||
struct mLight light;
|
||||
float constant;
|
||||
float linear;
|
||||
float quadratic;
|
||||
float distance;
|
||||
|
||||
float cutoff;
|
||||
float outerCutoff;
|
||||
};
|
||||
|
||||
struct mSpotLight *MakeSpotlight();
|
||||
void spotlight_gui(struct mSpotLight *light);
|
||||
void spotlight_prepshader(struct mSpotLight *light, struct mShader *shader,
|
||||
int num);
|
||||
void spotlights_prepshader(struct mShader *shader);
|
||||
|
||||
|
||||
|
||||
struct mDirectionalLight {
|
||||
struct mLight light;
|
||||
};
|
||||
|
||||
void dlight_prepshader(struct mDirectionalLight *light,
|
||||
struct mShader *shader);
|
||||
struct mDirectionalLight *MakeDLight();
|
||||
|
||||
extern struct mDirectionalLight *dLight;
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
56
source/engine/log.c
Normal file
56
source/engine/log.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "log.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
#define logLevel 0
|
||||
|
||||
void mYughLog(int category, int priority, const char *message,
|
||||
int line, const char *file, ...)
|
||||
{
|
||||
if (priority >= logLevel) {
|
||||
time_t now = time(0);
|
||||
char *dt = ctime(&now);
|
||||
dt[strlen(dt) - 1] = '\0'; // The above time conversion adds a \n; this removes it
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
char msgbuffer[ERROR_BUFFER] = { '\0' };
|
||||
vsnprintf(msgbuffer, ERROR_BUFFER, message, args);
|
||||
va_end(args);
|
||||
|
||||
char buffer[ERROR_BUFFER] = { '\0' };
|
||||
snprintf(buffer, ERROR_BUFFER, "LEVEL %d :: %s [ %s:%d ] %s\n",
|
||||
priority, msgbuffer, file, line, dt);
|
||||
|
||||
//SDL_LogMessage(category, priority, buffer);
|
||||
printf(buffer);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void FlushGLErrors()
|
||||
{
|
||||
GLenum glErr = GL_NO_ERROR;
|
||||
glErr = glGetError();
|
||||
while (glErr != GL_NO_ERROR) {
|
||||
YughLog(SDL_LOG_CATEGORY_RENDER, SDL_LOG_PRIORITY_ERROR,
|
||||
"GL Error: %d", glErr);
|
||||
glErr = glGetError();
|
||||
}
|
||||
}
|
||||
|
||||
int TestSDLError(int sdlErr)
|
||||
{
|
||||
if (sdlErr != 0) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR, "SDL Error :: %s",
|
||||
SDL_GetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
17
source/engine/log.h
Normal file
17
source/engine/log.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <SDL_log.h>
|
||||
|
||||
#define ERROR_BUFFER 2048
|
||||
|
||||
#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, msg, __LINE__, __FILE__, __VA_ARGS__)
|
||||
|
||||
void mYughLog(int category, int priority, const char *message,
|
||||
int line, const char *file, ...);
|
||||
|
||||
void FlushGLErrors();
|
||||
|
||||
int TestSDLError(int sdlErr);
|
||||
|
||||
#endif
|
7545
source/engine/mathc.c
Normal file
7545
source/engine/mathc.c
Normal file
File diff suppressed because it is too large
Load diff
1659
source/engine/mathc.h
Normal file
1659
source/engine/mathc.h
Normal file
File diff suppressed because it is too large
Load diff
132
source/engine/mesh.c
Normal file
132
source/engine/mesh.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include "mesh.h"
|
||||
|
||||
#include "shader.h"
|
||||
#include "texture.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
void DrawMesh(struct mMesh *mesh, struct mShader *shader)
|
||||
{
|
||||
// bind appropriate textures
|
||||
uint32_t diffuseNr = 1;
|
||||
uint32_t specularNr = 1;
|
||||
uint32_t normalNr = 1;
|
||||
uint32_t heightNr = 1;
|
||||
|
||||
for (uint32_t i = 0; i < (mesh->te - mesh->textures); i++) {
|
||||
glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding
|
||||
// retrieve texture number (the N in diffuse_textureN)
|
||||
char number;
|
||||
// TODO: malloc every single frame ... nope! Change to stack
|
||||
char *name =
|
||||
(char *) malloc(sizeof(char) *
|
||||
(strlen(mesh->textures[i].type) + 2));
|
||||
if (mesh->textures[i].type == "texture_diffuse")
|
||||
number = diffuseNr++;
|
||||
else if (mesh->textures[i].type == "texture_specular")
|
||||
number = specularNr++;
|
||||
else if (mesh->textures[i].type == "texture_normal")
|
||||
number = normalNr++;
|
||||
else if (mesh->textures[i].type == "texture_height")
|
||||
number = heightNr++;
|
||||
|
||||
sprintf(name, "%s%d", mesh->textures[i].type, number);
|
||||
// now set the sampler to the correct texture unit
|
||||
glUniform1i(glGetUniformLocation(shader->id, name), i);
|
||||
// and finally bind the texture
|
||||
glBindTexture(GL_TEXTURE_2D, mesh->textures[i].id);
|
||||
free(name);
|
||||
}
|
||||
|
||||
// draw mesh
|
||||
glBindVertexArray(mesh->VAO);
|
||||
DrawMeshAgain(mesh);
|
||||
|
||||
// DEBUG
|
||||
// triCount += indices.size() / 3;
|
||||
}
|
||||
|
||||
|
||||
void DrawMeshAgain(struct mMesh *mesh)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLES, (mesh->ie - mesh->indices),
|
||||
GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
struct mMesh *MakeMesh(struct Vertex *vertices, struct Vertex *ve,
|
||||
uint32_t * indices, uint32_t * ie,
|
||||
struct Texture *textures, struct Texture *te)
|
||||
{
|
||||
struct mMesh *newmesh = (struct mMesh *) malloc(sizeof(struct mMesh));
|
||||
newmesh->vertices = vertices;
|
||||
newmesh->ve = ve;
|
||||
newmesh->indices = indices;
|
||||
newmesh->ie = ie;
|
||||
newmesh->textures = textures;
|
||||
newmesh->te = te;
|
||||
|
||||
setupmesh(newmesh);
|
||||
return newmesh;
|
||||
}
|
||||
|
||||
void setupmesh(struct mMesh *mesh)
|
||||
{
|
||||
// create buffers/arrays
|
||||
glGenVertexArrays(1, &mesh->VAO);
|
||||
glGenBuffers(1, &mesh->VBO);
|
||||
glGenBuffers(1, &mesh->EBO);
|
||||
|
||||
glBindVertexArray(mesh->VAO);
|
||||
// load data into vertex buffers
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh->VBO);
|
||||
|
||||
|
||||
// The effect is that we can simply pass a pointer to the struct and it translates perfectly to vevc array which
|
||||
// again translates to 3/2 floats which translates to a byte array.
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
(mesh->ve - mesh->vertices) * sizeof(struct Vertex),
|
||||
&mesh->vertices[0], GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
(mesh->ie - mesh->indices) * sizeof(uint32_t),
|
||||
&mesh->indices[0], GL_STATIC_DRAW);
|
||||
|
||||
// set the vertex attribute pointers
|
||||
// vertex Positions
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) 0);
|
||||
// vertex normals
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex, Normal[3]));
|
||||
// vertex texture coords
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex, TexCoords[2]));
|
||||
// vertex tangent
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex, Tangent[3]));
|
||||
// vertex bitangent
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex, Bitangent[3]));
|
||||
|
||||
// Bone ids
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribPointer(5, 4, GL_INT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex,
|
||||
m_BoneIDs
|
||||
[MAX_BONE_INFLUENCE]));
|
||||
|
||||
// Weights
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(struct Vertex),
|
||||
(void *) offsetof(struct Vertex, m_Weights));
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
41
source/engine/mesh.h
Normal file
41
source/engine/mesh.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef MESH_H
|
||||
#define MESH_H
|
||||
|
||||
#include "mathc.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct mShader;
|
||||
struct Texture;
|
||||
|
||||
#define MAX_BONE_INFLUENCE 4
|
||||
|
||||
struct Vertex {
|
||||
mfloat_t Position[3];
|
||||
mfloat_t Normal[3];
|
||||
mfloat_t TexCoords[2];
|
||||
mfloat_t Tangent[3];
|
||||
mfloat_t Bitangent[3];
|
||||
|
||||
int m_BoneIDs[MAX_BONE_INFLUENCE];
|
||||
|
||||
float m_Weights[MAX_BONE_INFLUENCE];
|
||||
};
|
||||
|
||||
struct mMesh {
|
||||
struct Vertex *vertices;
|
||||
struct Vertex *ve;
|
||||
uint32_t *indices;
|
||||
uint32_t *ie;
|
||||
struct Texture *textures;
|
||||
struct Texture *te;
|
||||
uint32_t VAO, VBO, EBO;
|
||||
};
|
||||
|
||||
struct mMesh *MakeMesh(struct Vertex *vertices, struct Vertex *ve,
|
||||
uint32_t * indices, uint32_t * ie,
|
||||
struct Texture *textures, struct Texture *te);
|
||||
void setupmesh(struct mMesh *mesh); /* Loads mesh into the GPU */
|
||||
void DrawMesh(struct mMesh *mesh, struct mShader *shader);
|
||||
void DrawMeshAgain(struct mMesh *mesh); /* Draws whatever mesh was drawn last */
|
||||
|
||||
#endif
|
281
source/engine/model.c
Normal file
281
source/engine/model.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
#include "model.h"
|
||||
|
||||
#include "mesh.h"
|
||||
#include "resources.h"
|
||||
#include "shader.h"
|
||||
#include <SDL_image.h>
|
||||
#include <cgltf.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct mModel *lastRendered;
|
||||
static struct mModel *loadedModels[100];
|
||||
static struct mModel **lastModel = loadedModels;
|
||||
|
||||
static void processnode();
|
||||
static void processmesh();
|
||||
static void processtexture();
|
||||
|
||||
|
||||
struct mModel *GetExistingModel(const char *path)
|
||||
{
|
||||
struct mModel **model = loadedModels;
|
||||
|
||||
while (model++ != lastModel) {
|
||||
if (!strcmp(path, (*model)->path))
|
||||
goto end;
|
||||
|
||||
return MakeModel(path);
|
||||
|
||||
}
|
||||
|
||||
end:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* TODO: Make this a hash compare for speedup */
|
||||
struct mModel *MakeModel(const char *path)
|
||||
{
|
||||
char *modelPath =
|
||||
(char *) malloc(sizeof(char) *
|
||||
(strlen(DATA_PATH) + strlen(path) + 1));
|
||||
modelPath[0] = '\0';
|
||||
strcat(modelPath, DATA_PATH);
|
||||
strcat(modelPath, path);
|
||||
printf
|
||||
("Created new model with modelPath %s, from data_path %s and path %s\n",
|
||||
modelPath, DATA_PATH, path);
|
||||
|
||||
struct mModel *newmodel =
|
||||
(struct mModel *) malloc(sizeof(struct mModel));
|
||||
newmodel->path = path;
|
||||
|
||||
loadmodel(newmodel);
|
||||
*lastModel++ = newmodel;
|
||||
return newmodel;
|
||||
}
|
||||
|
||||
// TODO: Come back to this; simple optimization
|
||||
void draw_model(struct mModel *model, struct mShader *shader)
|
||||
{
|
||||
if (lastRendered != model) {
|
||||
lastRendered = model;
|
||||
for (uint32_t i = 0; i < (model->mp - model->meshes); i++)
|
||||
DrawMesh(&model->meshes[i], shader);
|
||||
} else {
|
||||
for (uint32_t i = 0; i < (model->mp - model->meshes); i++)
|
||||
DrawMeshAgain(&model->meshes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void loadmodel(struct mModel *model)
|
||||
{
|
||||
printf("Loading model at path %s\n", model->path);
|
||||
/*
|
||||
// Load model with cgltf
|
||||
cgltf_options options = {0};
|
||||
cgltf_data *data = NULL;
|
||||
cgltf_result result = cgltf_parse_file(&options, model->path, &data);
|
||||
|
||||
meshes = (struct mMesh*)malloc(sizeof(Mesh)*cgltf_data->meshes_count);
|
||||
|
||||
directory = get_directory_from_path(model->path);
|
||||
|
||||
for (int i = 0; i < data->nodes_count; i++) {
|
||||
if (data->nodes[i]->mesh) {
|
||||
for (int j = 0; j < data->nodes[i]->mesh->primatives_count; j++) {
|
||||
|
||||
|
||||
for (int k = 0; k < data->nodes[i]->mesh->primatives[j]->attributes_count; k++) {
|
||||
switch(data->nodes[i]->mesh->primatives[j]->attributes[k]->type) {
|
||||
case cgltf_attribute_type_position:
|
||||
Vertex *vs = (Vertex*)malloc(sizeof(Vertex) * cgltf_accessor_unpack_floats(:::attributes[k]->accesor, NULL, attributes[k]->accessor.count);
|
||||
cgltf_accessor_unpack_floats(:::attributes[k]->accessor, vs, attributes[k]->accessor.count);
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_normal:
|
||||
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_tangent:
|
||||
break;
|
||||
|
||||
case cgltf_attribute_type_texcoord:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO: DELETE
|
||||
|
||||
|
||||
|
||||
// read file via ASSIMP
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile(path,
|
||||
aiProcess_Triangulate |
|
||||
aiProcess_GenSmoothNormals |
|
||||
aiProcess_FlipUVs |
|
||||
aiProcess_CalcTangentSpace);
|
||||
// check for errors
|
||||
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE
|
||||
|| !scene->mRootNode) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"ASSIMP error: %s",
|
||||
importer.GetErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
directory = get_directory_from_path(path);
|
||||
|
||||
meshes = (Mesh *) malloc(sizeof(Mesh) * 100);
|
||||
mp = meshes;
|
||||
// process ASSIMP's root node recursively
|
||||
processNode(scene->mRootNode, scene); */
|
||||
}
|
||||
|
||||
|
||||
static void processnode()
|
||||
{
|
||||
/*
|
||||
for (uint32_t i = 0; i < node->mNumMeshes; i++) {
|
||||
aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];
|
||||
*mp = processMesh(mesh, scene);
|
||||
mp++;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < node->mNumChildren; i++) {
|
||||
processnode(node->mChildren[i], scene);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
static void processmesh()
|
||||
{
|
||||
/*
|
||||
Vertex *vertices =
|
||||
(Vertex *) malloc(sizeof(Vertex) * mesh->mNumVertices);
|
||||
Vertex *vp = vertices + mesh->mNumVertices;
|
||||
Vertex *p = vertices;
|
||||
for (int i = 0; i < mesh->mNumVertices; i++) {
|
||||
// positions
|
||||
(p + i)->Position.x = mesh->mVertices[i][0];
|
||||
(p + i)->Position.y = mesh->mVertices[i][1];
|
||||
(p + i)->Position.z = mesh->mVertices[i][2];
|
||||
|
||||
|
||||
// normals
|
||||
if (mesh->HasNormals()) {
|
||||
(p + i)->Normal.x = mesh->mNormals[i][0];
|
||||
(p + i)->Normal.y = mesh->mNormals[i].y;
|
||||
(p + i)->Normal.z = mesh->mNormals[i].z;
|
||||
}
|
||||
|
||||
// texture coordinates
|
||||
if (mesh->mTextureCoords[0]) {
|
||||
glm::vec2 vec;
|
||||
// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
|
||||
// use models where a vertex can have multiple texture coordinates so we always take the first set (0).
|
||||
(p + i)->TexCoords.x = mesh->mTextureCoords[0][i].x;
|
||||
(p + i)->TexCoords.y = mesh->mTextureCoords[0][i].y;
|
||||
|
||||
// tangent
|
||||
(p + i)->Tangent.x = mesh->mTangents[i].x;
|
||||
(p + i)->Tangent.y = mesh->mTangents[i].y;
|
||||
(p + i)->Tangent.z = mesh->mTangents[i].z;
|
||||
|
||||
// bitangent
|
||||
(p + i)->Bitangent.x = mesh->mBitangents[i].x;
|
||||
(p + i)->Bitangent.y = mesh->mBitangents[i].y;
|
||||
(p + i)->Bitangent.z = mesh->mBitangents[i].z;
|
||||
|
||||
} else
|
||||
(p + i)->TexCoords = glm::vec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: Done quickly, find better way. Go through for loop twice!
|
||||
int numindices = 0;
|
||||
// now walk through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.
|
||||
for (uint32_t i = 0; i < mesh->mNumFaces; i++) {
|
||||
numindices += mesh->mFaces[i].mNumIndices;
|
||||
}
|
||||
|
||||
uint32_t *indices = (uint32_t *) malloc(sizeof(uint32_t) * numindices);
|
||||
uint32_t *ip = indices;
|
||||
|
||||
for (uint32_t i = 0; i < mesh->mNumFaces; i++) {
|
||||
for (uint32_t j = 0; j < mesh->mFaces[i].mNumIndices; j++) {
|
||||
*ip = mesh->mFaces[i].mIndices[j];
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// std::vector<Texture> textures;
|
||||
aiMaterial *material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
// TODO: Allocating 100 to be safe, can probably be way less
|
||||
textures_loaded = (Texture *) malloc(sizeof(Texture) * 100);
|
||||
tp = textures_loaded;
|
||||
// we assume a convention for sampler names in the shaders. Each diffuse texture should be named
|
||||
// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER.
|
||||
// Same applies to other texture as the following list summarizes:
|
||||
// diffuse: texture_diffuseN
|
||||
// specular: texture_specularN
|
||||
// normal: texture_normalN
|
||||
|
||||
// 1. diffuse maps
|
||||
loadMaterialTextures(material, aiTextureType_DIFFUSE,
|
||||
"texture_diffuse");
|
||||
|
||||
// 2. specular maps
|
||||
loadMaterialTextures(material, aiTextureType_SPECULAR,
|
||||
"texture_specular");
|
||||
|
||||
// 3. normal maps
|
||||
loadMaterialTextures(material, aiTextureType_NORMALS,
|
||||
"texture_normal");
|
||||
|
||||
// 4. height maps
|
||||
loadMaterialTextures(material, aiTextureType_AMBIENT,
|
||||
"texture_height");
|
||||
|
||||
|
||||
// return a mesh object created from the extracted mesh data
|
||||
return Mesh(vertices, vp, indices, ip, textures_loaded, tp);
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
// TODO: This routine mallocs inside the function
|
||||
static void processtexture()
|
||||
{
|
||||
/*
|
||||
for (uint32_t i = 0; i < mat->GetTextureCount(type); i++) {
|
||||
aiString str;
|
||||
mat->GetTexture(type, i, &str);
|
||||
for (Texture * tpp = textures_loaded; tpp != tp; tpp++) {
|
||||
if (strcmp(tpp->path, str.data) == 0)
|
||||
goto next; // Check if we already have this texture
|
||||
}
|
||||
|
||||
tp->id = TextureFromFile(str.data, this->directory);
|
||||
tp->type = (char *) malloc(sizeof(char) * strlen(typeName));
|
||||
strcpy(tp->type, typeName);
|
||||
tp->path = (char *) malloc(sizeof(char) * strlen(str.data));
|
||||
strcpy(tp->path, str.data);
|
||||
|
||||
tp++;
|
||||
|
||||
next:;
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
26
source/engine/model.h
Normal file
26
source/engine/model.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
struct mMesh;
|
||||
struct mShader;
|
||||
|
||||
struct mModel {
|
||||
struct mMesh *meshes;
|
||||
struct mMesh *mp;
|
||||
char *directory;
|
||||
const char *path;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* Get the model at a path, or create and return if it doesn't exist */
|
||||
struct mModel *GetExistingModel(const char *path);
|
||||
|
||||
/* Make a Model struct */
|
||||
struct mModel *MakeModel(const char *path);
|
||||
|
||||
/* Load a model from memory into the GPU */
|
||||
void loadmodel(struct mModel *model);
|
||||
|
||||
void draw_model(struct mModel *model, struct mShader *shader);
|
||||
|
||||
#endif
|
695
source/engine/openglrender.c
Normal file
695
source/engine/openglrender.c
Normal file
|
@ -0,0 +1,695 @@
|
|||
#include "openglrender.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include "sprite.h"
|
||||
#include "shader.h"
|
||||
#include "font.h"
|
||||
#include "config.h"
|
||||
#include "static_actor.h"
|
||||
#include "gameobject.h"
|
||||
#include "camera.h"
|
||||
#include "window.h"
|
||||
#include "debugdraw.h"
|
||||
#include "log.h"
|
||||
|
||||
int renderMode = 0;
|
||||
|
||||
static GLuint UBO;
|
||||
static GLuint UBOBind = 0;
|
||||
|
||||
static GLuint gridVBO = 0;
|
||||
static GLuint gridVAO = 0;
|
||||
|
||||
static GLuint quadVAO = 0;
|
||||
static GLuint quadVBO = 0;
|
||||
|
||||
static GLuint depthMapFBO = 0;
|
||||
static GLuint depthMap = 0;
|
||||
const unsigned int SHADOW_WIDTH = 2048, SHADOW_HEIGHT = 2048;
|
||||
|
||||
static struct mShader *outlineShader;
|
||||
static struct mShader *modelShader;
|
||||
static struct mShader *shadowShader;
|
||||
|
||||
struct mShader *spriteShader = NULL;
|
||||
struct mShader *animSpriteShader = NULL;
|
||||
static struct mShader *textShader;
|
||||
static struct mShader *diffuseShader;
|
||||
|
||||
struct sFont stdFont;
|
||||
|
||||
static struct mShader *debugDepthQuad;
|
||||
static struct mShader *debugColorPickShader;
|
||||
static struct mShader *debugGridShader;
|
||||
static struct mShader *debugGizmoShader;
|
||||
|
||||
struct mStaticActor *gizmo;
|
||||
|
||||
float editorFOV = 45.f;
|
||||
float editorClose = 0.1f;
|
||||
float editorFar = 1000.f;
|
||||
mfloat_t editorClearColor[4] = { 0.2f, 0.4f, 0.3f, 1.f };
|
||||
|
||||
float shadowLookahead = 8.5f;
|
||||
|
||||
mfloat_t gridSmallColor[3] = { 0.35f, 1.f, 0.9f };
|
||||
|
||||
mfloat_t gridBigColor[3] = { 0.92f, 0.92f, 0.68f };
|
||||
|
||||
float gridScale = 500.f;
|
||||
float smallGridUnit = 1.f;
|
||||
float bigGridUnit = 10.f;
|
||||
float gridSmallThickness = 2.f;
|
||||
float gridBigThickness = 7.f;
|
||||
float gridOpacity = 0.3f;
|
||||
|
||||
mfloat_t proj[16];
|
||||
|
||||
float near_plane = -100.f, far_plane = 10.f, plane_size = 60.f;
|
||||
|
||||
|
||||
// Debug render modes
|
||||
bool renderGizmos = false;
|
||||
bool showGrid = true;
|
||||
bool debugDrawPhysics = false;
|
||||
bool renderNav = false;
|
||||
|
||||
// Lighting effect flags
|
||||
bool renderAO = true;
|
||||
bool renderDynamicShadows = true;
|
||||
bool renderRefraction = true;
|
||||
bool renderReflection = true;
|
||||
|
||||
///// for editing
|
||||
struct mGameObject *selectedobject = NULL;
|
||||
char objectName[200] = { '\0' }; // object name buffer
|
||||
|
||||
uint16_t debugColorPickBO = 0;
|
||||
uint16_t debugColorPickTEX = 0;
|
||||
|
||||
|
||||
struct mSprite *tsprite = NULL;
|
||||
static struct mSprite *tanim = NULL;
|
||||
|
||||
static unsigned int projUBO;
|
||||
|
||||
void openglInit()
|
||||
{
|
||||
//Initialize SDL
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"SDL could not initialize! SDL Error: %s", SDL_GetError());
|
||||
}
|
||||
//Use OpenGL 3.3
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
||||
SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); /* How many x MSAA */
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
|
||||
|
||||
// TODO: Add non starter initializtion return here for some reason?
|
||||
window = MakeSDLWindow("Untitled Game", 1920, 1080,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN |
|
||||
SDL_WINDOW_RESIZABLE);
|
||||
|
||||
//Use Vsync
|
||||
if (SDL_GL_SetSwapInterval(1)) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_WARN,
|
||||
"Unable to set VSync! SDL Error: %s", SDL_GetError());
|
||||
}
|
||||
////// MAKE SHADERS
|
||||
outlineShader = MakeShader("outlinevert.glsl", "outline.glsl");
|
||||
|
||||
textShader = MakeShader("textvert.glsl", "textfrag.glsl");
|
||||
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
|
||||
animSpriteShader =
|
||||
MakeShader("animspritevert.glsl", "animspritefrag.glsl");
|
||||
|
||||
debugdraw_init();
|
||||
|
||||
stdFont = MakeFont("notosans.ttf", 300);
|
||||
|
||||
//glEnable(GL_STENCIL_TEST);
|
||||
glClearColor(editorClearColor[0], editorClearColor[1],
|
||||
editorClearColor[2], editorClearColor[3]);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glLineWidth(1.3f);
|
||||
/*
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glLineWidth(2);
|
||||
*/
|
||||
|
||||
glGenBuffers(1, &projUBO);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
|
||||
glBufferData(GL_UNIFORM_BUFFER, 64, NULL, GL_DYNAMIC_DRAW);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, projUBO, 0,
|
||||
sizeof(float) * 16);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
|
||||
shader_setUBO(spriteShader, "Projection", 0);
|
||||
shader_setUBO(textShader, "Projection", 0);
|
||||
shader_setUBO(animSpriteShader, "Projection", 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void openglRender(struct mCamera *mcamera)
|
||||
{
|
||||
//////////// 2D projection
|
||||
mfloat_t projection[16] = { 0.f };
|
||||
mat4_ortho(projection, mcamera->transform.position[0],
|
||||
window->width + mcamera->transform.position[0],
|
||||
mcamera->transform.position[1],
|
||||
window->height + mcamera->transform.position[1], -1.f, 1.f);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, projUBO);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, 64, projection);
|
||||
|
||||
/*
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glCullFace(GL_BACK);
|
||||
*/
|
||||
// Clear color and depth
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
////// TEXT && GUI
|
||||
/*
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
shader_use(textShader);
|
||||
shader_setmat4(textShader, "projection", window->projection);
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
mfloat_t fontpos[2] = { 25.f, 25.f };
|
||||
mfloat_t fontcolor[3] = { 0.5f, 0.8f, 0.2f };
|
||||
renderText(stdFont, textShader, "Sample text", fontpos, 0.4f, fontcolor, -1.f);
|
||||
*/
|
||||
|
||||
for (int i = 0; i < numSprites; i++) {
|
||||
sprite_draw(sprites[i]);
|
||||
}
|
||||
|
||||
|
||||
//glDepthFunc(GL_LESS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void openglInit3d(struct mSDLWindow *window)
|
||||
{
|
||||
//Initialize SDL
|
||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"SDL could not initialize! SDL Error: %s", SDL_GetError());
|
||||
}
|
||||
//Use OpenGL 3.3
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
|
||||
SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); /* How many x MSAA */
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
|
||||
|
||||
// TODO: Add non starter initializtion return here for some reason?
|
||||
MakeSDLWindow("Untitled Game", 1280, 720,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN |
|
||||
SDL_WINDOW_RESIZABLE);
|
||||
|
||||
|
||||
//Use Vsync
|
||||
if (!SDL_GL_SetSwapInterval(1)) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_WARN,
|
||||
"Unable to set VSync! SDL Error: %s", SDL_GetError());
|
||||
}
|
||||
/* TODO: IMG init doesn't work in C+
|
||||
int init =(0x00000001 | 0x00000002);
|
||||
int initted =IMG_Init(init);
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR, "Init flags: %d\nInitted values: %d ", init, initted);
|
||||
if ((initted & (IMG_INIT_JPG | IMG_INIT_PNG)) != (IMG_INIT_JPG | IMG_INIT_PNG)) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"IMG_Init: Failed to init required jpg and png support! SDL_IMG error: %s",
|
||||
IMG_GetError());
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
////// MAKE SHADERS
|
||||
outlineShader = MakeShader("outlinevert.glsl", "outline.glsl");
|
||||
diffuseShader = MakeShader("simplevert.glsl", "albedofrag.glsl");
|
||||
modelShader = MakeShader("modelvert.glsl", "modelfrag.glsl");
|
||||
shadowShader = MakeShader("shadowvert.glsl", "shadowfrag.glsl");
|
||||
|
||||
textShader = MakeShader("textvert.glsl", "textfrag.glsl");
|
||||
spriteShader = MakeShader("spritevert.glsl", "spritefrag.glsl");
|
||||
|
||||
debugDepthQuad = MakeShader("postvert.glsl", "debugdepthfrag.glsl");
|
||||
debugColorPickShader =
|
||||
MakeShader("simplevert.glsl", "debugcolorfrag.glsl");
|
||||
debugGridShader = MakeShader("gridvert.glsl", "gridfrag.glsl");
|
||||
debugGizmoShader = MakeShader("gizmovert.glsl", "gizmofrag.glsl");
|
||||
|
||||
stdFont = MakeFont("notosans.ttf", 300);
|
||||
|
||||
shader_compile_all();
|
||||
|
||||
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
|
||||
window->height, editorClose, editorFar);
|
||||
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
glLineWidth(2);
|
||||
|
||||
////
|
||||
// Shadow mapping buffers
|
||||
////
|
||||
glGenFramebuffers(1, &depthMapFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
|
||||
|
||||
glGenTextures(1, &depthMap);
|
||||
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH,
|
||||
SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
float borderColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||
GL_TEXTURE_2D, depthMap, 0);
|
||||
glDrawBuffer(GL_NONE);
|
||||
//glReadBuffer(GL_NONE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
//// Universal buffer to hold projection and light coordinates
|
||||
glGenBuffers(1, &UBO);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
|
||||
|
||||
glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(proj), NULL,
|
||||
GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, UBO, 0, 2 * sizeof(proj));
|
||||
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
|
||||
////// debug color pick buffer
|
||||
glGenFramebuffers(1, &debugColorPickBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
|
||||
|
||||
glGenTextures(1, &debugColorPickTEX);
|
||||
glBindTexture(GL_TEXTURE_2D, debugColorPickTEX);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, debugColorPickTEX, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
|
||||
//////// Create grid
|
||||
float gridVertices[] = {
|
||||
-1.f, 0.f, 1.f, 0.f, 1.f,
|
||||
-1.f, 0.f, -1.f, 0.f, 0.f,
|
||||
1.f, 0.f, 1.f, 1.f, 1.f,
|
||||
1.f, 0.f, -1.f, 1.f, 0.f,
|
||||
};
|
||||
|
||||
glGenVertexArrays(1, &gridVAO);
|
||||
glGenBuffers(1, &gridVBO);
|
||||
glBindVertexArray(gridVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, gridVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(gridVertices), &gridVertices,
|
||||
GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
|
||||
(void *) 0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
|
||||
(void *) (3 * sizeof(float)));
|
||||
|
||||
//////// Create post quad
|
||||
float quadVertices[] = {
|
||||
// positions // texture Coords
|
||||
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
};
|
||||
// setup plane VAO
|
||||
glGenVertexArrays(1, &quadVAO);
|
||||
glGenBuffers(1, &quadVBO);
|
||||
glBindVertexArray(quadVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices,
|
||||
GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
|
||||
(void *) 0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
|
||||
(void *) (3 * sizeof(float)));
|
||||
|
||||
//////
|
||||
|
||||
// skybox = new Skybox("skybox");
|
||||
|
||||
BindUniformBlock(modelShader->id, "Matrices", 0);
|
||||
BindUniformBlock(outlineShader->id, "Matrices", 0);
|
||||
// BindUniformBlock(skybox->shader->id, "Matrices", 0);
|
||||
BindUniformBlock(diffuseShader->id, "Matrices", 0);
|
||||
|
||||
BindUniformBlock(debugGridShader->id, "Matrices", 0);
|
||||
BindUniformBlock(debugGizmoShader->id, "Matrices", 0);
|
||||
|
||||
shader_use(debugDepthQuad);
|
||||
shader_setint(debugDepthQuad, "depthMap", 0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
//////////// 2D projection
|
||||
mfloat_t projection[16] = { 0.f };
|
||||
mat4_ortho(projection, 0.f, SCREEN_WIDTH, SCREEN_HEIGHT, 1.f, -1.f,
|
||||
1.f);
|
||||
shader_setmat4(textShader, "projection", projection);
|
||||
shader_setmat4(spriteShader, "projection", projection);
|
||||
shader_setmat4(debugGizmoShader, "proj", projection);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void openglRender3d(struct mSDLWindow *window, struct mCamera *mcamera)
|
||||
{
|
||||
//////// SET NEW PROJECTION
|
||||
// TODO: Make this not happen every frame
|
||||
mat4_perspective_fov(proj, editorFOV * DEG2RADS, window->width,
|
||||
window->height, editorClose, editorFar);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(proj), proj);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
////////// Render a depthmap from the perspective of the directional light
|
||||
|
||||
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
|
||||
glCullFace(GL_BACK);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Configure matrices with an orthogonal
|
||||
mfloat_t lightView[16] = { 0.f };
|
||||
mfloat_t lightSpaceMatrix[16] = { 0.f };
|
||||
|
||||
/*
|
||||
if (dLight) {
|
||||
|
||||
mfloat_t lightProjection[16] = { 0.f };
|
||||
mat4_ortho(lightProjection, -plane_size, plane_size, -plane_size,
|
||||
plane_size, near_plane, far_plane);
|
||||
|
||||
mfloat_t lookPos[3] = { 0.f };
|
||||
mfloat_t cam_fwd[3] = { 0.f };
|
||||
vec3_add(lookPos, mcamera->transform.position,
|
||||
vec3_multiply_f(lookPos,
|
||||
trans_forward(cam_fwd,
|
||||
&mcamera->transform),
|
||||
shadowLookahead));
|
||||
lookPos[1] = 0.f;
|
||||
|
||||
mfloat_t lightLookPos[3] = { 0.f };
|
||||
mfloat_t light_fwd[3] = { 0.f };
|
||||
mat4_look_at(lightView,
|
||||
vec3_subtract(lightLookPos, lookPos,
|
||||
trans_forward(light_fwd,
|
||||
&dLight->light.obj.
|
||||
transform)), lookPos, UP);
|
||||
|
||||
mat4_multiply(lightSpaceMatrix, lightProjection, lightView);
|
||||
//lightSpaceMatrix = lightProjection * lightView;
|
||||
|
||||
if (renderDynamicShadows) {
|
||||
shader_use(shadowShader);
|
||||
shader_setmat4(shadowShader, "lightSpaceMatrix",
|
||||
lightSpaceMatrix);
|
||||
staticactor_draw_shadowcasters(shadowShader);
|
||||
}
|
||||
}
|
||||
*/
|
||||
//////////////////////////
|
||||
|
||||
// Back to the normal render
|
||||
window_makecurrent(window);
|
||||
|
||||
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
// Render the color thing for debug picking
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO);
|
||||
glClearColor(editorClearColor[0], editorClearColor[1],
|
||||
editorClearColor[2], editorClearColor[3]);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
shader_use(debugColorPickShader);
|
||||
staticactor_draw_dbg_color_pick(debugColorPickShader);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Clear color and depth
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
|
||||
GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (renderMode == DIRSHADOWMAP) {
|
||||
// render Depth map to quad for visual debugging
|
||||
// ---------------------------------------------
|
||||
shader_use(debugDepthQuad);
|
||||
shader_setfloat(debugDepthQuad, "near_plane", near_plane);
|
||||
shader_setfloat(debugDepthQuad, "far_plane", far_plane);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
} else if (renderMode == OBJECTPICKER) {
|
||||
// TODO: This rendering mode
|
||||
shader_use(debugColorPickShader);
|
||||
} else {
|
||||
|
||||
glClearColor(editorClearColor[0], editorClearColor[1],
|
||||
editorClearColor[2], editorClearColor[3]);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
mfloat_t view[16] = { 0.f };
|
||||
getviewmatrix(view, mcamera);
|
||||
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, UBO);
|
||||
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(view), sizeof(view),
|
||||
view);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
|
||||
switch (renderMode) {
|
||||
case LIT:
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
shader_use(modelShader);
|
||||
|
||||
/*
|
||||
if (dLight)
|
||||
dlight_prepshader(dLight, modelShader);
|
||||
|
||||
pointlights_prepshader(modelShader);
|
||||
spotlights_prepshader(modelShader);
|
||||
*/
|
||||
|
||||
shader_setvec3(modelShader, "viewPos",
|
||||
mcamera->transform.position);
|
||||
shader_setmat4(modelShader, "lightSpaceMatrix",
|
||||
lightSpaceMatrix);
|
||||
shader_setint(modelShader, "shadowMap", 12);
|
||||
glActiveTexture(GL_TEXTURE);
|
||||
glBindTexture(GL_TEXTURE_2D, depthMap);
|
||||
staticactor_draw_models(modelShader);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case UNLIT:
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
shader_use(diffuseShader);
|
||||
staticactor_draw_models(diffuseShader);
|
||||
|
||||
break;
|
||||
|
||||
case WIREFRAME:
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
shader_use(diffuseShader);
|
||||
staticactor_draw_models(diffuseShader);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//// skybox
|
||||
// draw skybox as last
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
// skybox->Draw(mcamera);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (debugDrawPhysics) {
|
||||
// Render physics world
|
||||
//dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
// Draw outline
|
||||
if (selectedobject != NULL) {
|
||||
// Draw the selected object outlined
|
||||
glClearStencil(0);
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
glDepthMask(false);
|
||||
glColorMask(false, false, false, false);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||
glStencilMask(0xFF);
|
||||
shader_use(diffuseShader);
|
||||
setup_model_transform(&selectedobject->transform,
|
||||
diffuseShader, 1.f);
|
||||
//selectedobject->draw(diffuseShader);
|
||||
|
||||
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
|
||||
glDepthMask(true);
|
||||
glColorMask(true, true, true, true);
|
||||
glStencilMask(0x00);
|
||||
shader_use(outlineShader);
|
||||
setup_model_transform(&selectedobject->transform,
|
||||
outlineShader, 1.f);
|
||||
//selectedobject->draw(outlineShader);
|
||||
|
||||
|
||||
}
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
glStencilMask(0xFF);
|
||||
glStencilFunc(GL_ALWAYS, 0, 0xFF);
|
||||
|
||||
}
|
||||
|
||||
////// TEXT && GUI
|
||||
// glCullFace(GL_FRONT);
|
||||
glDepthFunc(GL_ALWAYS);
|
||||
shader_use(textShader);
|
||||
shader_setmat4(textShader, "projection", window->projection);
|
||||
mfloat_t fontpos[2] = { 25.f, 25.f };
|
||||
mfloat_t fontcolor[3] = { 0.5f, 0.8f, 0.2f };
|
||||
renderText(stdFont, textShader, "Sample text", fontpos, 0.4f,
|
||||
fontcolor, -1.f);
|
||||
|
||||
sprite_draw(tsprite);
|
||||
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
|
||||
////// Render grid
|
||||
if (showGrid) {
|
||||
glDisable(GL_CULL_FACE);
|
||||
shader_use(debugGridShader);
|
||||
mfloat_t gmodel[16] = { 0.f };
|
||||
mfloat_t gridscale[3] = { 0.f };
|
||||
vec3(gridscale, gridScale, gridScale, gridScale);
|
||||
mat4_multiply_f(gmodel, gmodel, gridScale);
|
||||
// TODO: Hook into here to make the grid scalable
|
||||
shader_setmat4(debugGridShader, "model", gmodel);
|
||||
shader_setvec3(debugGridShader, "smallColor", gridSmallColor);
|
||||
shader_setvec3(debugGridShader, "bigColor", gridBigColor);
|
||||
shader_setfloat(debugGridShader, "gridScale", gridScale);
|
||||
shader_setfloat(debugGridShader, "smallUnit", smallGridUnit);
|
||||
shader_setfloat(debugGridShader, "bigUnit", bigGridUnit);
|
||||
shader_setfloat(debugGridShader, "smallThickness",
|
||||
gridSmallThickness);
|
||||
shader_setfloat(debugGridShader, "largeThickness",
|
||||
gridBigThickness);
|
||||
shader_setfloat(debugGridShader, "opacity", gridOpacity);
|
||||
glBindVertexArray(gridVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
///// Render gizmos
|
||||
// These are things that are overlaid on everything else
|
||||
|
||||
|
||||
// glBindFramebuffer(GL_FRAMEBUFFER, 0); // back to default
|
||||
// glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
// glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// postShader.use();
|
||||
// glBindVertexArray(quadVAO);
|
||||
// glBindTexture(GL_TEXTURE_2D, fboTexture);
|
||||
// glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
void BindUniformBlock(GLuint shaderID, const char *bufferName,
|
||||
GLuint bufferBind)
|
||||
{
|
||||
glUniformBlockBinding(shaderID,
|
||||
glGetUniformBlockIndex(shaderID, bufferName),
|
||||
bufferBind);
|
||||
}
|
54
source/engine/openglrender.h
Normal file
54
source/engine/openglrender.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef OPENGL_RENDER_H
|
||||
#define OPENGL_RENDER_H
|
||||
|
||||
#include "render.h"
|
||||
|
||||
struct mCamera;
|
||||
struct mSDLWindow;
|
||||
|
||||
extern struct mShader *spriteShader;
|
||||
extern struct mShader *animSpriteShader;
|
||||
|
||||
extern struct mSprite *tsprite;
|
||||
|
||||
extern int renderMode;
|
||||
|
||||
|
||||
extern float editorClose;
|
||||
extern float editorFar;
|
||||
extern float gridScale;
|
||||
extern float smallGridUnit;
|
||||
extern float bigGridUnit;
|
||||
extern float gridSmallThickness;
|
||||
extern float gridBigThickness;
|
||||
extern float gridBigColor[];
|
||||
extern float gridSmallColor[];
|
||||
extern float gridOpacity;
|
||||
extern float editorFOV;
|
||||
extern float shadowLookahead;
|
||||
extern float plane_size;
|
||||
extern float near_plane;
|
||||
extern float far_plane;
|
||||
extern char objectName[];
|
||||
extern uint16_t debugColorPickBO;
|
||||
|
||||
extern struct mGameObject *selectedobject;
|
||||
|
||||
enum RenderMode {
|
||||
LIT,
|
||||
UNLIT,
|
||||
WIREFRAME,
|
||||
DIRSHADOWMAP,
|
||||
OBJECTPICKER
|
||||
};
|
||||
|
||||
void openglInit();
|
||||
void openglRender(struct mCamera *camera);
|
||||
|
||||
void openglInit3d(struct mSDLWindow *window);
|
||||
void openglRender3d(struct mSDLWindow *window, struct mCamera *camera);
|
||||
|
||||
void BindUniformBlock(GLuint shaderID, const char *bufferName,
|
||||
GLuint bufferBind);
|
||||
|
||||
#endif
|
25
source/engine/pinball.c
Normal file
25
source/engine/pinball.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "pinball.h"
|
||||
#include "gameobject.h"
|
||||
#include "input.h"
|
||||
|
||||
struct flipper *pinball_flipper_make(struct mGameObject *go)
|
||||
{
|
||||
struct flipper *new = calloc(1, sizeof(struct flipper));
|
||||
pinball_flipper_init(new, go);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
void pinball_flipper_init(struct flipper *flip, struct mGameObject *go)
|
||||
{
|
||||
cpBodySetAngle(go->body, flip->angle1);
|
||||
}
|
||||
|
||||
void pinball_flipper_update(struct flipper *flip, struct mGameObject *go)
|
||||
{
|
||||
if ((flip->left && currentKeystates[SDL_SCANCODE_LSHIFT])
|
||||
|| currentKeystates[SDL_SCANCODE_RSHIFT]) {
|
||||
cpBodySetAngle(go->body, flip->angle2);
|
||||
} else
|
||||
cpBodySetAngle(go->body, flip->angle1);
|
||||
}
|
18
source/engine/pinball.h
Normal file
18
source/engine/pinball.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef PINBALL_H
|
||||
#define PINBALL_H
|
||||
|
||||
struct mGameObject;
|
||||
|
||||
struct flipper {
|
||||
float angle1;
|
||||
float angle2;
|
||||
float flipspeed;
|
||||
int left;
|
||||
};
|
||||
|
||||
struct flipper *pinball_flipper_make(struct mGameObject *go);
|
||||
void pinball_flipper_init(struct flipper *flip, struct mGameObject *go);
|
||||
void pinball_flipper_update(struct flipper *flip, struct mGameObject *go);
|
||||
|
||||
|
||||
#endif
|
53
source/engine/registry.c
Normal file
53
source/engine/registry.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "registry.h"
|
||||
#include "gameobject.h"
|
||||
#include "2dphysics.h"
|
||||
#include "editor.h"
|
||||
#include "sprite.h"
|
||||
#include "pinball.h"
|
||||
|
||||
struct component components[MAXNAME] = { 0 };
|
||||
|
||||
int ncomponent = 0;
|
||||
|
||||
void registry_init()
|
||||
{
|
||||
register_component("Sprite", sizeof(struct mSprite), &MakeSprite, NULL,
|
||||
sprite_gui, &sprite_init, NULL);
|
||||
register_component("2D Circle Collider", sizeof(struct phys2d_circle),
|
||||
&Make2DCircle, &phys2d_dbgdrawcircle, &circle_gui,
|
||||
&phys2d_circleinit, NULL);
|
||||
register_component("2D Segment", sizeof(struct phys2d_segment),
|
||||
&Make2DSegment, &phys2d_dbgdrawseg, &segment_gui,
|
||||
&phys2d_seginit, NULL);
|
||||
register_component("2D Box", sizeof(struct phys2d_box), &Make2DBox,
|
||||
&phys2d_dbgdrawbox, &box_gui, &phys2d_boxinit,
|
||||
NULL);
|
||||
register_component("2D Polygon", sizeof(struct phys2d_poly),
|
||||
&Make2DPoly, &phys2d_dbgdrawpoly, &poly_gui,
|
||||
&phys2d_polyinit, NULL);
|
||||
register_component("2D Edge", sizeof(struct phys2d_edge), &Make2DEdge,
|
||||
&phys2d_dbgdrawedge, &edge_gui, &phys2d_edgeinit,
|
||||
NULL);
|
||||
register_component("Flipper", sizeof(struct flipper),
|
||||
&pinball_flipper_make, NULL, &pinball_flipper_gui,
|
||||
&pinball_flipper_init, &pinball_flipper_update);
|
||||
}
|
||||
|
||||
void register_component(const char *name, size_t size,
|
||||
void (*make)(struct mGameObject * go,
|
||||
struct component * c),
|
||||
void(*draw_debug)(void *data),
|
||||
void(*draw_gui)(void *data),
|
||||
void(*init)(void *data, struct mGameObject * go),
|
||||
void(*update)(void *data, struct mGameObject * go))
|
||||
{
|
||||
struct component *c = &components[ncomponent++];
|
||||
c->name = name;
|
||||
c->make = make;
|
||||
c->draw_debug = draw_debug;
|
||||
c->draw_gui = draw_gui;
|
||||
c->init = init;
|
||||
c->data = NULL;
|
||||
c->id = ncomponent - 1;
|
||||
c->datasize = size;
|
||||
}
|
35
source/engine/registry.h
Normal file
35
source/engine/registry.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef REGISTRY_H
|
||||
#define REGISTRY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "config.h"
|
||||
|
||||
struct mGameObject;
|
||||
|
||||
struct component {
|
||||
const char *name;
|
||||
void *(*make)(struct mGameObject * go);
|
||||
void *data;
|
||||
struct mGameObject *go;
|
||||
void (*draw_debug)(void *data);
|
||||
void (*draw_gui)(void *data);
|
||||
void (*update)(void *data, struct mGameObject * go);
|
||||
int id;
|
||||
int datasize;
|
||||
void (*init)(void *data, struct mGameObject * go);
|
||||
};
|
||||
|
||||
extern struct component components[MAXNAME];
|
||||
extern int ncomponent;
|
||||
|
||||
void registry_init();
|
||||
void register_component(const char *name, size_t size,
|
||||
void (*make)(struct mGameObject * go,
|
||||
struct component * c),
|
||||
void(*draw_debug)(void *data),
|
||||
void(*draw_gui)(void *data),
|
||||
void(*init)(void *data, struct mGameObject * go),
|
||||
void(*update)(void *data,
|
||||
struct mGameObject * go));
|
||||
|
||||
#endif
|
0
source/engine/render.c
Normal file
0
source/engine/render.c
Normal file
9
source/engine/render.h
Normal file
9
source/engine/render.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef RENDER_H
|
||||
#define RENDER_H
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/glew.h>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
|
||||
#endif
|
112
source/engine/resources.c
Normal file
112
source/engine/resources.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "resources.h"
|
||||
|
||||
#include "config.h"
|
||||
#include <dirent.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "vec.h"
|
||||
#include <ftw.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
char *DATA_PATH = NULL;
|
||||
char *PREF_PATH = NULL;
|
||||
|
||||
struct vec *prefabs = NULL;
|
||||
|
||||
const char *EXT_PREFAB = ".prefab";
|
||||
const char *EXT_LEVEL = ".level";
|
||||
int stemlen = 0;
|
||||
|
||||
static const char *cur_ext = NULL;
|
||||
static DIR *cur_dir = NULL;
|
||||
struct dirent *c_dirent = NULL;
|
||||
struct vec *c_vec = NULL;
|
||||
|
||||
char pathbuf[MAXPATH];
|
||||
|
||||
|
||||
void resources_init()
|
||||
{
|
||||
char *dpath = SDL_GetBasePath();
|
||||
DATA_PATH = malloc(strlen(dpath) + 1);
|
||||
strcpy(DATA_PATH, dpath);
|
||||
|
||||
char *ppath = SDL_GetPrefPath("Odplot", "Test Game");
|
||||
PREF_PATH = malloc(strlen(ppath) + 1);
|
||||
strcpy(PREF_PATH, ppath);
|
||||
}
|
||||
|
||||
char *get_filename_from_path(char *path, int extension)
|
||||
{
|
||||
char *dirpos = strrchr(path, '/');
|
||||
if (!dirpos)
|
||||
dirpos = path;
|
||||
|
||||
char *end = strrchr(path, '\0');
|
||||
|
||||
int offset = 0;
|
||||
if (!extension) {
|
||||
char *ext = strrchr(path, '.');
|
||||
offset = end - ext;
|
||||
printf("Making without extension ...\n");
|
||||
}
|
||||
|
||||
char *filename =
|
||||
(char *) malloc(sizeof(char) * (end - dirpos - offset + 1));
|
||||
strncpy(filename, dirpos, end - dirpos - offset);
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *get_directory_from_path(char *path)
|
||||
{
|
||||
const char *dirpos = strrchr(path, '/');
|
||||
char *directory = (char *) malloc(sizeof(char) * (dirpos - path + 1));
|
||||
strncpy(directory, path, dirpos - path);
|
||||
return directory;
|
||||
}
|
||||
|
||||
FILE *res_open(char *path, const char *tag)
|
||||
{
|
||||
strncpy(pathbuf, DATA_PATH, MAXPATH);
|
||||
strncat(pathbuf, path, MAXPATH);
|
||||
FILE *f = fopen(pathbuf, tag);
|
||||
return f;
|
||||
}
|
||||
|
||||
static int ext_check(const char *path, const struct stat *sb, int typeflag,
|
||||
struct FTW *ftwbuf)
|
||||
{
|
||||
if (typeflag == FTW_F) {
|
||||
const char *ext = strrchr(path, '.');
|
||||
if (ext != NULL && !strcmp(ext, cur_ext))
|
||||
vec_add(c_vec, path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fill_extensions(struct vec *vec, char *path, const char *ext)
|
||||
{
|
||||
c_vec = vec;
|
||||
cur_ext = ext;
|
||||
vec_clear(c_vec);
|
||||
nftw(path, &ext_check, 10, 0);
|
||||
}
|
||||
|
||||
void findPrefabs()
|
||||
{
|
||||
fill_extensions(prefabs, DATA_PATH, EXT_PREFAB);
|
||||
}
|
||||
|
||||
FILE *path_open(const char *fmt, const char *tag, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(pathbuf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
FILE *f = fopen(pathbuf, tag);
|
||||
return f;
|
||||
}
|
27
source/engine/resources.h
Normal file
27
source/engine/resources.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef RESOURCES_H
|
||||
#define RESOURCES_H
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct vec;
|
||||
|
||||
extern char *DATA_PATH;
|
||||
extern char *PREF_PATH;
|
||||
|
||||
extern const char *EXT_PREFAB;
|
||||
extern const char *EXT_LEVEL;
|
||||
extern int stemlen;
|
||||
|
||||
void resources_init();
|
||||
|
||||
extern struct vec *prefabs;
|
||||
void findPrefabs();
|
||||
void fill_extensions(struct vec *vec, char *path, const char *ext);
|
||||
char *get_filename_from_path(char *path, int extension);
|
||||
char *get_directory_from_path(char *path);
|
||||
FILE *res_open(char *path, const char *tag);
|
||||
FILE *path_open(const char *fmt, const char *tag, ...);
|
||||
|
||||
#endif
|
54
source/engine/script.c
Normal file
54
source/engine/script.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "script.h"
|
||||
|
||||
#include "gameobject.h"
|
||||
#include <s7.h>
|
||||
|
||||
s7_scheme *s7 = NULL;
|
||||
|
||||
s7_pointer s7square(s7_scheme * sc, s7_pointer args)
|
||||
{
|
||||
if (s7_is_integer(s7_car(args)))
|
||||
return (s7_make_integer
|
||||
(sc, s7_integer(s7_car(args)) * s7_integer(s7_car(args))));
|
||||
|
||||
return (s7_wrong_type_arg_error
|
||||
(sc, "square", 1, s7_car(args), "an integer"));
|
||||
}
|
||||
|
||||
s7_pointer s7move(s7_scheme * sc, s7_pointer args)
|
||||
{
|
||||
if (s7_is_number(s7_car(args)) && s7_is_number(s7_cadr(args))) {
|
||||
gameobject_move(updateGO, s7_real(s7_car(args)),
|
||||
s7_real(s7_cadr(args)));
|
||||
return args;
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
s7_pointer s7rotate(s7_scheme * sc, s7_pointer args)
|
||||
{
|
||||
if (s7_is_number(s7_car(args))) {
|
||||
gameobject_rotate(updateGO, s7_real(s7_car(args)));
|
||||
return (s7_make_real(sc, cpBodyGetAngle(updateGO->body)));
|
||||
}
|
||||
|
||||
return (s7_wrong_type_arg_error
|
||||
(sc, "rotate", 1, s7_car(args), "a number"));
|
||||
}
|
||||
|
||||
void script_init()
|
||||
{
|
||||
s7 = s7_init();
|
||||
s7_define_function(s7, "square", s7square, 1, 0, 0,
|
||||
"(square int) squares int");
|
||||
s7_define_function(s7, "move", s7move, 1, 0, 0,
|
||||
"(move (xs ys)) moves at xs and ys pixels per second");
|
||||
s7_define_function(s7, "rotate", s7rotate, 1, 0, 0,
|
||||
"(rotate ms) rotates at ms meters per second");
|
||||
}
|
||||
|
||||
void script_run(const char *script)
|
||||
{
|
||||
s7_eval_c_string(s7, script);
|
||||
}
|
10
source/engine/script.h
Normal file
10
source/engine/script.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef SCRIPT_H
|
||||
#define SCRIPT_H
|
||||
|
||||
struct s7_scheme;
|
||||
extern struct s7_scheme *s7;
|
||||
|
||||
void script_init();
|
||||
void script_run(const char *script);
|
||||
|
||||
#endif
|
176
source/engine/shader.c
Normal file
176
source/engine/shader.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
#include "shader.h"
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
#include "resources.h"
|
||||
#include <GL/glew.h>
|
||||
|
||||
#define SHADER_BUF 10000
|
||||
|
||||
struct mShader *mshaders[255];
|
||||
struct mShader **lastShader = mshaders;
|
||||
|
||||
struct mShader *MakeShader(const char *vertpath, const char *fragpath)
|
||||
{
|
||||
struct mShader init = { 0, vertpath, fragpath };
|
||||
struct mShader *newshader =
|
||||
(struct mShader *) malloc(sizeof(struct mShader));
|
||||
memcpy(newshader, &init, sizeof(*newshader));
|
||||
*lastShader++ = newshader;
|
||||
shader_compile(newshader);
|
||||
return newshader;
|
||||
}
|
||||
|
||||
int shader_compile_error(GLuint shader)
|
||||
{
|
||||
GLint success = 0;
|
||||
GLchar infoLog[ERROR_BUFFER] = { '\0' };
|
||||
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (success) return 0;
|
||||
|
||||
glGetShaderInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR, "Shader compilation error.\nLog: %s", infoLog);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shader_link_error(GLuint shader)
|
||||
{
|
||||
GLint success = 0;
|
||||
GLchar infoLog[ERROR_BUFFER] = { '\0' };
|
||||
|
||||
glGetProgramiv(shader, GL_LINK_STATUS, &success);
|
||||
if (success) return 0;
|
||||
|
||||
glGetProgramInfoLog(shader, ERROR_BUFFER, NULL, infoLog);
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR, "Shader link error.\nLog: %s", infoLog);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
GLuint load_shader_from_file(char *path, int type)
|
||||
{
|
||||
char spath[MAXPATH] = {'\0'};
|
||||
|
||||
sprintf(spath, "%s%s%s", DATA_PATH, "shaders/", path);
|
||||
FILE *f = fopen(spath, "r'");
|
||||
if (!path)
|
||||
perror(spath), exit(1);
|
||||
|
||||
char buf[SHADER_BUF] = {'\0'};
|
||||
long int fsize;
|
||||
fseek(f, 0, SEEK_END);
|
||||
fsize = ftell(f);
|
||||
rewind(f);
|
||||
fread(buf, fsize, 1, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
|
||||
GLuint id = glCreateShader(type);
|
||||
const char *code = buf;
|
||||
glShaderSource(id, 1, &code, NULL);
|
||||
glCompileShader(id);
|
||||
if ( shader_compile_error(id))
|
||||
return 0;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void shader_compile(struct mShader *shader)
|
||||
{
|
||||
GLuint vert = load_shader_from_file(shader->vertpath, GL_VERTEX_SHADER);
|
||||
GLuint frag = load_shader_from_file(shader->fragpath, GL_FRAGMENT_SHADER);
|
||||
|
||||
shader->id = glCreateProgram();
|
||||
glAttachShader(shader->id, vert);
|
||||
glAttachShader(shader->id, frag);
|
||||
glLinkProgram(shader->id);
|
||||
shader_link_error(shader->id);
|
||||
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
}
|
||||
|
||||
void shader_use(struct mShader *shader)
|
||||
{
|
||||
glUseProgram(shader->id);
|
||||
}
|
||||
|
||||
void shader_setbool(struct mShader *shader, const char *name, int val)
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(shader->id, name), val);
|
||||
}
|
||||
|
||||
void shader_setint(struct mShader *shader, const char *name, int val)
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(shader->id, name), val);
|
||||
}
|
||||
|
||||
void shader_setfloat(struct mShader *shader, const char *name, float val)
|
||||
{
|
||||
glUniform1f(glGetUniformLocation(shader->id, name), val);
|
||||
}
|
||||
|
||||
void shader_setvec2(struct mShader *shader, const char *name,
|
||||
mfloat_t val[2])
|
||||
{
|
||||
glUniform2fv(glGetUniformLocation(shader->id, name), 1, val);
|
||||
}
|
||||
|
||||
void shader_setvec3(struct mShader *shader, const char *name,
|
||||
mfloat_t val[3])
|
||||
{
|
||||
glUniform3fv(glGetUniformLocation(shader->id, name), 1, val);
|
||||
}
|
||||
|
||||
void shader_setvec4(struct mShader *shader, const char *name,
|
||||
mfloat_t val[4])
|
||||
{
|
||||
glUniform4fv(glGetUniformLocation(shader->id, name), 1, val);
|
||||
}
|
||||
|
||||
void shader_setmat2(struct mShader *shader, const char *name,
|
||||
mfloat_t val[4])
|
||||
{
|
||||
glUniformMatrix2fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE,
|
||||
val);
|
||||
}
|
||||
|
||||
void shader_setmat3(struct mShader *shader, const char *name,
|
||||
mfloat_t val[9])
|
||||
{
|
||||
glUniformMatrix3fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE,
|
||||
val);
|
||||
}
|
||||
|
||||
void shader_setmat4(struct mShader *shader, const char *name,
|
||||
mfloat_t val[16])
|
||||
{
|
||||
shader_use(shader);
|
||||
glUniformMatrix4fv(glGetUniformLocation(shader->id, name), 1, GL_FALSE,
|
||||
val);
|
||||
}
|
||||
|
||||
void shader_setUBO(struct mShader *shader, const char *name,
|
||||
unsigned int index)
|
||||
{
|
||||
glUniformBlockBinding(shader->id,
|
||||
glGetUniformBlockIndex(shader->id, name), index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void shader_compile_all()
|
||||
{
|
||||
struct mShader **curshader = mshaders;
|
||||
do {
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Compiled Shader %d", 1);
|
||||
shader_compile(*curshader);
|
||||
} while (++curshader != lastShader);
|
||||
|
||||
}
|
37
source/engine/shader.h
Normal file
37
source/engine/shader.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef SHADER_H
|
||||
#define SHADER_H
|
||||
|
||||
#include "mathc.h"
|
||||
|
||||
struct mShader {
|
||||
unsigned int id;
|
||||
const char *vertpath;
|
||||
const char *fragpath;
|
||||
};
|
||||
|
||||
void shader_compile_all();
|
||||
struct mShader *MakeShader(const char *vertpath, const char *fragpath);
|
||||
void shader_compile(struct mShader *shader);
|
||||
void shader_use(struct mShader *shader);
|
||||
|
||||
void shader_setbool(struct mShader *shader, const char *name, int val);
|
||||
void shader_setint(struct mShader *shader, const char *name, int val);
|
||||
void shader_setfloat(struct mShader *shader, const char *name, float val);
|
||||
|
||||
void shader_setvec2(struct mShader *shader, const char *name,
|
||||
mfloat_t val[2]);
|
||||
void shader_setvec3(struct mShader *shader, const char *name,
|
||||
mfloat_t val[3]);
|
||||
void shader_setvec4(struct mShader *shader, const char *name,
|
||||
mfloat_t val[4]);
|
||||
void shader_setmat2(struct mShader *shader, const char *name,
|
||||
mfloat_t val[4]);
|
||||
void shader_setmat3(struct mShader *shader, const char *name,
|
||||
mfloat_t val[9]);
|
||||
void shader_setmat4(struct mShader *shader, const char *name,
|
||||
mfloat_t val[16]);
|
||||
|
||||
void shader_setUBO(struct mShader *shader, const char *name,
|
||||
unsigned int index);
|
||||
|
||||
#endif
|
123
source/engine/skybox.c
Normal file
123
source/engine/skybox.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include "skybox.h"
|
||||
|
||||
#include "shader.h"
|
||||
#include "camera.h"
|
||||
#include <SDL_image.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "openglrender.h"
|
||||
|
||||
static const float skyboxVertices[216] = {
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, -1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
1.0f, 1.0f, -1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f,
|
||||
-1.0f, 1.0f, 1.0f,
|
||||
-1.0f, 1.0f, -1.0f,
|
||||
|
||||
-1.0f, -1.0f, -1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
1.0f, -1.0f, -1.0f,
|
||||
-1.0f, -1.0f, 1.0f,
|
||||
1.0f, -1.0f, 1.0f
|
||||
};
|
||||
|
||||
struct mSkybox *MakeSkybox(const char *cubemap)
|
||||
{
|
||||
struct mSkybox *newskybox =
|
||||
(struct mSkybox *) malloc(sizeof(struct mSkybox));
|
||||
|
||||
newskybox->shader = MakeShader("skyvert.glsl", "skyfrag.glsl");
|
||||
shader_compile(newskybox->shader);
|
||||
|
||||
glGenVertexArrays(1, &newskybox->VAO);
|
||||
glGenBuffers(1, &newskybox->VBO);
|
||||
glBindVertexArray(newskybox->VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, newskybox->VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices,
|
||||
GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
|
||||
(void *) 0);
|
||||
|
||||
shader_use(newskybox->shader);
|
||||
shader_setint(newskybox->shader, "skybox", 0);
|
||||
|
||||
const char *faces[6] =
|
||||
{ "right.jpg", "left.jpg", "top.jpg", "bottom.jpg", "front.jpg",
|
||||
"back.jpg"
|
||||
};
|
||||
|
||||
glGenTextures(1, &newskybox->id);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, newskybox->id);
|
||||
char buf[100] = { '\0' };
|
||||
|
||||
for (unsigned int i = 0; i < 6; i++) {
|
||||
buf[0] = '\0';
|
||||
strcat(buf, cubemap);
|
||||
strcat(buf, "/");
|
||||
strcat(buf, faces[i]);
|
||||
SDL_Surface *data = NULL; //IMG_Load(buf);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 2048,
|
||||
2048, 0, GL_RGB, GL_UNSIGNED_BYTE, data->pixels);
|
||||
SDL_FreeSurface(data);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
|
||||
|
||||
return newskybox;
|
||||
}
|
||||
|
||||
void skybox_draw(const struct mSkybox *skybox,
|
||||
const struct mCamera *camera)
|
||||
{
|
||||
shader_use(skybox->shader);
|
||||
|
||||
mfloat_t view[16] = { 0.f };
|
||||
getviewmatrix(view, camera);
|
||||
shader_setmat4(skybox->shader, "skyview", view);
|
||||
|
||||
// skybox cube
|
||||
glBindVertexArray(skybox->VAO);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox->id);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||
glBindVertexArray(0);
|
||||
}
|
17
source/engine/skybox.h
Normal file
17
source/engine/skybox.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef SKYBOX_H
|
||||
#define SKYBOX_H
|
||||
|
||||
struct mCamera;
|
||||
|
||||
struct mSkybox {
|
||||
unsigned int VAO;
|
||||
unsigned int VBO;
|
||||
unsigned int id;
|
||||
struct mShader *shader;
|
||||
};
|
||||
|
||||
struct mSkybox *MakeSkybox(const char *cubemap);
|
||||
void skybox_draw(const struct mSkybox *skybox,
|
||||
const struct mCamera *camera);
|
||||
|
||||
#endif
|
206
source/engine/sprite.c
Normal file
206
source/engine/sprite.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
#include "sprite.h"
|
||||
|
||||
|
||||
#include "render.h"
|
||||
#include "openglrender.h"
|
||||
#include "texture.h"
|
||||
#include "shader.h"
|
||||
#include "datastream.h"
|
||||
#include "gameobject.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
static struct mShader *spriteShader = NULL;
|
||||
|
||||
static struct mShader *animSpriteShader = NULL;
|
||||
*/
|
||||
|
||||
struct TextureOptions TEX_SPRITE = { 1, 0 };
|
||||
|
||||
struct mSprite *sprites[100] = { NULL };
|
||||
|
||||
int numSprites = 0;
|
||||
|
||||
static uint32_t quadVAO;
|
||||
static uint32_t VBO;
|
||||
|
||||
struct mSprite *MakeSprite(struct mGameObject *go)
|
||||
{
|
||||
struct mSprite *sprite = malloc(sizeof(struct mSprite));
|
||||
sprites[numSprites++] = sprite;
|
||||
sprite->color[0] = 1.f;
|
||||
sprite->color[1] = 1.f;
|
||||
sprite->color[2] = 1.f;
|
||||
sprite->pos[0] = 0.f;
|
||||
sprite->pos[1] = 0.f;
|
||||
sprite->size[0] = 1.f;
|
||||
sprite->size[1] = 1.f;
|
||||
sprite->tex = NULL;
|
||||
sprite_init(sprite, go);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
void sprite_init(struct mSprite *sprite, struct mGameObject *go)
|
||||
{
|
||||
sprite->go = go;
|
||||
}
|
||||
|
||||
void sprite_loadtex(struct mSprite *sprite, const char *path)
|
||||
{
|
||||
sprite->tex = texture_loadfromfile(sprite->tex, path);
|
||||
}
|
||||
|
||||
void sprite_loadanim(struct mSprite *sprite, const char *path,
|
||||
struct Anim2D anim)
|
||||
{
|
||||
sprite->tex = texture_loadfromfile(sprite->tex, path);
|
||||
sprite->anim = anim;
|
||||
sprite->anim.timer =
|
||||
SDL_AddTimer(sprite->anim.ms, incrementAnimFrame, sprite);
|
||||
/*
|
||||
sprite->tex = texture_loadanimfromfile(sprite->tex, path, sprite->anim.frames,
|
||||
sprite->anim.dimensions);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
Uint32 incrementAnimFrame(Uint32 interval, struct mSprite *sprite)
|
||||
{
|
||||
sprite->anim.frame = (sprite->anim.frame + 1) % sprite->anim.frames;
|
||||
return interval;
|
||||
}
|
||||
|
||||
|
||||
// TODO: This should be done once for all sprites
|
||||
void sprite_initialize()
|
||||
{
|
||||
uint32_t VBO;
|
||||
float vertices[] = {
|
||||
// pos
|
||||
0.f, 0.f,
|
||||
1.0f, 0.0f,
|
||||
0.f, 1.f,
|
||||
1.f, 1.f
|
||||
};
|
||||
|
||||
glGenVertexArrays(1, &quadVAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
|
||||
glBindVertexArray(quadVAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices,
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void sprite_draw(struct mSprite *sprite)
|
||||
{
|
||||
if (sprite->tex != NULL) {
|
||||
|
||||
shader_use(spriteShader);
|
||||
|
||||
|
||||
mfloat_t model[16] = { 0.f };
|
||||
mfloat_t r_model[16] = { 0.f };
|
||||
mfloat_t s_model[16] = { 0.f };
|
||||
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
|
||||
memcpy(r_model, UNITMAT4, sizeof(UNITMAT4));
|
||||
memcpy(s_model, UNITMAT4, sizeof(UNITMAT4));
|
||||
|
||||
|
||||
|
||||
mfloat_t t_move[2] = { 0.f };
|
||||
mfloat_t t_scale[2] = { 0.f };
|
||||
|
||||
t_scale[0] =
|
||||
sprite->size[0] * sprite->tex->width * sprite->go->scale;
|
||||
t_scale[1] =
|
||||
sprite->size[1] * sprite->tex->height * sprite->go->scale;
|
||||
|
||||
t_move[0] = sprite->pos[0] * t_scale[0];
|
||||
t_move[1] = sprite->pos[1] * t_scale[1];
|
||||
|
||||
mat4_translate_vec2(model, t_move);
|
||||
mat4_scale_vec2(model, t_scale);
|
||||
mat4_rotation_z(r_model, cpBodyGetAngle(sprite->go->body));
|
||||
|
||||
mat4_multiply(model, r_model, model);
|
||||
|
||||
cpVect pos = cpBodyGetPosition(sprite->go->body);
|
||||
t_move[0] = pos.x;
|
||||
t_move[1] = pos.y;
|
||||
mat4_translate_vec2(model, t_move);
|
||||
|
||||
|
||||
shader_setmat4(spriteShader, "model", model);
|
||||
shader_setvec3(spriteShader, "spriteColor", sprite->color);
|
||||
|
||||
//tex_bind(sprite->tex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, sprite->tex->id);
|
||||
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void spriteanim_draw(struct mSprite *sprite)
|
||||
{
|
||||
shader_use(animSpriteShader);
|
||||
|
||||
mfloat_t model[16] = { 0.f };
|
||||
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
|
||||
|
||||
mat4_translate_vec2(model, sprite->pos);
|
||||
mfloat_t msize[2] =
|
||||
{ sprite->size[0] * sprite->anim.dimensions[0],
|
||||
sprite->size[1] * sprite->anim.dimensions[1] };
|
||||
mat4_scale_vec2(model, msize);
|
||||
|
||||
shader_setmat4(animSpriteShader, "model", model);
|
||||
shader_setvec3(animSpriteShader, "spriteColor", sprite->color);
|
||||
shader_setfloat(animSpriteShader, "frame", sprite->anim.frame);
|
||||
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, sprite->tex->id);
|
||||
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
|
||||
void video_draw(struct datastream *stream, mfloat_t position[2],
|
||||
mfloat_t size[2], float rotate, mfloat_t color[3])
|
||||
{
|
||||
shader_use(spriteShader);
|
||||
|
||||
static mfloat_t model[16];
|
||||
memcpy(model, UNITMAT4, sizeof(UNITMAT4));
|
||||
mat4_translate_vec2(model, position);
|
||||
mat4_scale_vec2(model, size);
|
||||
|
||||
shader_setmat4(spriteShader, "model", model);
|
||||
shader_setvec3(spriteShader, "spriteColor", color);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, stream->texture_y);
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, stream->texture_cb);
|
||||
glActiveTexture(GL_TEXTURE2);
|
||||
glBindTexture(GL_TEXTURE_2D, stream->texture_cr);
|
||||
|
||||
// TODO: video bind VAO
|
||||
//glBindVertexArray(stream->quadVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
}
|
47
source/engine/sprite.h
Normal file
47
source/engine/sprite.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef SPRITE_H
|
||||
#define SPRITE_H
|
||||
|
||||
#include <SDL_timer.h>
|
||||
#include "mathc.h"
|
||||
|
||||
struct datastream;
|
||||
struct mGameObject;
|
||||
|
||||
struct Anim2D {
|
||||
int frames;
|
||||
int frame;
|
||||
int dimensions[2];
|
||||
SDL_TimerID timer;
|
||||
int ms;
|
||||
};
|
||||
|
||||
struct mSprite {
|
||||
struct Texture *tex;
|
||||
mfloat_t pos[2];
|
||||
mfloat_t size[2];
|
||||
float rotation;
|
||||
mfloat_t color[3];
|
||||
|
||||
struct Anim2D anim;
|
||||
struct mGameObject *go;
|
||||
};
|
||||
|
||||
extern struct mSprite *sprites[100];
|
||||
extern int numSprites;
|
||||
|
||||
struct mSprite *MakeSprite(struct mGameObject *go);
|
||||
void sprite_init(struct mSprite *sprite, struct mGameObject *go);
|
||||
void sprite_loadtex(struct mSprite *sprite, const char *path);
|
||||
void sprite_loadanim(struct mSprite *sprite, const char *path,
|
||||
struct Anim2D anim);
|
||||
void sprite_initalize();
|
||||
void sprite_draw(struct mSprite *sprite);
|
||||
void spriteanim_draw(struct mSprite *sprite);
|
||||
void video_draw(struct datastream *ds, mfloat_t pos[2], mfloat_t size[2],
|
||||
float rotate, mfloat_t color[3]);
|
||||
Uint32 incrementAnimFrame(Uint32 interval, struct mSprite *sprite);
|
||||
|
||||
void sprite_draw_all();
|
||||
|
||||
|
||||
#endif
|
77
source/engine/static_actor.c
Normal file
77
source/engine/static_actor.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "static_actor.h"
|
||||
#include "editorstate.h"
|
||||
|
||||
//ADDMAKE(StaticActor);
|
||||
|
||||
static struct mStaticActor *models[100];
|
||||
static int numModels = 0;
|
||||
static struct mStaticActor *shadow_casters[100];
|
||||
static int numShadowCasters = 0;
|
||||
|
||||
struct mStaticActor *curActor = NULL;
|
||||
|
||||
void staticactor_draw_dbg_color_pick(struct mShader *s)
|
||||
{
|
||||
for (int i = 0; i < numModels; i++) {
|
||||
shader_setvec3(s, "PickingColor", models[i]->obj.editor.color);
|
||||
setup_model_transform(&models[i]->obj.transform, s, 1.f);
|
||||
//models[i]->obj.draw(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void staticactor_draw_models(struct mShader *s)
|
||||
{
|
||||
for (int i = 0; i < numModels; i++) {
|
||||
setup_model_transform(&models[i]->obj.transform, s, 1.f);
|
||||
draw_model(models[i]->model, s);
|
||||
}
|
||||
}
|
||||
|
||||
void staticactor_draw_shadowcasters(struct mShader *s)
|
||||
{
|
||||
for (int i = 0; i < numShadowCasters; i++) {
|
||||
setup_model_transform(&shadow_casters[i]->obj.transform, s, 1.f);
|
||||
//models[i]->obj.draw(s);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void StaticActor::serialize(FILE * file)
|
||||
{
|
||||
GameObject::serialize(file);
|
||||
SerializeBool(file, &castShadows);
|
||||
Serializecstr(file, currentModelPath);
|
||||
}
|
||||
|
||||
void StaticActor::deserialize(FILE * file)
|
||||
{
|
||||
GameObject::deserialize(file);
|
||||
DeserializeBool(file, &castShadows);
|
||||
|
||||
Deserializecstr(file, currentModelPath, MAXPATH);
|
||||
curActor = this;
|
||||
set_new_model(currentModelPath);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct mStaticActor *MakeStaticActor(const char *modelPath)
|
||||
{
|
||||
struct mStaticActor *newsa =
|
||||
(struct mStaticActor *) malloc(sizeof(struct mStaticActor));
|
||||
newsa->model = GetExistingModel(modelPath);
|
||||
models[numModels++] = newsa;
|
||||
|
||||
return newsa;
|
||||
}
|
||||
|
||||
/*
|
||||
Serialize *make_staticactor()
|
||||
{
|
||||
StaticActor *nactor = (StaticActor *) malloc(sizeof(StaticActor));
|
||||
|
||||
return nactor;
|
||||
}
|
||||
*/
|
24
source/engine/static_actor.h
Normal file
24
source/engine/static_actor.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef STATIC_ACTOR_H
|
||||
#define STATIC_ACTOR_H
|
||||
|
||||
#include "gameobject.h"
|
||||
#include "model.h"
|
||||
#include "shader.h"
|
||||
|
||||
struct mStaticActor {
|
||||
struct mGameObject obj;
|
||||
struct mModel *model;
|
||||
char *modelPath;
|
||||
char currentModelPath[MAXPATH];
|
||||
bool castShadows;
|
||||
};
|
||||
|
||||
void staticactor_draw_dbg_color_pick(struct mShader *s);
|
||||
void staticactor_draw_models(struct mShader *s);
|
||||
void staticactor_draw_shadowcasters(struct mShader *s);
|
||||
struct mStaticActor *MakeStaticActor();
|
||||
|
||||
|
||||
extern struct mStaticActor *curActor;
|
||||
|
||||
#endif
|
265
source/engine/texture.c
Normal file
265
source/engine/texture.c
Normal file
|
@ -0,0 +1,265 @@
|
|||
#include "texture.h"
|
||||
|
||||
#define STBI_FAILURE_USERMSG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stb_image.h>
|
||||
#include <stb_ds.h>
|
||||
#include <GL/glew.h>
|
||||
#include <SDL_image.h>
|
||||
#include "log.h"
|
||||
|
||||
static struct {
|
||||
char *key;
|
||||
struct Texture *value;
|
||||
} *texhash = NULL;
|
||||
|
||||
|
||||
struct Texture *texture_loadfromfile(struct Texture *tex, const char *path)
|
||||
{
|
||||
int index = shgeti(texhash, path);
|
||||
if (index != -1)
|
||||
return texhash[index].value;
|
||||
|
||||
tex = calloc(1, sizeof(*tex));
|
||||
tex->path = malloc(strlen(path) + 1);
|
||||
strncpy(tex->path, path, strlen(path) + 1);
|
||||
tex->flipy = 0;
|
||||
tex->opts.sprite = 1;
|
||||
tex->opts.gamma = 0;
|
||||
tex->anim.frames = 1;
|
||||
tex->anim.ms = 1;
|
||||
|
||||
glGenTextures(1, &tex->id);
|
||||
uint8_t n;
|
||||
stbi_set_flip_vertically_on_load(0);
|
||||
tex->data = stbi_load(tex->path, &tex->width, &tex->height, &n, 4);
|
||||
|
||||
if (stbi_failure_reason())
|
||||
YughLog(0, 3, "STBI failed to load file %s with message: %s",
|
||||
tex->path, stbi_failure_reason());
|
||||
|
||||
shput(texhash, tex->path, tex);
|
||||
|
||||
tex_gpu_load(tex);
|
||||
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
void tex_reload(struct Texture *tex)
|
||||
{
|
||||
tex_free(tex);
|
||||
|
||||
tex_gpu_load(tex);
|
||||
}
|
||||
|
||||
void tex_gpu_load(struct Texture *tex)
|
||||
{
|
||||
if (tex->anim.frames >= 0) {
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->width, tex->height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, tex->data);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
if (tex->opts.sprite) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_NEAREST);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
||||
GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
||||
GL_LINEAR);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id);
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
GL_RGBA,
|
||||
tex->anim.dimensions[0],
|
||||
tex->anim.dimensions[1],
|
||||
tex->anim.frames, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
|
||||
SDL_Surface *loadedSurface =
|
||||
SDL_CreateRGBSurfaceFrom(tex->data, tex->width, tex->height,
|
||||
32, (4 * tex->width),
|
||||
0x000000ff, 0x0000ff00, 0x00ff0000,
|
||||
0xff000000);
|
||||
|
||||
SDL_Surface *tempSurface;
|
||||
tempSurface =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, tex->anim.dimensions[0],
|
||||
tex->anim.dimensions[1], 32,
|
||||
SDL_PIXELFORMAT_RGBA32);
|
||||
|
||||
SDL_Rect srcRect;
|
||||
srcRect.x = 0;
|
||||
srcRect.y = 0;
|
||||
srcRect.w = tex->anim.dimensions[0];
|
||||
srcRect.h = tex->anim.dimensions[1];
|
||||
|
||||
for (int i = 0; i < tex->anim.frames; i++) {
|
||||
srcRect.x = i * srcRect.w;
|
||||
SDL_FillRect(tempSurface, NULL, 0x000000);
|
||||
|
||||
TestSDLError(SDL_BlitSurface
|
||||
(loadedSurface, &srcRect, tempSurface, NULL));
|
||||
|
||||
//SDL_UnlockSurface(tempSurface);
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i,
|
||||
tex->anim.dimensions[0],
|
||||
tex->anim.dimensions[1], 1, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, tempSurface->pixels);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
||||
GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER,
|
||||
GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T,
|
||||
GL_CLAMP_TO_EDGE);
|
||||
|
||||
SDL_FreeSurface(loadedSurface);
|
||||
SDL_FreeSurface(tempSurface);
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 tex_incr_anim(Uint32 interval, struct TexAnimation *tex_anim)
|
||||
{
|
||||
anim_incr(tex_anim);
|
||||
|
||||
if (!tex_anim->tex->anim.loop
|
||||
&& tex_anim->frame == tex_anim->tex->anim.frames)
|
||||
anim_pause(tex_anim);
|
||||
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
void anim_incr(struct TexAnimation *anim)
|
||||
{
|
||||
anim->frame = (anim->frame + 1) % anim->tex->anim.frames;
|
||||
tex_anim_calc_uv(anim);
|
||||
}
|
||||
|
||||
void anim_decr(struct TexAnimation *anim)
|
||||
{
|
||||
anim->frame =
|
||||
(anim->frame + anim->tex->anim.frames -
|
||||
1) % anim->tex->anim.frames;
|
||||
tex_anim_calc_uv(anim);
|
||||
}
|
||||
|
||||
void tex_anim_set(struct TexAnimation *anim)
|
||||
{
|
||||
if (anim->playing) {
|
||||
SDL_RemoveTimer(anim->timer);
|
||||
anim->timer =
|
||||
SDL_AddTimer(floor(1000.f / anim->tex->anim.ms), tex_incr_anim,
|
||||
anim);
|
||||
|
||||
}
|
||||
|
||||
tex_anim_calc_uv(anim);
|
||||
}
|
||||
|
||||
void tex_free(struct Texture *tex)
|
||||
{
|
||||
if (tex->id != 0) {
|
||||
glDeleteTextures(1, &tex->id);
|
||||
tex->id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void tex_anim_calc_uv(struct TexAnimation *anim)
|
||||
{
|
||||
struct Rect uv;
|
||||
uv.w = 1.f / anim->tex->anim.frames;
|
||||
uv.h = 1.f;
|
||||
uv.y = 0.f;
|
||||
uv.x = uv.w * (anim->frame);
|
||||
|
||||
anim->uv = uv;
|
||||
}
|
||||
|
||||
unsigned int powof2(unsigned int num)
|
||||
{
|
||||
if (num != 0) {
|
||||
num--;
|
||||
num |= (num >> 1);
|
||||
num |= (num >> 2);
|
||||
num |= (num >> 4);
|
||||
num |= (num >> 8);
|
||||
num |= (num >> 16);
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
int ispow2(int num)
|
||||
{
|
||||
return (num && !(num & (num - 1)));
|
||||
}
|
||||
|
||||
void tex_bind(struct Texture *tex)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id);
|
||||
}
|
||||
|
||||
void anim_play(struct TexAnimation *anim)
|
||||
{
|
||||
if (anim->playing)
|
||||
return;
|
||||
|
||||
if (anim->frame == anim->tex->anim.frames)
|
||||
anim->frame = 0;
|
||||
|
||||
anim->playing = 1;
|
||||
SDL_RemoveTimer(anim->timer);
|
||||
anim->timer =
|
||||
SDL_AddTimer(floor(1000.f / anim->tex->anim.ms), tex_incr_anim,
|
||||
anim);
|
||||
}
|
||||
|
||||
void anim_stop(struct TexAnimation *anim)
|
||||
{
|
||||
if (!anim->playing)
|
||||
return;
|
||||
|
||||
anim->playing = 0;
|
||||
anim->frame = 0;
|
||||
anim->pausetime = 0;
|
||||
SDL_RemoveTimer(anim->timer);
|
||||
tex_anim_calc_uv(anim);
|
||||
}
|
||||
|
||||
void anim_pause(struct TexAnimation *anim)
|
||||
{
|
||||
if (!anim->playing)
|
||||
return;
|
||||
|
||||
anim->playing = 0;
|
||||
SDL_RemoveTimer(anim->timer);
|
||||
}
|
||||
|
||||
void anim_fwd(struct TexAnimation *anim)
|
||||
{
|
||||
anim_incr(anim);
|
||||
}
|
||||
|
||||
void anim_bkwd(struct TexAnimation *anim)
|
||||
{
|
||||
anim_decr(anim);
|
||||
}
|
73
source/engine/texture.h
Normal file
73
source/engine/texture.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef TEXTURE_H
|
||||
#define TEXTURE_H
|
||||
|
||||
#include <SDL_timer.h>
|
||||
|
||||
struct Rect {
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
float h;
|
||||
};
|
||||
|
||||
struct TexAnimation {
|
||||
int frame;
|
||||
int playing;
|
||||
int pausetime;
|
||||
SDL_TimerID timer;
|
||||
struct Rect uv;
|
||||
struct Texture *tex;
|
||||
};
|
||||
|
||||
struct TexAnim {
|
||||
int frames;
|
||||
int dimensions[2];
|
||||
int ms;
|
||||
int loop;
|
||||
};
|
||||
|
||||
struct TextureOptions {
|
||||
int sprite;
|
||||
unsigned int gamma:1;
|
||||
int animation;
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
char *type;
|
||||
unsigned int id;
|
||||
char *path;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
short flipy;
|
||||
unsigned char *data;
|
||||
|
||||
struct TextureOptions opts;
|
||||
struct TexAnim anim;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct Texture *texture_loadfromfile(struct Texture *tex,
|
||||
const char *path);
|
||||
void tex_gpu_load(struct Texture *tex);
|
||||
void tex_reload(struct Texture *tex);
|
||||
void tex_free(struct Texture *tex);
|
||||
void tex_bind(struct Texture *tex);
|
||||
unsigned int powof2(unsigned int num);
|
||||
int ispow2(int num);
|
||||
|
||||
void anim_play(struct TexAnimation *anim);
|
||||
void anim_stop(struct TexAnimation *anim);
|
||||
void anim_pause(struct TexAnimation *anim);
|
||||
void anim_fwd(struct TexAnimation *anim);
|
||||
void anim_bkwd(struct TexAnimation *anim);
|
||||
void anim_incr(struct TexAnimation *anim);
|
||||
void anim_decr(struct TexAnimation *anim);
|
||||
|
||||
Uint32 tex_incr_anim(Uint32 interval, struct TexAnimation *tex_anim);
|
||||
void tex_anim_calc_uv(struct TexAnimation *anim);
|
||||
void tex_anim_set(struct TexAnimation *anim);
|
||||
|
||||
|
||||
#endif
|
226
source/engine/thirdpersonfollow.c
Normal file
226
source/engine/thirdpersonfollow.c
Normal file
|
@ -0,0 +1,226 @@
|
|||
// odplot productions is a trademarked name. Project Yugh is a copyrighted property. This code, however, is free to be copy and extended as you see fit.
|
||||
|
||||
#include "thirdpersonfollow.h"
|
||||
#include <math.h>
|
||||
|
||||
// void ThirdPersonFollow::_ready() {
|
||||
// Target = dynamic_cast<Spatial*>(get_node(TargetPath));
|
||||
// ExternalFrame = dynamic_cast<Spatial*>(get_node(ExternalFramePath));
|
||||
// }
|
||||
|
||||
// void ThirdPersonFollow::_process(float delta_time) {
|
||||
|
||||
// if (Target != nullptr) {
|
||||
// // Get the frame of reference
|
||||
// if (has_node(ExternalFramePath) && get_node(ExternalFramePath) != this)
|
||||
// TFOR = dynamic_cast<Spatial*>(get_node(ExternalFramePath))->get_global_transform();
|
||||
// else
|
||||
// TFOR = Transform(Basis(glm::vec3::RIGHT(), glm::vec3::UP(), glm::vec3::FORWARD()), glm::vec3::ZERO());
|
||||
|
||||
// CalculateTargetOffset();
|
||||
// TargetPosition = CalculatePosition();
|
||||
|
||||
// translate(to_local(FrameBasedVectorLerp(get_global_translation(), TargetPosition, PositionSpeeds, delta_time)));
|
||||
|
||||
// set_rotation_degrees(get_rotation_degrees().linear_interpolate(RotationOffset, RotationSpeed * delta_time));
|
||||
// }
|
||||
|
||||
// // For rotation
|
||||
// // TODO: Add rotation offset in properly
|
||||
// //this->SetActorRotation(FMath::Lerp(this->GetActorRotation(), TargetRotation, RotationSpeed * DeltaTime));
|
||||
// //this->set_rotation(glm::quat(this->get_rotation().slerp(RotationOffset, RotationSpeed * DeltaTime)).get_euler());
|
||||
|
||||
// //set_global_rotation_degrees(get_global_rotation_degrees().linear_interpolate(RotationOffset, RotationSpeed * delta_time));
|
||||
|
||||
// // TODO: Figure out how to translate rotation to a global rotation
|
||||
// }
|
||||
|
||||
mfloat_t *follow_calcpos()
|
||||
{
|
||||
mfloat_t p1[3] = { 0 };
|
||||
mfloat_t p2[3] = { 0 };
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
glm::vec3 ThirdPersonFollow::CalculatePosition()
|
||||
{
|
||||
glm::vec3 p1 = CalculateCenter();
|
||||
|
||||
glm::vec3 p2 =
|
||||
XDirPosts ? GetPostsOffset(TFOR.Right(),
|
||||
FloatWidths.
|
||||
x) : GetExtentsOffset(TFOR.Right(),
|
||||
FloatWidths.x,
|
||||
TargetOffset.x,
|
||||
AnchorWidths.x);
|
||||
glm::vec3 p3 =
|
||||
YDirPosts ? GetPostsOffset(TFOR.Up(),
|
||||
FloatWidths.
|
||||
y) : GetExtentsOffset(TFOR.Up(),
|
||||
FloatWidths.y,
|
||||
TargetOffset.y,
|
||||
AnchorWidths.y);
|
||||
glm::vec3 p4 =
|
||||
ZDirPosts ? GetPostsOffset(TFOR.Back(),
|
||||
FloatWidths.
|
||||
z) : GetExtentsOffset(TFOR.Back(),
|
||||
FloatWidths.z,
|
||||
TargetOffset.z,
|
||||
AnchorWidths.z);
|
||||
|
||||
return p1 + p2 + p3 + p4;
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::CalculateCenter()
|
||||
{
|
||||
return Target->get_global_translation() +
|
||||
TFOR.TransformDirection(Offset) + (mytransform->Back() * Distance);
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::
|
||||
GetPostsOffset(const glm::vec3 & DirectionVector, float AnchorWidth)
|
||||
{
|
||||
float dot = glm::dot(Target->Forward(), DirectionVector);
|
||||
|
||||
return DirectionVector * (dot >= 0 ? AnchorWidth : AnchorWidth * -1);
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::
|
||||
GetExtentsOffset(const glm::vec3 & DirectionVector, float AnchorWidth,
|
||||
float TOffset, float Width)
|
||||
{
|
||||
|
||||
float negated_offset_sign = ((0 <= TOffset) - (TOffset < 0)) * -1.f;
|
||||
float TotalWidth = AnchorWidth + Width;
|
||||
|
||||
if (glm::abs(TOffset) > TotalWidth
|
||||
&& !glm::epsilonEqual(glm::abs(TOffset), TotalWidth, 0.5f))
|
||||
return DirectionVector * TotalWidth * negated_offset_sign;
|
||||
else {
|
||||
if (glm::abs(TOffset) >= AnchorWidth)
|
||||
return DirectionVector * AnchorWidth * negated_offset_sign;
|
||||
else
|
||||
return DirectionVector * TOffset * -1.f;
|
||||
}
|
||||
|
||||
return glm::vec3(0.f);
|
||||
}
|
||||
|
||||
glm::vec3 ThirdPersonFollow::FrameBasedVectorLerp(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds,
|
||||
float Tick)
|
||||
{
|
||||
// Previously "FORTransform.TransformVector(Speeds)
|
||||
glm::vec3 TSpeed = glm::abs(TFOR.TransformDirection(Speeds));
|
||||
glm::vec3 TOffset = glm::abs(TFOR.TransformDirection(TargetOffset));
|
||||
glm::vec3 TAnchorWidths =
|
||||
glm::abs(TFOR.TransformDirection(AnchorWidths));
|
||||
glm::vec3 TFloatWidths =
|
||||
glm::abs(TFOR.TransformDirection(FloatWidths));
|
||||
|
||||
|
||||
|
||||
// If these are true, that means to use the anchor speed instead of the normal speed.
|
||||
// True if the offset is beyond the anchor plus the width
|
||||
bool bUseX = GetLerpParam(TOffset.x, TAnchorWidths.x, TFloatWidths.x);
|
||||
bool bUseY = GetLerpParam(TOffset.y, TAnchorWidths.y, TFloatWidths.y);
|
||||
bool bUseZ = GetLerpParam(TOffset.z, TAnchorWidths.z, TFloatWidths.z);
|
||||
|
||||
|
||||
float xAlpha =
|
||||
glm::clamp((bUseX ? AnchorSpeed : TSpeed.x) * Tick, 0.f, 1.f);
|
||||
float yAlpha =
|
||||
glm::clamp((bUseY ? AnchorSpeed : TSpeed.y) * Tick, 0.f, 1.f);
|
||||
float zAlpha =
|
||||
glm::clamp((bUseZ ? AnchorSpeed : TSpeed.z) * Tick, 0.f, 1.f);
|
||||
|
||||
return VectorLerpPiecewise(From, To,
|
||||
glm::vec3(xAlpha, yAlpha, zAlpha));
|
||||
}
|
||||
|
||||
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e)
|
||||
{
|
||||
return fabs(a - b) < e;
|
||||
}
|
||||
|
||||
int lerpparam(float offset, float anchorwidth, float floatwidth)
|
||||
{
|
||||
return (offset > (anchorwidth + floatwidth)) && !float_epsilon(anchorwidth + floatwidth, offset, 0.5f);
|
||||
}
|
||||
|
||||
mfloat_t *vec3lerp(mfloat_t from[3], mfloat_t to[3], mfloat_t a[3])
|
||||
{
|
||||
from[0] = from[0] + (to[0] - from[0]) * a[0];
|
||||
from[1] = from[1] + (to[1] - from[1]) * a[1];
|
||||
from[2] = from[2] + (to[2] - from[2]) * a[2];
|
||||
}
|
||||
|
||||
void follow_calctargets()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ThirdPersonFollow::CalculateTargets()
|
||||
{
|
||||
// For translation
|
||||
TargetPosition = CalculatePosition();
|
||||
|
||||
|
||||
// For rotation
|
||||
// TODO: Check of this implementation is the same as UKismetMath FindLookAtRotation
|
||||
TargetRotation =
|
||||
RemoveLockedRotation(glm::quat
|
||||
(mytransform->
|
||||
get_global_transform()->get_origin() -
|
||||
Target->
|
||||
get_global_transform()->get_origin()));
|
||||
}
|
||||
|
||||
follow_removelockedrot()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
glm::quat ThirdPersonFollow::
|
||||
RemoveLockedRotation(const glm::quat & CurrentRotation)
|
||||
{
|
||||
glm::vec3 NewRotator;
|
||||
glm::vec3 CurrentRotator = glm::eulerAngles(CurrentRotation);
|
||||
//
|
||||
|
||||
NewRotator.x =
|
||||
LockRoll ? mytransform->get_rotation().x : CurrentRotator.x;
|
||||
NewRotator.y =
|
||||
LockPitch ? mytransform->get_rotation().y : CurrentRotator.y;
|
||||
NewRotator.z =
|
||||
LockYaw ? mytransform->get_rotation().z : CurrentRotator.z;
|
||||
|
||||
return glm::quat(NewRotator);
|
||||
}
|
||||
|
||||
// The target offset is the value of where the target is compared to where he "should" be based on where
|
||||
// the camera is. It is what the camera needs to move to be centered on the target
|
||||
void ThirdPersonFollow::CalculateTargetOffset()
|
||||
{
|
||||
glm::vec3 p1 =
|
||||
(mytransform->Forward() * Distance) +
|
||||
TFOR.TransformDirection(Offset) +
|
||||
mytransform->get_global_translation();
|
||||
glm::vec3 p2 =
|
||||
TFOR.InverseTransformDirection(Target->get_global_translation());
|
||||
glm::vec3 p3 = TFOR.InverseTransformDirection(p1);
|
||||
|
||||
TargetOffset = p2 - p3;
|
||||
}
|
||||
|
||||
void follow_targetoffset()
|
||||
{
|
||||
mfloat_t p1[3], p2[3], p3[3] = {0};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
*/
|
190
source/engine/thirdpersonfollow.h
Normal file
190
source/engine/thirdpersonfollow.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
// odplot productions is a trademarked name. Project Yugh is a copyrighted property. This code, however, is free to be copy and extended as you see fit.
|
||||
|
||||
#ifndef THIRDPERSONFOLLOW_H
|
||||
#define THIRDPERSONFOLLOW_H
|
||||
|
||||
#include "transform.h"
|
||||
|
||||
struct follow {
|
||||
float distance;
|
||||
mfloat_t target_rot[4];
|
||||
};
|
||||
|
||||
mfloat_t *follow_calcpos();
|
||||
mfloat_t *follow_calccenter();
|
||||
mfloat_t *follow_postoffset();
|
||||
mfloat_t *extentsoffset();
|
||||
mfloat_t *framebasedveclerp();
|
||||
int lerpparam(float offset, float anchorwidth, float floatwidth);
|
||||
mfloat_t *vec3lerp(mfloat_t from[3], mfloat_t to[3], mfloat_t a[3]);
|
||||
void follow_calctargets();
|
||||
mfloat_t *follow_removelockedrot();
|
||||
void follow_targetoffset(struct follow *follow);
|
||||
int float_epsilon(mfloat_t a, mfloat_t b, mfloat_t e);
|
||||
|
||||
/*
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// A good camera.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ThirdPersonFollow {
|
||||
|
||||
public:
|
||||
enum CameraType {
|
||||
STATIONARY,
|
||||
TRANSLATING,
|
||||
ROTATING,
|
||||
SPLINE
|
||||
};
|
||||
|
||||
enum CameraTransition {
|
||||
NONE,
|
||||
CROSSDISSOLVE,
|
||||
WIPE,
|
||||
DIP
|
||||
};
|
||||
|
||||
enum FrameOfReference {
|
||||
LOCAL,
|
||||
WORLD,
|
||||
EXTERNAL
|
||||
};
|
||||
|
||||
ThirdPersonFollow() {
|
||||
// Rotation
|
||||
RotationSpeed = 10.0f;
|
||||
LockPitch = LockYaw = LockRoll = true;
|
||||
|
||||
XDirPosts = false;
|
||||
YDirPosts = false;
|
||||
ZDirPosts = false;
|
||||
|
||||
|
||||
// Translation
|
||||
//FloatWidths = AnchorWidths = CenterVector = glm::vec3(0, 0, 0);
|
||||
PositionSpeeds = glm::vec3(2.f, 2.f, 2.f);
|
||||
//TranslationScales = glm::vec3(1, 1, 1);
|
||||
|
||||
// Frame settings
|
||||
Offset = glm::vec3(0.f, 0.f, 0.f);
|
||||
Distance = 10;
|
||||
|
||||
AnchorSpeed = 80;
|
||||
} ~ThirdPersonFollow() {
|
||||
}
|
||||
|
||||
Transform *mytransform;
|
||||
|
||||
// An actor that can be given for the camera to base its movement around
|
||||
// instead of itself. Makes most sense for this to be stationary
|
||||
Transform *ExternalFrame = nullptr;
|
||||
|
||||
|
||||
void SetExternalFrame(Transform * val) {
|
||||
ExternalFrame = val;
|
||||
}
|
||||
|
||||
// The target the camera "looks" at, used for calculations
|
||||
Transform *Target = nullptr;
|
||||
|
||||
void SetTarget(Transform * val) {
|
||||
Target = val;
|
||||
}
|
||||
|
||||
// Offset from the target
|
||||
glm::vec3 Offset;
|
||||
|
||||
// How far away should the camera act from the target
|
||||
float Distance;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Translation variables. In this mode, the camera doesn't rotate to look
|
||||
// at the target, it only moves around the world.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// "Posts" for each direction in 3D space. These are items that the target
|
||||
/// is allowed to move within without the camera following along.
|
||||
bool XDirPosts;
|
||||
bool YDirPosts;
|
||||
bool ZDirPosts;
|
||||
|
||||
/// The range in ecah direction the camera floats. While within this range,
|
||||
/// the camera will smoothly glide to the desired position.
|
||||
glm::vec3 FloatWidths;
|
||||
|
||||
/// The clamp range for each direction. If the camera reaches this range,
|
||||
/// it will stick and not move any further.
|
||||
glm::vec3 AnchorWidths;
|
||||
|
||||
/// When floating to the target, the speed to float.
|
||||
glm::vec3 PositionSpeeds;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Rotation variables. Used for the camera's rotation mode, where it
|
||||
// follows the Target without translating.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Variables to lock its rotation in any of the three directions
|
||||
bool LockRoll;
|
||||
bool LockPitch;
|
||||
bool LockYaw;
|
||||
|
||||
glm::vec3 RotationOffset;
|
||||
|
||||
/// The speed of rotation
|
||||
float RotationSpeed;
|
||||
|
||||
private:
|
||||
void CalculateTargetOffset();
|
||||
|
||||
// Transform of frame of reference
|
||||
Transform TFOR;
|
||||
|
||||
/// The calculated offset based on frames of reference
|
||||
glm::vec3 TargetOffset;
|
||||
|
||||
glm::vec3 TargetPosition;
|
||||
|
||||
glm::quat TargetRotation;
|
||||
|
||||
|
||||
void CalculateTargets();
|
||||
|
||||
// Calculates
|
||||
|
||||
glm::vec3 CalculatePosition();
|
||||
|
||||
glm::vec3 CalculateCenter();
|
||||
|
||||
/// Given a direction and width, find the offsets.
|
||||
glm::vec3 GetPostsOffset(const glm::vec3 & DirectionVector,
|
||||
float AnchorWidth);
|
||||
|
||||
/// Given anchors, what's the anchor width?
|
||||
glm::vec3 GetExtentsOffset(const glm::vec3 & DirectionVector,
|
||||
float AnchorWidth, float TOffset,
|
||||
float Width);
|
||||
|
||||
glm::quat RemoveLockedRotation(const glm::quat & CurrentRotation);
|
||||
|
||||
glm::vec3 FrameBasedVectorLerp(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Speeds, float Tick);
|
||||
|
||||
glm::vec3 VectorLerpPiecewise(const glm::vec3 & From,
|
||||
const glm::vec3 & To,
|
||||
const glm::vec3 & Alpha);
|
||||
|
||||
bool GetLerpParam(const float Offst, const float AnchorWidth,
|
||||
const float FloatWidth);
|
||||
|
||||
/// Set to a value that gives good clamping, smoothly. Activates when
|
||||
/// the target is out of range.
|
||||
float AnchorSpeed;
|
||||
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
#endif
|
44
source/engine/transform.c
Normal file
44
source/engine/transform.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "transform.h"
|
||||
#include <string.h>
|
||||
|
||||
struct mTransform MakeTransform(mfloat_t pos[3], mfloat_t rotation[4],
|
||||
float scale)
|
||||
{
|
||||
struct mTransform newT;
|
||||
memcpy(newT.position, pos, sizeof(*pos));
|
||||
memcpy(newT.rotation, rotation, sizeof(*rotation));
|
||||
newT.scale = scale;
|
||||
return newT;
|
||||
}
|
||||
|
||||
mfloat_t *trans_forward(mfloat_t * res,
|
||||
const struct mTransform *const trans)
|
||||
{
|
||||
// YughLog(0, SDL_LOG_PRIORITY_WARN, "Rotation is %f", trans->rotation[0]);
|
||||
return vec3_rotate_quat(res, FORWARD, trans->rotation);
|
||||
}
|
||||
|
||||
mfloat_t *trans_back(mfloat_t * res, const struct mTransform *trans)
|
||||
{
|
||||
return vec3_rotate_quat(res, BACK, trans->rotation);
|
||||
}
|
||||
|
||||
mfloat_t *trans_up(mfloat_t * res, const struct mTransform *trans)
|
||||
{
|
||||
return vec3_rotate_quat(res, UP, trans->rotation);
|
||||
}
|
||||
|
||||
mfloat_t *trans_down(mfloat_t * res, const struct mTransform *trans)
|
||||
{
|
||||
return vec3_rotate_quat(res, DOWN, trans->rotation);
|
||||
}
|
||||
|
||||
mfloat_t *trans_right(mfloat_t * res, const struct mTransform *trans)
|
||||
{
|
||||
return vec3_rotate_quat(res, RIGHT, trans->rotation);
|
||||
}
|
||||
|
||||
mfloat_t *trans_left(mfloat_t * res, const struct mTransform *trans)
|
||||
{
|
||||
return vec3_rotate_quat(res, LEFT, trans->rotation);
|
||||
}
|
27
source/engine/transform.h
Normal file
27
source/engine/transform.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef TRANSFORM_H
|
||||
#define TRANSFORM_H
|
||||
|
||||
#include "mathc.h"
|
||||
|
||||
struct mTransform {
|
||||
mfloat_t position[3];
|
||||
mfloat_t rotation[4];
|
||||
float scale;
|
||||
};
|
||||
|
||||
|
||||
struct mTransform MakeTransform(mfloat_t pos[3], mfloat_t rotation[3],
|
||||
float scale);
|
||||
|
||||
mfloat_t *trans_forward(mfloat_t * res,
|
||||
const struct mTransform *const trans);
|
||||
mfloat_t *trans_back(mfloat_t * res, const struct mTransform *trans);
|
||||
mfloat_t *trans_up(mfloat_t * res, const struct mTransform *trans);
|
||||
mfloat_t *trans_down(mfloat_t * res, const struct mTransform *trans);
|
||||
mfloat_t *trans_right(mfloat_t * res, const struct mTransform *trans);
|
||||
mfloat_t *trans_left(mfloat_t * res, const struct mTransform *trans);
|
||||
|
||||
|
||||
//extern Serialize *make_transform();
|
||||
|
||||
#endif
|
132
source/engine/vec.c
Normal file
132
source/engine/vec.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include "vec.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
struct vec *vec_make(int width, int size)
|
||||
{
|
||||
struct vec *new = calloc(1, sizeof(struct vec));
|
||||
new->size = size;
|
||||
new->width = width;
|
||||
new->data = calloc(new->size, new->width);
|
||||
return new;
|
||||
}
|
||||
|
||||
void *vec_get(struct vec *vec, int n)
|
||||
{
|
||||
if (n < vec->len)
|
||||
return (char *) vec->data + (n * vec->width);
|
||||
|
||||
YughLog(0, 4,
|
||||
"Attempted to access element %d of a vec with %d elements.", n,
|
||||
vec->len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vec_walk(struct vec *vec, void (*fn)(void *data))
|
||||
{
|
||||
for(int i = 0; i < vec->len; i++)
|
||||
fn((char *) (vec->data + (i * vec->width)));
|
||||
}
|
||||
|
||||
void vec_delete(struct vec *vec, int n)
|
||||
{
|
||||
if (n < vec->len) {
|
||||
vec->len--;
|
||||
memcpy(vec_p(vec, n), vec_p(vec, vec->len), vec->width);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void vec_del_order(struct vec *vec, int n)
|
||||
{
|
||||
if (n < vec->len) {
|
||||
vec->len--;
|
||||
memmove(vec_p(vec, n), vec_p(vec, n + 1),
|
||||
vec->width * (vec->len - n));
|
||||
}
|
||||
}
|
||||
|
||||
void *vec_add(struct vec *vec, void *data)
|
||||
{
|
||||
if (vec->size == vec->len)
|
||||
vec_expand(vec);
|
||||
|
||||
if (data)
|
||||
memcpy(vec_p(vec, vec->len), data, vec->width);
|
||||
else
|
||||
memset(vec_p(vec, vec->len), 0, vec->width);
|
||||
|
||||
vec->len++;
|
||||
return vec_get(vec, vec->len - 1);
|
||||
}
|
||||
|
||||
void *vec_add_sort(struct vec *vec, void *data,
|
||||
int (*sort)(void *a, void *b))
|
||||
{
|
||||
if(vec->size == vec->len)
|
||||
vec_expand(vec);
|
||||
|
||||
int n = vec->len - 1;
|
||||
while (sort(vec_p(vec, n), data))
|
||||
n--;
|
||||
|
||||
vec_insert(vec, data, n);
|
||||
}
|
||||
|
||||
void *vec_insert(struct vec *vec, void *data, int n)
|
||||
{
|
||||
if (vec->size == vec->len)
|
||||
vec_expand(vec);
|
||||
|
||||
memmove(vec_p(vec, n), vec_p(vec, n + 1), vec->width * (vec->len - n));
|
||||
vec->len++;
|
||||
memcpy(vec_p(vec, n), data, vec->width);
|
||||
return vec_get(vec, n);
|
||||
}
|
||||
|
||||
char *vec_p(struct vec *vec, int n)
|
||||
{
|
||||
return ((char *) vec->data + (vec->width * n));
|
||||
}
|
||||
|
||||
void *vec_set(struct vec *vec, int n, void *data)
|
||||
{
|
||||
if (vec->len >= n)
|
||||
return NULL;
|
||||
|
||||
memcpy(vec_p(vec, n), data, vec->width);
|
||||
return vec_get(vec, n);
|
||||
}
|
||||
|
||||
void vec_expand(struct vec *vec)
|
||||
{
|
||||
vec->size *= 2;
|
||||
vec->data = realloc(vec->data, vec->size * vec->width);
|
||||
}
|
||||
|
||||
void vec_store(struct vec *vec, FILE * f)
|
||||
{
|
||||
fwrite(&vec->len, sizeof(vec->len), 1, f);
|
||||
fwrite(&vec->size, sizeof(vec->size), 1, f);
|
||||
fwrite(&vec->width, sizeof(vec->width), 1, f);
|
||||
fwrite(vec->data, vec->width, vec->len, f);
|
||||
}
|
||||
|
||||
void vec_load(struct vec *vec, FILE * f)
|
||||
{
|
||||
fread(&vec->len, sizeof(vec->len), 1, f);
|
||||
fread(&vec->size, sizeof(vec->size), 1, f);
|
||||
fread(&vec->width, sizeof(vec->width), 1, f);
|
||||
fread(vec->data, vec->width, vec->len, f);
|
||||
}
|
||||
|
||||
void vec_clear(struct vec *vec)
|
||||
{
|
||||
vec->len = 0;
|
||||
}
|
||||
|
||||
void vec_fit(struct vec *vec)
|
||||
{
|
||||
vec->size = vec->len;
|
||||
vec->data = realloc(vec->data, vec->size * vec->width);
|
||||
}
|
32
source/engine/vec.h
Normal file
32
source/engine/vec.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef VEC_H
|
||||
#define VEC_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct vec {
|
||||
int len;
|
||||
int size;
|
||||
int width;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct vec *vec_make(int width, int size);
|
||||
void *vec_get(struct vec *vec, int n);
|
||||
void vec_walk(struct vec *vec, void (*fn)(void *data));
|
||||
void vec_clear(struct vec *vec);
|
||||
void *vec_add(struct vec *vec, void *data);
|
||||
|
||||
/* sort returns 0 for a<=b, 1 for a>b */
|
||||
void *vec_add_sort(struct vec *vec, void *data,
|
||||
int (*sort)(void *a, void *b));
|
||||
void *vec_insert(struct vec *vec, void *data, int n);
|
||||
void *vec_set(struct vec *vec, int n, void *data);
|
||||
void vec_delete(struct vec *vec, int n);
|
||||
void vec_del_order(struct vec *vec, int n);
|
||||
void vec_store(struct vec *vec, FILE *f);
|
||||
void vec_load(struct vec *vec, FILE *f);
|
||||
char *vec_p(struct vec *vec, int n);
|
||||
void vec_expand(struct vec *vec);
|
||||
void vec_fit(struct vec *vec);
|
||||
|
||||
#endif
|
157
source/engine/window.c
Normal file
157
source/engine/window.c
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include "window.h"
|
||||
|
||||
#include "openglrender.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "log.h"
|
||||
|
||||
struct mSDLWindow *window = NULL;
|
||||
|
||||
static struct mSDLWindow *windows[5];
|
||||
static int numWindows = 0;
|
||||
|
||||
struct mSDLWindow *MakeSDLWindow(const char *name, int width, int height,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct mSDLWindow *w = calloc(1, sizeof(struct mSDLWindow));
|
||||
w->width = width;
|
||||
w->height = height;
|
||||
w->window = SDL_CreateWindow(name, 0, 0, width, height, flags);
|
||||
|
||||
if (w->window == NULL) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"Window could not be created! SDL Error: %s",
|
||||
SDL_GetError());
|
||||
} else {
|
||||
w->glContext = SDL_GL_CreateContext(w->window);
|
||||
|
||||
if (w->glContext == NULL) {
|
||||
YughLog(0, SDL_LOG_PRIORITY_ERROR,
|
||||
"OpenGL context could not be created! SDL Error: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
w->id = SDL_GetWindowID(w->window);
|
||||
|
||||
glewExperimental = GL_TRUE;
|
||||
glewInit();
|
||||
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
|
||||
if (numWindows < 5)
|
||||
windows[numWindows++] = w;
|
||||
}
|
||||
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
void window_handle_event(struct mSDLWindow *w, SDL_Event * e)
|
||||
{
|
||||
if (e->type == SDL_WINDOWEVENT && e->window.windowID == w->id) { // TODO: Check ptr direct?
|
||||
switch (e->window.event) {
|
||||
case SDL_WINDOWEVENT_SHOWN:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Showed window %d.", w->id);
|
||||
w->shown = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_HIDDEN:
|
||||
w->shown = false;
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Hid window %d.", w->id);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
|
||||
w->width = e->window.data1;
|
||||
w->height = e->window.data2;
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Changed size of window %d: width %d, height %d.",
|
||||
w->id, w->width, w->height);
|
||||
window_makecurrent(w);
|
||||
/*w.projection =
|
||||
glm::ortho(0.f, (float) width, 0.f, (float) height, -1.f,
|
||||
1.f); */
|
||||
w->render = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Exposed window %d.", w->id);
|
||||
w->render = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_ENTER:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Entered window %d.", w->id);
|
||||
w->mouseFocus = true;
|
||||
SDL_RaiseWindow(w->window);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_LEAVE:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Left window %d.", w->id);
|
||||
w->mouseFocus = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Lost focus on window %d.", w->id);
|
||||
w->keyboardFocus = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Gained focus on window %d.", w->id);
|
||||
w->keyboardFocus = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MINIMIZED:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Minimized window %d.", w->id);
|
||||
w->minimized = true;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Maximized window %d.", w->id);
|
||||
w->minimized = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO,
|
||||
"Restored window %d.", w->id);
|
||||
w->minimized = false;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
YughLog(0, SDL_LOG_PRIORITY_INFO, "Closed window %d.", w->id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void window_makefullscreen(struct mSDLWindow *w)
|
||||
{
|
||||
SDL_SetWindowFullscreen(w->window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
w->fullscreen = true;
|
||||
}
|
||||
|
||||
void window_togglefullscreen(struct mSDLWindow *w)
|
||||
{
|
||||
w->fullscreen = !w->fullscreen;
|
||||
|
||||
if (w->fullscreen) {
|
||||
window_makefullscreen(w);
|
||||
} else {
|
||||
SDL_SetWindowFullscreen(w->window, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void window_makecurrent(struct mSDLWindow *w)
|
||||
{
|
||||
if (w->window != SDL_GL_GetCurrentWindow())
|
||||
SDL_GL_MakeCurrent(w->window, w->glContext);
|
||||
glViewport(0, 0, w->width, w->height);
|
||||
}
|
||||
|
||||
void window_swap(struct mSDLWindow *w)
|
||||
{
|
||||
SDL_GL_SwapWindow(w->window);
|
||||
}
|
34
source/engine/window.h
Normal file
34
source/engine/window.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mSDLWindow {
|
||||
SDL_Window *window;
|
||||
SDL_GLContext glContext;
|
||||
int id;
|
||||
int width;
|
||||
int height;
|
||||
/* TODO: Bitfield these */
|
||||
bool render;
|
||||
bool mouseFocus;
|
||||
bool keyboardFocus;
|
||||
bool fullscreen;
|
||||
bool minimized;
|
||||
bool shown;
|
||||
float projection[16];
|
||||
};
|
||||
|
||||
extern struct mSDLWindow *window;
|
||||
|
||||
struct mSDLWindow *MakeSDLWindow(const char *name, int width, int height,
|
||||
uint32_t flags);
|
||||
void window_handle_event(struct mSDLWindow *w, SDL_Event * e);
|
||||
void window_focus(struct mSDLWindow *w);
|
||||
void window_makecurrent(struct mSDLWindow *w);
|
||||
void window_makefullscreen(struct mSDLWindow *w);
|
||||
void window_togglefullscreen(struct mSDLWindow *w);
|
||||
void window_swap(struct mSDLWindow *w);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue