From 68e6b55daa6907d4c047af1c27709e337385d3ae Mon Sep 17 00:00:00 2001 From: mrq Date: Thu, 4 Mar 2021 00:00:00 -0600 Subject: [PATCH] Commit for 2021.03.04.7z --- Makefile | 19 +- client/dreamcast.gldc.inl | 87 - client/dreamcast.inl | 412 +++- client/main.cpp | 4 +- engine/inc/uf/engine/behavior/behavior.h | 16 +- engine/inc/uf/engine/behavior/macros.inl | 83 +- engine/inc/uf/engine/entity/behavior.h | 9 +- engine/inc/uf/engine/entity/entity.h | 5 +- .../inc/uf/engine/instantiator/instantiator.h | 9 +- .../uf/engine/instantiator/instantiator.inl | 100 +- engine/inc/uf/engine/instantiator/macros.inl | 19 +- engine/inc/uf/engine/object/behavior.h | 32 +- engine/inc/uf/engine/object/behaviors/gltf.h | 16 +- .../inc/uf/engine/object/behaviors/loading.h | 16 +- engine/inc/uf/engine/object/behaviors/lua.h | 16 +- .../inc/uf/engine/object/behaviors/render.h | 16 +- engine/inc/uf/engine/object/object.h | 6 +- engine/inc/uf/engine/object/object.inl | 9 +- engine/inc/uf/engine/scene/behavior.h | 9 +- engine/inc/uf/engine/scene/scene.h | 8 + engine/inc/uf/ext/lua/lua.h | 10 +- engine/inc/uf/ext/lua/lua.inl | 26 +- engine/inc/uf/ext/opengl/ogl.h | 2 + engine/inc/uf/ext/opengl/texture.h | 1 + engine/inc/uf/macros.h | 15 +- engine/inc/uf/spec/controller/controller.h | 9 + engine/inc/uf/spec/controller/dreamcast.h | 23 + engine/inc/uf/spec/controller/universal.h | 17 + engine/inc/uf/spec/controller/unknown.h | 8 + engine/inc/uf/spec/controller/windows.h | 23 + engine/inc/uf/spec/window/dreamcast.h | 1 - engine/inc/uf/utils/image/image.h | 10 + engine/inc/uf/utils/math/math.h | 8 +- engine/inc/uf/utils/math/matrix.h | 2 +- engine/inc/uf/utils/math/matrix/pod.inl | 24 +- engine/inc/uf/utils/math/sh4.h | 2194 +++++++++++++++++ engine/inc/uf/utils/math/vector/pod.inl | 47 +- engine/src/engine/asset/asset.cpp | 2 + engine/src/engine/behavior/behavior.cpp | 125 +- engine/src/engine/entity/behavior.cpp | 37 +- engine/src/engine/entity/entity.cpp | 12 +- .../src/engine/instantiator/instantiator.cpp | 30 +- engine/src/engine/object/behavior.cpp | 56 +- engine/src/engine/object/behaviors/gltf.cpp | 127 +- .../src/engine/object/behaviors/loading.cpp | 46 +- engine/src/engine/object/behaviors/lua.cpp | 15 +- engine/src/engine/object/behaviors/render.cpp | 2 +- engine/src/engine/object/object.cpp | 68 +- engine/src/engine/scene/behavior.cpp | 7 +- engine/src/engine/scene/scene.cpp | 87 +- engine/src/ext/gltf/graph.cpp | 243 +- engine/src/ext/lua/usertypes/asset.cpp | 1 - engine/src/ext/lua/usertypes/audio.cpp | 1 - engine/src/ext/lua/usertypes/camera.cpp | 1 - engine/src/ext/lua/usertypes/object.cpp | 4 +- engine/src/ext/opengl/commands.cpp | 3 + engine/src/ext/opengl/opengl.cpp | 188 +- engine/src/ext/opengl/rendermode.cpp | 20 + engine/src/ext/opengl/rendermodes/base.cpp | 14 +- engine/src/ext/opengl/texture.cpp | 123 +- engine/src/ext/vulkan/rendermode.cpp | 41 +- engine/src/ext/vulkan/vulkan.cpp | 218 +- engine/src/spec/controller/dreamcast.cpp | 114 + engine/src/spec/controller/universal.cpp | 8 + engine/src/spec/controller/unknown.cpp | 5 + engine/src/spec/controller/windows.cpp | 79 + engine/src/spec/window/dreamcast.cpp | 337 ++- engine/src/spec/window/windows.cpp | 808 +++--- engine/src/utils/image/image.cpp | 150 +- engine/src/utils/thread/thread.cpp | 23 +- ext/behaviors/craeture/behavior.cpp | 16 +- ext/behaviors/craeture/behavior.h | 16 +- ext/behaviors/hands/behavior.cpp | 4 +- ext/behaviors/hands/behavior.h | 16 +- ext/behaviors/light/behavior.cpp | 266 +- ext/behaviors/light/behavior.h | 31 +- ext/behaviors/noise/behavior.cpp | 4 +- ext/behaviors/noise/behavior.h | 16 +- ext/behaviors/player/behavior.cpp | 475 ++-- ext/behaviors/player/behavior.h | 41 +- ext/behaviors/player/model/behavior.h | 16 +- ext/behaviors/portal/behavior.cpp | 4 +- ext/behaviors/portal/behavior.h | 32 +- ext/behaviors/scene/behavior.cpp | 440 ++-- ext/behaviors/scene/behavior.h | 44 +- ext/behaviors/scene/collision/behavior.cpp | 4 +- ext/behaviors/scene/collision/behavior.h | 16 +- ext/behaviors/soundemitter/behavior.h | 16 +- ext/behaviors/sprite/behavior.cpp | 4 +- ext/behaviors/sprite/behavior.h | 16 +- ext/gui/behavior.cpp | 21 +- ext/gui/behavior.h | 16 +- ext/gui/gui.h | 3 +- ext/gui/html/behavior.cpp | 4 +- ext/gui/html/behavior.h | 16 +- ext/gui/manager/behavior.cpp | 1 - ext/gui/manager/behavior.h | 16 +- ext/main.cpp | 155 +- ext/scenes/raytrace/behavior.cpp | 4 +- ext/scenes/raytrace/behavior.h | 15 +- ext/scenes/worldscape/behavior.cpp | 4 +- ext/scenes/worldscape/behavior.h | 15 +- ext/scenes/worldscape/gui/battle.cpp | 4 +- ext/scenes/worldscape/gui/dialogue.cpp | 4 +- ext/scenes/worldscape/housamo/battle.cpp | 4 +- ext/scenes/worldscape/housamo/dialogue.cpp | 4 +- ext/scenes/worldscape/housamo/housamo.cpp | 4 +- ext/scenes/worldscape/terrain/behavior.cpp | 4 +- ext/scenes/worldscape/terrain/behavior.h | 15 +- ext/scenes/worldscape/terrain/generator.cpp | 4 +- ext/scenes/worldscape/terrain/maze.cpp | 4 +- ext/scenes/worldscape/terrain/region.cpp | 4 +- ext/scenes/worldscape/terrain/region.h | 15 +- ext/scenes/worldscape/terrain/terrain.cpp | 4 +- ext/scenes/worldscape/terrain/voxel.cpp | 4 +- makefiles/dreamcast.gcc.make | 12 +- makefiles/win64.clang.make | 2 +- makefiles/win64.gcc.make | 2 +- makefiles/win64.gcc10.make | 2 +- 119 files changed, 5622 insertions(+), 2523 deletions(-) delete mode 100644 client/dreamcast.gldc.inl create mode 100644 engine/inc/uf/spec/controller/controller.h create mode 100644 engine/inc/uf/spec/controller/dreamcast.h create mode 100644 engine/inc/uf/spec/controller/universal.h create mode 100644 engine/inc/uf/spec/controller/unknown.h create mode 100644 engine/inc/uf/spec/controller/windows.h create mode 100644 engine/inc/uf/utils/math/sh4.h create mode 100644 engine/src/spec/controller/dreamcast.cpp create mode 100644 engine/src/spec/controller/universal.cpp create mode 100644 engine/src/spec/controller/unknown.cpp create mode 100644 engine/src/spec/controller/windows.cpp diff --git a/Makefile b/Makefile index 75b38698..c9f2344c 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,7 @@ ifneq (,$(findstring win64,$(ARCH))) FLAGS += DEPS += -lgdi32 else ifneq (,$(findstring dreamcast,$(ARCH))) - REQ_DEPS += opengl gldc json:nlohmann png meshoptimizer bullet freetype # lua ogg openal draco luajit ultralight-ux ncurses curl openvr discord - FLAGS += $(KOS_CPPFLAGS) -frtti -DUF_NO_EXCEPTIONS - INCS += $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include - LIBS += $(KOS_LIB_PATHS) -L/opt/dreamcast/sh-elf/sh-elf/lib + REQ_DEPS += opengl gldc json:nlohmann bullet lua # freetype png meshoptimizer ogg openal draco luajit ultralight-ux ncurses curl openvr discord endif ifneq (,$(findstring vulkan,$(REQ_DEPS))) FLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN @@ -66,7 +63,7 @@ ifneq (,$(findstring json,$(REQ_DEPS))) endif ifneq (,$(findstring png,$(REQ_DEPS))) FLAGS += -DUF_USE_PNG - DEPS += -lpng -lz -lbz2 + DEPS += -lpng -lz endif ifneq (,$(findstring openal,$(REQ_DEPS))) FLAGS += -DUF_USE_OPENAL @@ -87,7 +84,7 @@ ifneq (,$(findstring ogg,$(REQ_DEPS))) endif ifneq (,$(findstring freetype,$(REQ_DEPS))) FLAGS += -DUF_USE_FREETYPE - DEPS += -lfreetype + DEPS += -lfreetype -lbz2 ifneq (,$(findstring dreamcast,$(ARCH))) DEPS += -lbrotlicommon-static -lbrotlidec-static endif @@ -185,8 +182,8 @@ SRCS_SHADERS += $(wildcard bin/data/shaders/*.glsl) $(wildcard bin/data/shade TARGET_SHADERS += $(patsubst %.glsl,%.spv,$(SRCS_SHADERS)) ifneq (,$(findstring dreamcast,$(ARCH))) -$(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi -#$(ARCH): $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi +#$(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi +$(ARCH): $(TARGET) ./bin/dreamcast/$(TARGET_NAME).cdi OBJS = $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_DLL)) $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_EXT_DLL)) $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS)) DEPS += -lkallisti -lc -lm -lgcc -lstdc++ # -l$(LIB_NAME) -l$(EXT_LIB_NAME) @@ -253,6 +250,9 @@ clean: @-rm ./bin/dreamcast/build/* @-rm ./bin/dreamcast/romdisk.* @-rm ./bin/dreamcast/$(TARGET_NAME).* + +run: + $(KOS_EMU) ./bin/dreamcast/$(TARGET_NAME).cdi else clean: @-rm $(EX_DLL) @@ -262,6 +262,9 @@ clean: @-rm -f $(OBJS_DLL) @-rm -f $(OBJS_EXT_DLL) @-rm -f $(OBJS) + +run: + ./program.sh endif clean-uf: @-rm $(EX_DLL) diff --git a/client/dreamcast.gldc.inl b/client/dreamcast.gldc.inl deleted file mode 100644 index 9ae27a74..00000000 --- a/client/dreamcast.gldc.inl +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include - -/* A general OpenGL initialization function. Sets all of the initial parameters. */ -void InitGL(int Width, int Height) // We call this right after our OpenGL window is created. -{ - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black - glClearDepth(1.0); // Enables Clearing Of The Depth Buffer - glDepthFunc(GL_LESS); // The Type Of Depth Test To Do - glEnable(GL_DEPTH_TEST); // Enables Depth Testing - glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading - - glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex arrays - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); // Reset The Projection Matrix - - gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window - - glMatrixMode(GL_MODELVIEW); -} - -/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */ -void ReSizeGLScene(int Width, int Height) -{ - if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small - Height = 1; - - glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); - glMatrixMode(GL_MODELVIEW); -} - - -/* The main drawing function. */ -void DrawGLScene() -{ - - const GLfloat triangle [] = { - 0.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, -1.0f, 0.0f - }; - - const GLfloat square [] = { - -1.0f, 1.0f, 0.0f, - 1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, - -1.0f, -1.0f, 0.0f - }; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer - glLoadIdentity(); // Reset The View - - glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0 - - glVertexPointer(3, GL_FLOAT, 0, triangle); - glDrawArrays(GL_TRIANGLES, 0, 3); - - glTranslatef(3.0f,0.0f,0.0f); // Move Right 3 Units - - glVertexPointer(3, GL_FLOAT, 0, square); - glDrawArrays(GL_QUADS, 0, 4); - - // swap buffers to display, since we're double buffered. - glKosSwapBuffers(); -} - -int main(int argc, char **argv) -{ - glKosInit(); - - InitGL(640, 480); - ReSizeGLScene(640, 480); - - while(1) { - UF_DEBUG_PRINT_MARKER(); - DrawGLScene(); - } - - return 0; -} diff --git a/client/dreamcast.inl b/client/dreamcast.inl index f03a2f31..e9669e2a 100644 --- a/client/dreamcast.inl +++ b/client/dreamcast.inl @@ -1,82 +1,366 @@ -/* - KallistiOS 2.0.0 - - nehe02.c - (c)2014 Josh Pearson - (c)2001 Benoit Miller - (c)2000 Jeff Molofee +/* +** $Id: lua.c,v 1.222 2014/11/11 19:41:27 roberto Exp $ +** Lua stand-alone interpreter +** See Copyright Notice in lua.h */ -#include +#define lua_c -#include -#include -#include +#if 0 +#include "lprefix.h" + + +#include +#endif + +#include +#include +#include + +#include "lua.h" + +#include "lauxlib.h" +#include "lualib.h" + +/* KOS-specific stuff. */ +#include +#include +#include +#include + +void cont_cb(uint8 addr, uint32 btns) { + (void)addr; + (void)btns; + + exit(0); +} + +static int kbd_readline(char *buf, int len) { + int ch = 0; + maple_device_t *dev; + int pos = 0; + + if(!buf || !len) + return 0; + + /* Clear the buffer. */ + memset(buf, 0, len); + + while(ch != '\n' && pos < len - 1) { + /* Not really sensible, but just in case someone unplugs and replugs + their keyboard, we'll probably work right... */ + if((dev = maple_enum_type(0, MAPLE_FUNC_KEYBOARD))) { + ch = kbd_queue_pop(dev, 1); + + /* Make sure we got an ASCII character. */ + if((ch & 0xFFFFFF00)) + continue; + + /* Put the character into the buffer and print it out on the + terminal. */ + buf[pos++] = (char)ch; + printf("%c", (char)ch); + fflush(stdout); + } + } + + return 1; +} + +#define lua_readline(L,b,p) \ + ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ + kbd_readline(b, LUA_MAXINPUT) != 0) /* get line */ +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } + +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ + +/* End KOS-specific stuff. */ + + +#if !defined(LUA_PROMPT) +#define LUA_PROMPT "> " +#define LUA_PROMPT2 ">> " +#endif + +#if !defined(LUA_PROGNAME) +#define LUA_PROGNAME "lua" +#endif + +#if !defined(LUA_MAXINPUT) +#define LUA_MAXINPUT 512 +#endif + +#if !defined(LUA_INIT_VAR) +#define LUA_INIT_VAR "LUA_INIT" +#endif + +#define LUA_INITVARVERSION \ + LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR + + +static lua_State *globalL = NULL; + +static const char *progname = LUA_PROGNAME; /* - The simplest OpenGL example ever! - - Essentially the same thing as NeHe's lesson02 code. - To learn more, go to http://nehe.gamedev.net/. +** Prints an error message, adding the program name in front of it +** (if present) */ - -void draw_gl(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glLoadIdentity(); - glTranslatef(-1.5f, 0.0f, -6.0f); - - glBegin(GL_TRIANGLES); - glVertex3f(0.0f, 1.0f, 0.0f); - glVertex3f(-1.0f, -1.0f, 0.0f); - glVertex3f(1.0f, -1.0f, 0.0f); - glEnd(); - - glTranslatef(3.0f, 0.0f, 0.0f); - - glBegin(GL_QUADS); - glVertex3f(-1.0f, 1.0f, 0.0f); - glVertex3f(1.0f, 1.0f, 0.0f); - glVertex3f(1.0f, -1.0f, 0.0f); - glVertex3f(-1.0f, -1.0f, 0.0f); - glEnd(); +static void l_message (const char *pname, const char *msg) { + if (pname) lua_writestringerror("%s: ", pname); + lua_writestringerror("%s\n", msg); } -int main(int argc, char **argv) { - maple_device_t *cont; - cont_state_t *state; - /* Get basic stuff initialized */ - printf("nehe02 beginning\n"); - /* Notice we do not init the PVR here, that is handled by OpenGL */ - glKosInit(); +/* +** Check whether 'status' is not OK and, if so, prints the error +** message on the top of the stack. It assumes that the error object +** is a string, as it was either generated by Lua or by 'msghandler'. +*/ +static int report (lua_State *L, int status) { + if (status != LUA_OK) { + const char *msg = lua_tostring(L, -1); + l_message(progname, msg); + lua_pop(L, 1); /* remove message */ + } + return status; +} - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(45.0f, 640.0f / 480.0f, 0.1f, 100.0f); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - while(1) { - cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); +/* +** Message handler used to run all chunks +*/ +static int msghandler (lua_State *L) { + const char *msg = lua_tostring(L, 1); + if (msg == NULL) { /* is error object not a string? */ + if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ + lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ + return 1; /* that is the message */ + else + msg = lua_pushfstring(L, "(error object is a %s value)", + luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); /* append a standard traceback */ + return 1; /* return the traceback */ +} - /* Check key status */ - state = (cont_state_t *)maple_dev_status(cont); - if(!state) { - printf("Error reading controller\n"); - break; - } +/* +** Interface to 'lua_pcall', which sets appropriate message function +** and C-signal handler. Used to run all chunks. +*/ +static int docall (lua_State *L, int narg, int nres) { + int status; + int base = lua_gettop(L) - narg; /* function index */ + lua_pushcfunction(L, msghandler); /* push message handler */ + lua_insert(L, base); /* put it under function and args */ + globalL = L; /* to be available to 'laction' */ - if(state->buttons & CONT_START) - break; + status = lua_pcall(L, narg, nres, base); - /* Draw the "scene" */ - draw_gl(); + lua_remove(L, base); /* remove message handler from the stack */ + return status; +} - /* Finish the frame - Notice there is no glKosBegin/FinshFrame */ - glutSwapBuffers(); + +static void print_version (void) { + lua_writestring(LUA_COPYRIGHT, strlen(LUA_COPYRIGHT)); + lua_writeline(); +} + + +/* +** Returns the string to be used as a prompt by the interpreter. +*/ +static const char *get_prompt (lua_State *L, int firstline) { + const char *p; + lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); + p = lua_tostring(L, -1); + if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); + return p; +} + +/* mark in error messages for incomplete statements */ +#define EOFMARK "" +#define marklen (sizeof(EOFMARK)/sizeof(char) - 1) + + +/* +** Check whether 'status' signals a syntax error and the error +** message at the top of the stack ends with the above mark for +** incomplete statements. +*/ +static int incomplete (lua_State *L, int status) { + if (status == LUA_ERRSYNTAX) { + size_t lmsg; + const char *msg = lua_tolstring(L, -1, &lmsg); + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { + lua_pop(L, 1); + return 1; } - - return 0; + } + return 0; /* else... */ } + + +/* +** Prompt the user, read a line, and push it into the Lua stack. +*/ +static int pushline (lua_State *L, int firstline) { + char buffer[LUA_MAXINPUT]; + char *b = buffer; + size_t l; + const char *prmt = get_prompt(L, firstline); + int readstatus = lua_readline(L, b, prmt); + if (readstatus == 0) + return 0; /* no input (prompt will be popped by caller) */ + lua_pop(L, 1); /* remove prompt */ + l = strlen(b); + if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ + b[l-1] = '\0'; /* remove it */ + if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */ + lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ + else + lua_pushstring(L, b); + lua_freeline(L, b); + return 1; +} + + +/* +** Try to compile line on the stack as 'return '; on return, stack +** has either compiled chunk or original line (if compilation failed). +*/ +static int addreturn (lua_State *L) { + int status; + size_t len; const char *line; + lua_pushliteral(L, "return "); + lua_pushvalue(L, -2); /* duplicate line */ + lua_concat(L, 2); /* new line is "return ..." */ + line = lua_tolstring(L, -1, &len); + if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK) + lua_remove(L, -3); /* remove original line */ + else + lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */ + return status; +} + + +/* +** Read multiple lines until a complete Lua statement +*/ +static int multiline (lua_State *L) { + for (;;) { /* repeat until gets a complete statement */ + size_t len; + const char *line = lua_tolstring(L, 1, &len); /* get what it has */ + int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ + if (!incomplete(L, status) || !pushline(L, 0)) + return status; /* cannot or should not try to add continuation line */ + lua_pushliteral(L, "\n"); /* add newline... */ + lua_insert(L, -2); /* ...between the two lines */ + lua_concat(L, 3); /* join them */ + } +} + + +/* +** Read a line and try to load (compile) it first as an expression (by +** adding "return " in front of it) and second as a statement. Return +** the final status of load/call with the resulting function (if any) +** in the top of the stack. +*/ +static int loadline (lua_State *L) { + int status; + lua_settop(L, 0); + if (!pushline(L, 1)) + return -1; /* no input */ + if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */ + status = multiline(L); /* try as command, maybe with continuation lines */ + lua_saveline(L, 1); /* keep history */ + lua_remove(L, 1); /* remove line from the stack */ + lua_assert(lua_gettop(L) == 1); + return status; +} + + +/* +** Prints (calling the Lua 'print' function) any values on the stack +*/ +static void l_print (lua_State *L) { + int n = lua_gettop(L); + if (n > 0) { /* any result to be printed? */ + luaL_checkstack(L, LUA_MINSTACK, "too many results to print"); + lua_getglobal(L, "print"); + lua_insert(L, 1); + if (lua_pcall(L, n, 0, 0) != LUA_OK) + l_message(progname, lua_pushfstring(L, "error calling 'print' (%s)", + lua_tostring(L, -1))); + } +} + + +/* +** Do the REPL: repeatedly read (load) a line, evaluate (call) it, and +** print any results. +*/ +static void doREPL (lua_State *L) { + int status; + const char *oldprogname = progname; + progname = NULL; /* no 'progname' on errors in interactive mode */ + while ((status = loadline(L)) != -1) { + if (status == LUA_OK) + status = docall(L, 0, LUA_MULTRET); + if (status == LUA_OK) l_print(L); + else report(L, status); + } + lua_settop(L, 0); /* clear stack */ + lua_writeline(); + progname = oldprogname; +} + + +/* +** Main body of stand-alone interpreter (to be called in protected mode). +** Reads the options and handles them all. +*/ +static int pmain (lua_State *L) { + luaL_checkversion(L); /* check that interpreter has correct version */ + + lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */ + lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); + + luaL_openlibs(L); /* open standard libraries */ + + print_version(); + doREPL(L); /* do read-eval-print loop */ + + lua_pushboolean(L, 1); /* signal no errors */ + return 1; +} + + +int main (int argc, char **argv) { + int status, result; + lua_State *L = luaL_newstate(); /* create state */ + + /* Make sure printf and friends go to the screen. */ + dbgio_dev_select("fb"); + + /* Set our "interrupt" callback to give us a way out of the interpreter. */ + cont_btn_callback(0, CONT_START, &cont_cb); + + if (L == NULL) { + l_message(argv[0], "cannot create state: not enough memory"); + return EXIT_FAILURE; + } + + lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ + lua_pushinteger(L, argc); /* 1st argument */ + lua_pushlightuserdata(L, argv); /* 2nd argument */ + status = lua_pcall(L, 2, 1, 0); /* do the call */ + result = lua_toboolean(L, -1); /* get result */ + report(L, status); + lua_close(L); + return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE; +} \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp index d90881e4..798a1f15 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -51,10 +51,10 @@ int main(int argc, char** argv){ json["window"]["size"]["y"] = client::config["window"]["size"]["y"]; uf::hooks.call(hook, json); } - client::tick(); - ext::tick(); client::render(); ext::render(); + client::tick(); + ext::tick(); #if HANDLE_EXCEPTIONS } catch ( std::runtime_error& e ) { uf::iostream << "RUNTIME ERROR: " << e.what() << "\n"; diff --git a/engine/inc/uf/engine/behavior/behavior.h b/engine/inc/uf/engine/behavior/behavior.h index 8ded8cd9..442b244d 100644 --- a/engine/inc/uf/engine/behavior/behavior.h +++ b/engine/inc/uf/engine/behavior/behavior.h @@ -13,10 +13,11 @@ namespace uf { namespace pod { struct UF_API Behavior { - typedef std::type_index type_t; + // typedef std::type_index type_t; + typedef std::string type_t; typedef std::function function_t; - type_t type = std::type_index(typeid(pod::Behavior)); + type_t type = ""; //std::type_index(typeid(pod::Behavior)); function_t initialize = function_t(); function_t tick = function_t(); function_t render = function_t(); @@ -40,6 +41,10 @@ namespace uf { } bool hasBehavior( const pod::Behavior& ); + void addBehavior( const pod::Behavior& ); + void removeBehavior( const pod::Behavior& ); + + #if 0 template bool hasBehavior() { for ( auto& behavior : this->m_behaviors ) { @@ -47,13 +52,9 @@ namespace uf { } return false; } - - void addBehavior( const pod::Behavior& ); - void removeBehavior( const pod::Behavior& ); - template static pod::Behavior::type_t getType() { - return std::type_index(typeid(T)); + return T::type; //std::type_index(typeid(T)); } template void addBehavior() { @@ -71,6 +72,7 @@ namespace uf { .type = getType() }); } + #endif }; } diff --git a/engine/inc/uf/engine/behavior/macros.inl b/engine/inc/uf/engine/behavior/macros.inl index 2629b023..b630a514 100644 --- a/engine/inc/uf/engine/behavior/macros.inl +++ b/engine/inc/uf/engine/behavior/macros.inl @@ -1,19 +1,25 @@ #pragma once -#define UF_BEHAVIOR_ENTITY_H( OBJ )\ - class UF_API OBJ ## Behavior {\ - public:\ - static void attach( uf::Entity& );\ - static void initialize( uf::Object& );\ - static void tick( uf::Object& );\ - static void render( uf::Object& );\ - static void destroy( uf::Object& );\ +#define UF_ENTITY_METADATA_USE_JSON 0 +#define UF_BEHAVIOR_DEFINE_TYPE static constexpr const char* type = __FILE__; + +#define UF_BEHAVIOR_ENTITY_METADATA_H( OBJ, METADATA )\ + namespace OBJ ## Behavior {\ + UF_BEHAVIOR_DEFINE_TYPE;\ + void attach( uf::Entity& );\ + void initialize( uf::Object& );\ + void tick( uf::Object& );\ + void render( uf::Object& );\ + void destroy( uf::Object& );\ + METADATA;\ }; +#define UF_BEHAVIOR_ENTITY_H( OBJ ) UF_BEHAVIOR_ENTITY_METADATA_H( OBJ, struct Metadata{}; ) + #define UF_BEHAVIOR_ENTITY_CPP_BEGIN( OBJ )\ void OBJ ## Behavior::attach( uf::Entity& self ) {\ self.addBehavior(pod::Behavior{\ - .type = uf::Behaviors::getType(),\ + .type = OBJ ## Behavior::type,\ .initialize = OBJ ## Behavior::initialize,\ .tick = OBJ ## Behavior::tick,\ .render = OBJ ## Behavior::render,\ @@ -24,61 +30,4 @@ OBJ ## Behavior::attach( *this );\ } -#define UF_BEHAVIOR_ENTITY_CPP_END( OBJ ) - -/* -#define UF_BEHAVIOR_VIRTUAL 0 - -#define UF_BEHAVIOR_ENTITY_H( OBJ )\ - class UF_API OBJ ## Behavior {\ - public:\ - static void attach( uf::Entity& );\ - static void initialize( uf::Object& );\ - static void tick( uf::Object& );\ - static void render( uf::Object& );\ - static void destroy( uf::Object& );\ - }; -#if UF_BEHAVIOR_VIRTUAL - #define UF_BEHAVIOR_VIRTUAL_H() \ - virtual void initialize();\ - virtual void destroy();\ - virtual void tick();\ - virtual void render(); - - #define UF_BEHAVIOR_ENTITY_CPP_VIRTUAL_DEFINITIONS( OBJ )\ - void uf::OBJ::initialize(){ uf::Behaviors::initialize(); }\ - void uf::OBJ::tick(){ uf::Behaviors::tick(); }\ - void uf::OBJ::render(){ uf::Behaviors::render(); }\ - void uf::OBJ::destroy(){ uf::Behaviors::destroy(); } -#else - #define UF_BEHAVIOR_VIRTUAL_H() - #define UF_BEHAVIOR_ENTITY_CPP_VIRTUAL_DEFINITIONS( OBJ ) -#endif -#define UF_BEHAVIOR_ENTITY_CPP_BEGIN( OBJ )\ - uf::OBJ::OBJ() { \ - uf::OBJ ## Behavior::attach( *this );\ - }\ - UF_BEHAVIOR_ENTITY_CPP_VIRTUAL_DEFINITIONS( OBJ )\ - void uf::OBJ ## Behavior::attach( uf::Entity& self ) {\ - self.addBehavior(pod::Behavior{\ - .type = uf::Behaviors::getType(),\ - .initialize = uf::OBJ ## Behavior::initialize,\ - .tick = uf::OBJ ## Behavior::tick,\ - .render = uf::OBJ ## Behavior::render,\ - .destroy = uf::OBJ ## Behavior::destroy,\ - });\ - } -#define UF_BEHAVIOR_ENTITY_CPP_END( OBJ ) - -#define EXT_BEHAVIOR_ENTITY_CPP_BEGIN( OBJ )\ - void ext::OBJ ## Behavior::attach( uf::Entity& self ) {\ - self.addBehavior(pod::Behavior{\ - .type = uf::Behaviors::getType(),\ - .initialize = ext::OBJ ## Behavior::initialize,\ - .tick = ext::OBJ ## Behavior::tick,\ - .render = ext::OBJ ## Behavior::render,\ - .destroy = ext::OBJ ## Behavior::destroy,\ - });\ - } -#define EXT_BEHAVIOR_ENTITY_CPP_END( OBJ ) -*/ \ No newline at end of file +#define UF_BEHAVIOR_ENTITY_CPP_END( OBJ ) \ No newline at end of file diff --git a/engine/inc/uf/engine/entity/behavior.h b/engine/inc/uf/engine/entity/behavior.h index b4ef84d2..ff1f0b76 100644 --- a/engine/inc/uf/engine/entity/behavior.h +++ b/engine/inc/uf/engine/entity/behavior.h @@ -1,5 +1,12 @@ #pragma once namespace uf { - UF_BEHAVIOR_ENTITY_H(Entity) + namespace EntityBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Entity& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index 850eb296..161afb5f 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -11,7 +11,7 @@ namespace uf { class UF_API Object; class UF_API Entity : public uf::Behaviors { - friend class EntityBehavior; + //friend class EntityBehavior; public: typedef std::vector container_t; static uf::Entity null; @@ -45,6 +45,9 @@ namespace uf { template const T& getParent() const; template const T& getRootParent() const; + void setUid(); + void unsetUid(); + void setParent(); void setParent( uf::Entity& parent ); uf::Entity& addChild( uf::Entity& child ); diff --git a/engine/inc/uf/engine/instantiator/instantiator.h b/engine/inc/uf/engine/instantiator/instantiator.h index 24751b9e..88262cda 100644 --- a/engine/inc/uf/engine/instantiator/instantiator.h +++ b/engine/inc/uf/engine/instantiator/instantiator.h @@ -37,13 +37,16 @@ namespace pod { C& get( const std::string& name ); template C& get(); + + C& operator[]( const std::string& name ); }; } namespace uf { namespace instantiator { extern UF_API pod::NamedTypes* objects; - extern UF_API pod::NamedTypes* behaviors; + // extern UF_API pod::NamedTypes* behaviors; + extern UF_API std::unordered_map* behaviors; uf::Entity* UF_API alloc( size_t ); template T* alloc(); @@ -54,8 +57,9 @@ namespace uf { size_t UF_API collect( uint8_t = 0 ); template void registerObject( const std::string& name ); - template void registerBehavior( const std::string& name ); + // template void registerBehavior( const std::string& name ); template void registerBinding( const std::string& name ); + void UF_API registerBehavior( const std::string& name, const pod::Behavior& ); void UF_API registerBinding( const std::string& object, const std::string& behavior ); uf::Entity& UF_API instantiate( const std::string& ); @@ -64,6 +68,7 @@ namespace uf { void UF_API bind( const std::string&, uf::Entity& ); template void bind( uf::Entity& ); + void UF_API unbind( const std::string&, uf::Entity& ); template void unbind( uf::Entity& ); }; diff --git a/engine/inc/uf/engine/instantiator/instantiator.inl b/engine/inc/uf/engine/instantiator/instantiator.inl index 8d014cca..2ec88cee 100644 --- a/engine/inc/uf/engine/instantiator/instantiator.inl +++ b/engine/inc/uf/engine/instantiator/instantiator.inl @@ -34,6 +34,10 @@ template C& pod::NamedTypes::get() { return map[getName()]; } +template +C& pod::NamedTypes::operator[]( const std::string& name ) { + return get(name); +} template T* uf::instantiator::alloc() { @@ -48,8 +52,9 @@ template void uf::instantiator::registerObject( const std::string& n .behaviors = {} }); - if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered instantiation for " << name << std::endl; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Registered instantiation for " << name); } +#if 0 template void uf::instantiator::registerBehavior( const std::string& name ) { if ( !behaviors ) behaviors = new pod::NamedTypes; auto& container = *uf::instantiator::behaviors; @@ -61,16 +66,16 @@ template void uf::instantiator::registerBehavior( const std::string& .destroy = T::destroy, }); - if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered behavior for " << name << std::endl; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Registered behavior for " << name); } - +#endif template void uf::instantiator::registerBinding( const std::string& name ) { if ( !objects ) objects = new pod::NamedTypes; auto& container = *uf::instantiator::objects; auto& instantiator = container.get(); instantiator.behaviors.emplace_back(name); - if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered binding for " << name << std::endl; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Registered binding for " << name); } template @@ -90,7 +95,7 @@ template void uf::instantiator::bind( uf::Entity& entity ) { auto& instantiator = uf::instantiator::objects->get(); for ( auto& name : instantiator.behaviors ) { - auto& behavior = uf::instantiator::behaviors->get( name ); + auto& behavior = (*uf::instantiator::behaviors)[name]; entity.addBehavior(behavior); } } @@ -99,88 +104,7 @@ template void uf::instantiator::unbind( uf::Entity& entity ) { auto& instantiator = uf::instantiator::objects->get(); for ( auto& name : instantiator.behaviors ) { - auto& behavior = uf::instantiator::behaviors->get( name ); + auto& behavior = (*uf::instantiator::behaviors)[name]; entity.removeBehavior(behavior); } -} -/* -template -T* uf::instantiator::alloc() { - return (T*) alloc( sizeof(T) ); -} - -template -std::string uf::instantiator::getName() { - auto type = getType(); - auto& names = *uf::instantiator::names; - return names[type]; -} - -template -uf::instantiator::type_t uf::instantiator::getType() { - return std::type_index(typeid(T)); -} - -template -T& uf::instantiator::instantiate() { - T* entity = alloc(); - ::new (entity) T(); - T& object = *entity; - uf::instantiator::bind( object ); - return object; -} -template -T* uf::instantiator::_instantiate() { - return &instantiate(); -} - -template -void uf::instantiator::add( const std::string& name ) { - if ( !map ) map = new std::unordered_map; - if ( !names ) names = new std::unordered_map; - - auto& map = *uf::instantiator::map; - auto& names = *uf::instantiator::names; - - auto type = getType(); - names[type] = name; - map[name] = { - .function = _instantiate - }; - - std::cout << "Registered instantiation for " << name << std::endl; -} -template -void uf::instantiator::add( const pod::Behavior& behavior ) { - if ( !registered() ) return; - auto type = getType(); - auto& map = *uf::instantiator::map; - auto& instantiator = map[getName()]; - instantiator.behaviors.emplace_back(behavior); -} -template -void uf::instantiator::add() { - return uf::instantiator::add(pod::Behavior{ - .type = uf::Behaviors::getType(), - .initialize = U::initialize, - .tick = U::tick, - .render = U::render, - .destroy = U::destroy, - }); -} - -template -bool uf::instantiator::registered() { - return uf::instantiator::map->count(getName()) > 0; -} - -template -void uf::instantiator::bind( T& object ) { - if ( !registered() ) return; - auto& map = *uf::instantiator::map; - auto& instantiator = map[getName()]; - for ( auto& behavior : instantiator.behaviors ) { - object.addBehavior(behavior); - } -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/engine/instantiator/macros.inl b/engine/inc/uf/engine/instantiator/macros.inl index 345c904e..cfe38e57 100644 --- a/engine/inc/uf/engine/instantiator/macros.inl +++ b/engine/inc/uf/engine/instantiator/macros.inl @@ -7,10 +7,17 @@ namespace {\ });\ } +// uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) ); #define UF_BEHAVIOR_REGISTER_CPP( BEHAVIOR ) \ namespace {\ static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\ - uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) );\ + uf::instantiator::registerBehavior(UF_NS_GET_LAST(BEHAVIOR), pod::Behavior{\ + .type = BEHAVIOR::type,\ + .initialize = BEHAVIOR::initialize,\ + .tick = BEHAVIOR::tick,\ + .render = BEHAVIOR::render,\ + .destroy = BEHAVIOR::destroy,\ + });\ });\ } @@ -30,8 +37,16 @@ namespace {\ #define UF_OBJECT_BIND_BEHAVIOR( BEHAVIOR )\ uf::instantiator::registerBinding( name, UF_NS_GET_LAST(BEHAVIOR) ); +// uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) ); #define UF_OBJECT_REGISTER_BEHAVIOR( BEHAVIOR )\ - uf::instantiator::registerBehavior( UF_NS_GET_LAST(BEHAVIOR) );\ + if ( !uf::instantiator::behaviors ) uf::instantiator::behaviors = new std::unordered_map;\ + uf::instantiator::registerBehavior(UF_NS_GET_LAST(BEHAVIOR), pod::Behavior{\ + .type = BEHAVIOR::type,\ + .initialize = BEHAVIOR::initialize,\ + .tick = BEHAVIOR::tick,\ + .render = BEHAVIOR::render,\ + .destroy = BEHAVIOR::destroy,\ + });\ UF_OBJECT_BIND_BEHAVIOR( BEHAVIOR ) #define UF_OBJECT_REGISTER_END()\ diff --git a/engine/inc/uf/engine/object/behavior.h b/engine/inc/uf/engine/object/behavior.h index aa402c1e..7c3bfef9 100644 --- a/engine/inc/uf/engine/object/behavior.h +++ b/engine/inc/uf/engine/object/behavior.h @@ -1,5 +1,35 @@ #pragma once +#include +#include +#include + +#include +#include +#include + namespace uf { - UF_BEHAVIOR_ENTITY_H(Object) + namespace ObjectBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Entity& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + struct Metadata { + struct Queued { + std::string name; + ext::json::Value payload; + double timeout; + }; + + struct { + std::unordered_map> bound; + std::vector queue; + } hooks; + struct { + bool ignoreGraph = false; + } system; + }; + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/object/behaviors/gltf.h b/engine/inc/uf/engine/object/behaviors/gltf.h index 918f3183..dcf517fd 100644 --- a/engine/inc/uf/engine/object/behaviors/gltf.h +++ b/engine/inc/uf/engine/object/behaviors/gltf.h @@ -5,12 +5,12 @@ #include namespace uf { - class UF_API GltfBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace GltfBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Object& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/object/behaviors/loading.h b/engine/inc/uf/engine/object/behaviors/loading.h index df574268..5ef0df3a 100644 --- a/engine/inc/uf/engine/object/behaviors/loading.h +++ b/engine/inc/uf/engine/object/behaviors/loading.h @@ -5,12 +5,12 @@ #include namespace uf { - class UF_API LoadingBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace LoadingBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Object& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/object/behaviors/lua.h b/engine/inc/uf/engine/object/behaviors/lua.h index 3bb1c38f..92fb78e9 100644 --- a/engine/inc/uf/engine/object/behaviors/lua.h +++ b/engine/inc/uf/engine/object/behaviors/lua.h @@ -5,12 +5,12 @@ #include namespace uf { - class UF_API LuaBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace LuaBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Object& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/object/behaviors/render.h b/engine/inc/uf/engine/object/behaviors/render.h index 18e4ca8c..562a8ceb 100644 --- a/engine/inc/uf/engine/object/behaviors/render.h +++ b/engine/inc/uf/engine/object/behaviors/render.h @@ -5,12 +5,12 @@ #include namespace uf { - class UF_API RenderBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace RenderBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Object& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/object/object.h b/engine/inc/uf/engine/object/object.h index 7bee03a0..9299ee6f 100644 --- a/engine/inc/uf/engine/object/object.h +++ b/engine/inc/uf/engine/object/object.h @@ -1,5 +1,6 @@ #pragma once +#include "behavior.h" #include #include #include @@ -33,18 +34,13 @@ namespace uf { std::string formatHookName( const std::string& name ); static std::string formatHookName( const std::string& name, size_t uid, bool fetch = true ); - // void queueHook( const std::string&, const std::string& = "", double = 0 ); - // std::vector callHook( const std::string&, const std::string& = "" ); - // std::size_t addHook( const std::string&, const uf::HookHandler::Readable::function_t& ); void queueHook( const std::string&, const ext::json::Value& = ext::json::null(), double = 0 ); - // std::vector callHook( const std::string&, const ext::json::Value& = ext::json::null() ); uf::Hooks::return_t callHook( const std::string& ); uf::Hooks::return_t callHook( const std::string&, const ext::json::Value& ); uf::Hooks::return_t callHook( const std::string&, const uf::Serializer& ); template size_t addHook( const std::string& name, T function ); - // template uf::Hooks::return_t queueHook( const std::string& name, const T& payload, double = 0 ); template uf::Hooks::return_t callHook( const std::string& name, const T& payload ); std::string grabURI( const std::string& filename, const std::string& root = "" ); diff --git a/engine/inc/uf/engine/object/object.inl b/engine/inc/uf/engine/object/object.inl index d2c080bf..b82bc0e3 100644 --- a/engine/inc/uf/engine/object/object.inl +++ b/engine/inc/uf/engine/object/object.inl @@ -20,8 +20,13 @@ template size_t uf::Object::addHook( const std::string& name, T callback ) { std::string parsed = this->formatHookName( name ); std::size_t id = uf::hooks.addHook( parsed, callback ); - uf::Serializer& metadata = this->getComponent(); - metadata["system"]["hooks"]["alloc"][parsed].emplace_back(id); +#if UF_ENTITY_METADATA_USE_JSON + auto& metadata = this->getComponent(); + metadata["system"]["hooks"]["bound"][parsed].emplace_back(id); +#else + auto& metadata = this->getComponent(); + metadata.hooks.bound[parsed].emplace_back(id); +#endif return id; } template diff --git a/engine/inc/uf/engine/scene/behavior.h b/engine/inc/uf/engine/scene/behavior.h index 39b2c346..efa3e831 100644 --- a/engine/inc/uf/engine/scene/behavior.h +++ b/engine/inc/uf/engine/scene/behavior.h @@ -1,5 +1,12 @@ #pragma once namespace uf { - UF_BEHAVIOR_ENTITY_H(Scene) + namespace SceneBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void UF_API attach( uf::Entity& ); + void UF_API initialize( uf::Object& ); + void UF_API tick( uf::Object& ); + void UF_API render( uf::Object& ); + void UF_API destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/engine/inc/uf/engine/scene/scene.h b/engine/inc/uf/engine/scene/scene.h index 6433cb58..aee073b3 100644 --- a/engine/inc/uf/engine/scene/scene.h +++ b/engine/inc/uf/engine/scene/scene.h @@ -2,6 +2,8 @@ #include +#define UF_SCENE_USE_GRAPH 1 + namespace uf { class UF_API Scene : public uf::Object { public: @@ -19,6 +21,12 @@ namespace uf { namespace scene { extern UF_API std::vector scenes; + extern UF_API std::vector graph; + extern UF_API bool queuedInvalidation; + extern UF_API bool useGraph; + void UF_API invalidateGraph(); + std::vector UF_API generateGraph(); + Scene& UF_API getCurrentScene(); Scene& UF_API loadScene( const std::string& name, const std::string& filename = "" ); Scene& UF_API loadScene( const std::string& name, const uf::Serializer& ); diff --git a/engine/inc/uf/ext/lua/lua.h b/engine/inc/uf/ext/lua/lua.h index 29694911..db8d1f13 100644 --- a/engine/inc/uf/ext/lua/lua.h +++ b/engine/inc/uf/ext/lua/lua.h @@ -4,10 +4,16 @@ #if UF_USE_LUA #if UF_USE_LUAJIT #define SOL_LUAJIT 1 - #define SOL_USING_CXX_LUA_JIT 1 +// #define SOL_USING_CXX_LUA_JIT 1 + #else +// #define SOL_USING_CXX_LUA 1 #endif #define SOL_NO_EXCEPTIONS 1 -#define SOL_ALL_SAFETIES_ON 1 +#if UF_ENV_DREAMCAST + #define SOL_NO_THREAD_LOCAL 1 +#else + #define SOL_ALL_SAFETIES_ON 1 +#endif #include #include diff --git a/engine/inc/uf/ext/lua/lua.inl b/engine/inc/uf/ext/lua/lua.inl index 9d218dfb..be5e8c59 100644 --- a/engine/inc/uf/ext/lua/lua.inl +++ b/engine/inc/uf/ext/lua/lua.inl @@ -29,28 +29,4 @@ namespace {\ } #define UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) #k, v -#define UF_LUA_REGISTER_USERTYPE_MEMBER(member) UF_NS_GET_LAST(member), &member - - -/* -#define UF_NS_LUA_REGISTER_USERTYPE_BEGIN(k, v) {\ - std::string name = #v;\ - sol::usertype usertype = state.new_usertype(name); - -#define POD_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(pod, x) -#define UF_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(uf, x) -#define EXT_LUA_REGISTER_USERTYPE_BEGIN(x) UF_NS_LUA_REGISTER_USERTYPE_BEGIN(ext, x) - -#define UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) usertype[#k] = v; -#define POD_LUA_REGISTER_USERTYPE_DEFINE(k, v) UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) -#define EXT_LUA_REGISTER_USERTYPE_DEFINE(k, v) UF_LUA_REGISTER_USERTYPE_DEFINE(k, v) - -#define UF_NS_LUA_REGISTER_USERTYPE_MEMBER(ns, x, y) UF_LUA_REGISTER_USERTYPE_DEFINE(y, &ns::x::y) -#define POD_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(pod, x, y) -#define UF_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(uf, x, y) -#define EXT_LUA_REGISTER_USERTYPE_MEMBER(x, y) UF_NS_LUA_REGISTER_USERTYPE_MEMBER(ext, x, y) - -#define UF_LUA_REGISTER_USERTYPE_END() } -#define POD_LUA_REGISTER_USERTYPE_END() UF_LUA_REGISTER_USERTYPE_END() -#define EXT_LUA_REGISTER_USERTYPE_END() UF_LUA_REGISTER_USERTYPE_END() -*/ \ No newline at end of file +#define UF_LUA_REGISTER_USERTYPE_MEMBER(member) UF_NS_GET_LAST(member), &member \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/ogl.h b/engine/inc/uf/ext/opengl/ogl.h index 10636ddc..c7853224 100644 --- a/engine/inc/uf/ext/opengl/ogl.h +++ b/engine/inc/uf/ext/opengl/ogl.h @@ -22,10 +22,12 @@ #include #include #include + #include #else #include #include #include + #include #define glIsTexture(x) ( x != 0 ) #endif diff --git a/engine/inc/uf/ext/opengl/texture.h b/engine/inc/uf/ext/opengl/texture.h index b26f8688..9215fe5a 100644 --- a/engine/inc/uf/ext/opengl/texture.h +++ b/engine/inc/uf/ext/opengl/texture.h @@ -51,6 +51,7 @@ namespace ext { enums::Image::type_t type = enums::Image::TYPE_2D; enums::Image::viewType_t viewType = enums::Image::VIEW_TYPE_2D; enums::Format::type_t format = enums::Format::R8G8B8A8_UNORM; + size_t internalFormat = 0; struct Descriptor { GLuint image = GL_NULL_HANDLE; diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index 3c1bb847..9e213cb9 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -28,4 +28,17 @@ #define UF_EXCEPTION(X) UF_ERROR_MSG(X) #else #define UF_EXCEPTION(X) throw std::runtime_error(X) -#endif \ No newline at end of file +#endif + +#define UF_TIMER_TRACE_INIT() uf::Timer TIMER_TRACE; + +#define UF_TIMER_TRACE(X) {\ + auto elapsed = TIMER_TRACE.elapsed().asMilliseconds();\ + if ( elapsed > 0 ) UF_DEBUG_MSG(X << " | " << TIMER_TRACE.elapsed().asMilliseconds() << "ms");\ +} + +#define UF_TIMER_TRACE_RESET(X) {\ + auto elapsed = TIMER_TRACE.elapsed().asMilliseconds();\ + if ( elapsed > 0 ) UF_DEBUG_MSG(X << " | " << TIMER_TRACE.elapsed().asMilliseconds() << "ms");\ + TIMER_TRACE.reset();\ +} diff --git a/engine/inc/uf/spec/controller/controller.h b/engine/inc/uf/spec/controller/controller.h new file mode 100644 index 00000000..89075d44 --- /dev/null +++ b/engine/inc/uf/spec/controller/controller.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +// include universal +#include "universal.h" +// defines which implementation to use +#include UF_ENV_HEADER \ No newline at end of file diff --git a/engine/inc/uf/spec/controller/dreamcast.h b/engine/inc/uf/spec/controller/dreamcast.h new file mode 100644 index 00000000..1a1f30e3 --- /dev/null +++ b/engine/inc/uf/spec/controller/dreamcast.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "universal.h" + +#if UF_ENV_DREAMCAST + +namespace spec { + namespace dreamcast { + namespace controller { + void UF_API initialize(); + void UF_API tick(); + void UF_API terminate(); + + bool UF_API connected( size_t = 0 ); + bool UF_API pressed( const std::string&, size_t = 0 ); + float UF_API analog( const std::string&, size_t = 0 ); + } + } + namespace controller = dreamcast::controller; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/spec/controller/universal.h b/engine/inc/uf/spec/controller/universal.h new file mode 100644 index 00000000..024cec32 --- /dev/null +++ b/engine/inc/uf/spec/controller/universal.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace spec { + namespace uni { + namespace controller { + void UF_API initialize(); + void UF_API tick(); + void UF_API terminate(); + + bool UF_API connected( size_t = 0 ); + bool UF_API pressed( const std::string&, size_t = 0 ); + float UF_API analog( const std::string&, size_t = 0 ); + }; + }; +} \ No newline at end of file diff --git a/engine/inc/uf/spec/controller/unknown.h b/engine/inc/uf/spec/controller/unknown.h new file mode 100644 index 00000000..503fad3e --- /dev/null +++ b/engine/inc/uf/spec/controller/unknown.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include "universal.h" + +namespace spec { + namespace controller = uni::controller; +} \ No newline at end of file diff --git a/engine/inc/uf/spec/controller/windows.h b/engine/inc/uf/spec/controller/windows.h new file mode 100644 index 00000000..b0a85336 --- /dev/null +++ b/engine/inc/uf/spec/controller/windows.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "universal.h" + +#if UF_ENV_WINDOWS + +namespace spec { + namespace win32 { + namespace controller { + void UF_API initialize(); + void UF_API tick(); + void UF_API terminate(); + + bool UF_API connected( size_t = 0 ); + bool UF_API pressed( const std::string&, size_t = 0 ); + float UF_API analog( const std::string&, size_t = 0 ); + } + } + namespace controller = win32::controller; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/spec/window/dreamcast.h b/engine/inc/uf/spec/window/dreamcast.h index 09035380..0607d1d1 100644 --- a/engine/inc/uf/spec/window/dreamcast.h +++ b/engine/inc/uf/spec/window/dreamcast.h @@ -64,7 +64,6 @@ namespace spec { void UF_API setTracking(bool state); static pod::Vector2ui UF_API getResolution(); void UF_API switchToFullscreen( bool borderless = false ); - static std::string UF_API getKey(/*WPARAM key, LPARAM flags*/); }; } typedef spec::dreamcast::Window Window; diff --git a/engine/inc/uf/utils/image/image.h b/engine/inc/uf/utils/image/image.h index 976a93f4..43d4c8e9 100644 --- a/engine/inc/uf/utils/image/image.h +++ b/engine/inc/uf/utils/image/image.h @@ -18,6 +18,7 @@ namespace uf { Image::vec2_t m_dimensions; std::size_t m_bpp; std::size_t m_channels; + std::size_t m_format; public: // C-tor Image(); // Default @@ -38,18 +39,27 @@ namespace uf { // Getters void loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false ); void loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false ); + std::string getFilename() const; + Image::container_t& getPixels(); const Image::container_t& getPixels() const; + Image::pixel_t::type_t* getPixelsPtr(); const Image::pixel_t::type_t* getPixelsPtr() const; + Image::vec2_t& getDimensions(); const Image::vec2_t& getDimensions() const; + std::size_t& getBpp(); std::size_t getBpp() const; + std::size_t& getChannels(); std::size_t getChannels() const; + std::string getHash() const; + size_t getFormat() const; + Image::pixel_t at( const Image::vec2_t& at ); // Modifiers void flip(); diff --git a/engine/inc/uf/utils/math/math.h b/engine/inc/uf/utils/math/math.h index f0709b07..48652a58 100644 --- a/engine/inc/uf/utils/math/math.h +++ b/engine/inc/uf/utils/math/math.h @@ -3,6 +3,12 @@ #include #include +#if UF_ENV_DREAMCAST + #include "sh4.h" + #include + #define UF_EZ_VEC4(vec, size) vec[0], size > 1 ? vec[1] : 0, size > 2 ? vec[2] : 0, size > 3 ? vec[3] : 0 +#endif + namespace pod { namespace Math { typedef float num_t; @@ -19,7 +25,7 @@ namespace uf { float UF_API unquantize( uint16_t ); template - T lerp( const T& a, const T& b, double f ) { + inline T lerp( const T& a, const T& b, double f ) { return a + f * (b - a); } } diff --git a/engine/inc/uf/utils/math/matrix.h b/engine/inc/uf/utils/math/matrix.h index 1a718b8d..4d10b851 100644 --- a/engine/inc/uf/utils/math/matrix.h +++ b/engine/inc/uf/utils/math/matrix.h @@ -63,7 +63,7 @@ namespace uf { template pod::Matrix multiply( const pod::Matrix& left, const pod::Matrix& right ); // Multiplies two matrices of same type and size together template T /*UF_API*/ transpose( const T& matrix ); // Flip sign of all components template T /*UF_API*/ inverse( const T& matrix ); // Flip sign of all components - template pod::Vector3t multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector ); + template pod::Vector3t multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector, T w = 1 ); template pod::Vector4t multiply( const pod::Matrix4t& mat, const pod::Vector4t& vector ); template T /*UF_API*/ multiplyAll( const T& matrix, typename T::type_t scalar ); diff --git a/engine/inc/uf/utils/math/matrix/pod.inl b/engine/inc/uf/utils/math/matrix/pod.inl index 7728fc1f..651a29fa 100644 --- a/engine/inc/uf/utils/math/matrix/pod.inl +++ b/engine/inc/uf/utils/math/matrix/pod.inl @@ -170,6 +170,16 @@ template pod::Matrix uf::matrix::multiply( const pod::Matrix< uf::simd::store(row, &res[4*i]); } return res; +#elif UF_ENV_DREAMCAST +// kallistios has dedicated SH4 asm for these or something + mat_load( (matrix_t*) &left[0] ); + mat_apply( (matrix_t*) &right[0] ); + mat_store( (matrix_t*) &res[0]); + +// gives very wrong output, not sure why +// MATH_Load_Matrix_Product( (ALL_FLOATS_STRUCT*) &left[0], (ALL_FLOATS_STRUCT*) &right[0] ); +// MATH_Store_XMTRX( (ALL_FLOATS_STRUCT*) &res[0]); + return res; #elif 1 // float* dstPtr = &res[0]; @@ -400,15 +410,15 @@ template T uf::matrix::inverse( const T& matrix ) { template pod::Matrix uf::matrix::multiply( T& left, const T& right ) { return left = uf::matrix::multiply((const T&) left, right); } -template pod::Vector3t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector ) { - return { - vector[0] * mat[0] + vector[1] * mat[4] + vector[2] * mat[8] + vector[3] * mat[12], - vector[0] * mat[1] + vector[1] * mat[5] + vector[2] * mat[9] + vector[3] * mat[13], - vector[0] * mat[2] + vector[1] * mat[6] + vector[2] * mat[10] + vector[3] * mat[14] - // vector[0] * mat[3] + vector[1] * mat[7] + vector[2] * mat[11] + vector[3] * mat[15] - }; +template pod::Vector3t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector3t& vector, T w ) { + return uf::matrix::multiply( mat, pod::Vector4t{ vector[0], vector[1], vector[2], w } ); } template pod::Vector4t uf::matrix::multiply( const pod::Matrix4t& mat, const pod::Vector4t& vector ) { +#if UF_ENV_DREAMCAST + MATH_Load_XMTRX( (ALL_FLOATS_STRUCT*) &mat[0] ); + auto res = MATH_Matrix_Transform( vector[0], vector[1], vector[2], vector[3] ); + return *((pod::Vector4t*) &res); +#endif return { vector[0] * mat[0] + vector[1] * mat[4] + vector[2] * mat[8] + vector[3] * mat[12], vector[0] * mat[1] + vector[1] * mat[5] + vector[2] * mat[9] + vector[3] * mat[13], diff --git a/engine/inc/uf/utils/math/sh4.h b/engine/inc/uf/utils/math/sh4.h new file mode 100644 index 00000000..425686b0 --- /dev/null +++ b/engine/inc/uf/utils/math/sh4.h @@ -0,0 +1,2194 @@ +// ---- sh4_math.h - SH7091 Math Module ---- +// +// Version 1.1.4 +// +// This file is part of the DreamHAL project, a hardware abstraction library +// primarily intended for use on the SH7091 found in hardware such as the SEGA +// Dreamcast game console. +// +// This math module is hereby released into the public domain in the hope that it +// may prove useful. Now go hit 60 fps! :) +// +// --Moopthehedgehog, January 2020 +// + +// Notes: +// - GCC 4 users have a different return type for the fsca functions due to an +// internal compiler error regarding complex numbers; no issue under GCC 9.2.0 +// - Using -m4 instead of -m4-single-only completely breaks the matrix and +// vector operations +// - Function inlining must be enabled and not blocked by compiler options such +// as -ffunction-sections, as blocking inlining will result in significant +// performance degradation for the vector and matrix functions employing a +// RETURN_VECTOR_STRUCT return type. I have added compiler hints and attributes +// "static inline __attribute__((always_inline))" to mitigate this, so in most +// cases the functions should be inlined regardless. If in doubt, check the +// compiler asm output! +// + +#ifndef __SH4_MATH_H_ +#define __SH4_MATH_H_ + +#define GNUC_FSCA_ERROR_VERSION 4 + +// +// Fast SH4 hardware math functions +// +// +// High-accuracy users beware, the fsrra functions have an error of +/- 2^-21 +// per http://www.shared-ptr.com/sh_insns.html +// + +//============================================================================== +// Definitions +//============================================================================== +// +// Structures, useful definitions, and reference comments +// + +// Front matrix format: +// +// FV0 FV4 FV8 FV12 +// --- --- --- ---- +// [ fr0 fr4 fr8 fr12 ] +// [ fr1 fr5 fr9 fr13 ] +// [ fr2 fr6 fr10 fr14 ] +// [ fr3 fr7 fr11 fr15 ] +// +// Back matrix, XMTRX, is similar, although it has no FVn vector groups: +// +// [ xf0 xf4 xf8 xf12 ] +// [ xf1 xf5 xf9 xf13 ] +// [ xf2 xf6 xf10 xf14 ] +// [ xf3 xf7 xf11 xf15 ] +// + +// This struct must be 32-byte aligned to ensure it only crosses 1 cacheline +// boundary, as it is exactly 64 bytes in size. +typedef struct __attribute__((aligned(32))) { + float fr0; + float fr1; + float fr2; + float fr3; + float fr4; + float fr5; + float fr6; + float fr7; + float fr8; + float fr9; + float fr10; + float fr11; + float fr12; + float fr13; + float fr14; + float fr15; +} ALL_FLOATS_STRUCT; + +// Return structs should be defined locally so that GCC optimizes them into +// register usage instead of memory accesses. +typedef struct { + float z1; + float z2; + float z3; + float z4; +} RETURN_VECTOR_STRUCT; + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION +typedef struct { + float sine; + float cosine; +} RETURN_FSCA_STRUCT; +#endif + +// Identity Matrix +// +// FV0 FV4 FV8 FV12 +// --- --- --- ---- +// [ 1 0 0 0 ] +// [ 0 1 0 0 ] +// [ 0 0 1 0 ] +// [ 0 0 0 1 ] +// + +static const ALL_FLOATS_STRUCT MATH_identity_matrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + +// Constants +#define MATH_pi 3.14159265358979323846264338327950288419716939937510f +#define MATH_e 2.71828182845904523536028747135266249775724709369995f +#define MATH_phi 1.61803398874989484820458683436563811772030917980576f + +//============================================================================== +// Basic math functions +//============================================================================== +// +// The following functions are available. +// Please see their definitions for other usage info, otherwise they may not +// work for you. +// +/* + // |x| + float MATH_fabs(float x) + + // sqrt(x) + // NOTE: There is a much faster version (MATH_Fast_Sqrt()) in the fsrra section of + // this file. Chances are you probably want that one. + float MATH_fsqrt(float x) + + // a*b+c + float MATH_fmac(float a, float b, float c) + + // a*b-c + float MATH_fmac_Dec(float a, float b, float c) + + // fminf() - return the min of two floats + // This doesn't check for NaN + float MATH_Fast_Fminf(float a, float b) + + // fmaxf() - return the max of two floats + // This doesn't check for NaN + float MATH_Fast_Fmaxf(float a, float b) + + // Fast floorf() - return the nearest integer <= x as a float + // This doesn't check for NaN + float MATH_Fast_Floorf(float x) + + // Fast ceilf() - return the nearest integer >= x as a float + // This doesn't check for NaN + float MATH_Fast_Ceilf(float x) + + // Very fast floorf() - return the nearest integer <= x as a float + // Inspired by a cool trick I came across here: + // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions + // This doesn't check for NaN + float MATH_Very_Fast_Floorf(float x) + + // Very fast ceilf() - return the nearest integer >= x as a float + // Inspired by a cool trick I came across here: + // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions + // This doesn't check for NaN + float MATH_Very_Fast_Ceilf(float x) +*/ + +// |x| +// This one works on ARM and x86, too! +static inline __attribute__((always_inline)) float MATH_fabs(float x) +{ + asm volatile ("fabs %[floatx]\n" + : [floatx] "+f" (x) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + return x; +} + +// sqrt(x) +// This one works on ARM and x86, too! +// NOTE: There is a much faster version (MATH_Fast_Sqrt()) in the fsrra section of +// this file. Chances are you probably want that one. +static inline __attribute__((always_inline)) float MATH_fsqrt(float x) +{ + asm volatile ("fsqrt %[floatx]\n" + : [floatx] "+f" (x) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + return x; +} + +// a*b+c +static inline __attribute__((always_inline)) float MATH_fmac(float a, float b, float c) +{ + asm volatile ("fmac fr0, %[floatb], %[floatc]\n" + : [floatc] "+f" (c) // outputs, "+" means r/w + : "w" (a), [floatb] "f" (b) // inputs + : // no clobbers + ); + + return c; +} + +// a*b-c +static inline __attribute__((always_inline)) float MATH_fmac_Dec(float a, float b, float c) +{ + asm volatile ("fneg %[floatc]\n\t" + "fmac fr0, %[floatb], %[floatc]\n" + : [floatc] "+&f" (c) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed + : "w" (a), [floatb] "f" (b) // inputs + : // no clobbers + ); + + return c; +} + +// Fast fminf() - return the min of two floats +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Fast_Fminf(float a, float b) +{ + float output_float; + + asm volatile ( + "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) + "bt.s 1f\n\t" // yes, a is smaller + " fmov %[floata], %[float_out]\n\t" // so return a + "fmov %[floatb], %[float_out]\n" // no, either b is smaller or they're equal and it doesn't matter + "1:\n" + : [float_out] "=&f" (output_float) // outputs + : [floata] "f" (a), [floatb] "f" (b) // inputs + : "t" // clobbers + ); + + return output_float; +} + +// Fast fmaxf() - return the max of two floats +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Fast_Fmaxf(float a, float b) +{ + float output_float; + + asm volatile ( + "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) + "bt.s 1f\n\t" // yes, a is smaller + " fmov %[floatb], %[float_out]\n\t" // so return b + "fmov %[floata], %[float_out]\n" // no, either a is bigger or they're equal and it doesn't matter + "1:\n" + : [float_out] "=&f" (output_float) // outputs + : [floata] "f" (a), [floatb] "f" (b) // inputs + : "t" // clobbers + ); + + return output_float; +} + +// Fast floorf() - return the nearest integer <= x as a float +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Fast_Floorf(float x) +{ + float output_float; + + // To hold -1.0f + float minus_one; + + asm volatile ( + "fldi1 %[minus_1]\n\t" + "fneg %[minus_1]\n\t" + "fcmp/gt %[minus_1], %[floatx]\n\t" // x >= 0 + "ftrc %[floatx], fpul\n\t" // convert float to int + "bt.s 1f\n\t" + " float fpul, %[float_out]\n\t" // convert int to float + "fadd %[minus_1], %[float_out]\n" // if input x < 0, subtract 1.0 + "1:\n" + : [minus_1] "=&f" (minus_one), [float_out] "=f" (output_float) + : [floatx] "f" (x) + : "fpul", "t" + ); + + return output_float; +} + +// Fast ceilf() - return the nearest integer >= x as a float +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Fast_Ceilf(float x) +{ + float output_float; + + // To hold 0.0f and 1.0f + float zero_one; + + asm volatile ( + "fldi0 %[zero_1]\n\t" + "fcmp/gt %[zero_1], %[floatx]\n\t" // x > 0 + "ftrc %[floatx], fpul\n\t" // convert float to int + "bf.s 1f\n\t" + " float fpul, %[float_out]\n\t" // convert int to float + "fldi1 %[zero_1]\n\t" + "fadd %[zero_1], %[float_out]\n" // if input x > 0, add 1.0 + "1:\n" + : [zero_1] "=&f" (zero_one), [float_out] "=f" (output_float) + : [floatx] "f" (x) + : "fpul", "t" + ); + + return output_float; +} + +// Very fast floorf() - return the nearest integer <= x as a float +// Inspired by a cool trick I came across here: +// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Very_Fast_Floorf(float x) +{ + float output_float; + unsigned int scratch_reg; + unsigned int scratch_reg2; + + // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f + // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) + + // floor = (float)( (int)(x + (float)2^31) - 2^31) + + asm volatile ( + "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) + "shll16 %[scratch]\n\t" // (EX) + "shll8 %[scratch]\n\t" // (EX) + "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) + "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) + "fsts fpul, %[float_out]\n\t" // (LS) + "fadd %[floatx], %[float_out]\n\t" // float-add float INT_MAX + 1 to x (FE) + "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) + "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo + "sts fpul, %[scratch]\n\t" // move back to int regs (LS) + "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) + "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo + "float fpul, %[float_out]\n" // convert back to float (FE) + : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) + : [floatx] "f" (x) + : "fpul", "t" + ); + + return output_float; +} + +// Very fast ceilf() - return the nearest integer >= x as a float +// Inspired by a cool trick I came across here: +// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions +// This doesn't check for NaN +static inline __attribute__((always_inline)) float MATH_Very_Fast_Ceilf(float x) +{ + float output_float; + unsigned int scratch_reg; + unsigned int scratch_reg2; + + // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f + // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) + + // Ceiling is the inverse of floor such that f^-1(x) = -f(-x) + // To make very fast ceiling have as wide a range as very fast floor, + // use this property to subtract x from INT_MAX + 1 and get the negative of the + // ceiling, and then negate the final output. This allows ceiling to use + // -2^31 and have the same range as very fast floor. + + // Given: + // floor = (float)( (int)(x + (float)2^31) - 2^31 ) + // We can do: + // ceiling = -( (float)( (int)((float)2^31 - x) - 2^31 ) ) + // or (slower on SH4 since 'fneg' is faster than 'neg'): + // ceiling = (float) -( (int)((float)2^31 - x) - 2^31 ) + // Since mathematically these functions are related by f^-1(x) = -f(-x). + + asm volatile ( + "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) + "shll16 %[scratch]\n\t" // (EX) + "shll8 %[scratch]\n\t" // (EX) + "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) + "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) + "fsts fpul, %[float_out]\n\t" // (LS) + "fsub %[floatx], %[float_out]\n\t" // float-sub x from float INT_MAX + 1 (FE) + "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) + "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo + "sts fpul, %[scratch]\n\t" // move back to int regs (LS) + "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) + "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo + "float fpul, %[float_out]\n\t" // convert back to float (FE) + "fneg %[float_out]\n" + : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) + : [floatx] "f" (x) + : "fpul", "t" + ); + + return output_float; +} + +//============================================================================== +// Fun with fsrra, which does 1/sqrt(x) in one cycle +//============================================================================== +// +// Error of 'fsrra' is +/- 2^-21 per http://www.shared-ptr.com/sh_insns.html +// +// The following functions are available. +// Please see their definitions for other usage info, otherwise they may not +// work for you. +// +/* + // 1/sqrt(x) + float MATH_fsrra(float x) + + // 1/x + // 1.0f / sqrt(x^2) + // Maximum value is sqrt(max 32-bit float) due to the squaring, as fsrra can't do negatives + // See MATH_Fast_Invert_Full() for a version that's 4 cycles slower, but allows for the full + // range of floating point numbers as input + float MATH_Fast_Invert(float x) + + // 1/x + // 1.0f / sqrt(x)^2 + // Though slower than MATH_FAST_Invert(), this can take the full range of floats as input + float MATH_Fast_Invert_Full(float x) + + // 1/x + // 1.0f / sqrt(x)^2 + // This is the fastest way to invert, but it only works for positive input (full range of positive input floats) + float MATH_Very_Fast_Invert(float x) + + // A faster divide than the 'fdiv' instruction + float MATH_Fast_Divide(float numerator, float denominator) + + // A faster square root then the 'fsqrt' instruction + float MATH_Fast_Sqrt(float x) + + // Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. + float MATH_Slow_Divide(float numerator, float denominator) +*/ + +// 1/sqrt(x) +static inline __attribute__((always_inline)) float MATH_fsrra(float x) +{ + asm volatile ("fsrra %[one_div_sqrt]\n" + : [one_div_sqrt] "+f" (x) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + return x; +} + +// 1/x +// 1.0f / sqrt(x^2) +// Maximum value is sqrt(max 32-bit float) due to the squaring, as fsrra can't do negatives +// See MATH_Fast_Invert_Full() for a version that's 4 cycles slower, but allows for the full +// range of floating point numbers as input +static inline __attribute__((always_inline)) float MATH_Fast_Invert(float x) +{ + int neg = 0; + + if(x < 0.0f) + { + neg = 1; + } + + x = MATH_fsrra(x*x); // 1.0f / sqrt(x^2) + + if(neg) + { + return -x; + } + else + { + return x; + } +} + +// 1/x +// 1.0f / sqrt(x)^2 +// Though slower than MATH_FAST_Invert(), this can take the full range of floats as input +static inline __attribute__((always_inline)) float MATH_Fast_Invert_Full(float x) +{ + int neg = 0; + + if(x < 0.0f) + { + neg = 1; + x *= -1.0f; // Make it positive + } + + x = MATH_fsrra(x); // 1.0f / sqrt(x) + x = x*x; // Square it + + if(neg) + { + return -x; + } + else + { + return x; + } +} + +// 1/x +// 1.0f / sqrt(x)^2 +// This is the fastest way to invert, but it only works for positive input (full range of positive input floats) +// Negative inputs will result in a very bad day of debugging +static inline __attribute__((always_inline)) float MATH_Very_Fast_Invert(float x) +{ + x = MATH_fsrra(x); + return x*x; +} + +// It's faster to do this than to use 'fdiv'. +// Only fdiv can do doubles, however. +// Of course, not having to divide at all is generally the best way to go. :P +static inline __attribute__((always_inline)) float MATH_Fast_Divide(float numerator, float denominator) +{ + denominator = MATH_Fast_Invert(denominator); + return numerator * denominator; +} + +// fast sqrt(x) +// Crazy thing: invert(fsrra(x)) is actually about 3x faster than fsqrt. +static inline __attribute__((always_inline)) float MATH_Fast_Sqrt(float x) +{ + return MATH_Fast_Invert(MATH_fsrra(x)); +} + +// Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. +// This DOES work on negatives. +static inline __attribute__((always_inline)) float MATH_Slow_Divide(float numerator, float denominator) +{ + asm volatile ("fdiv %[div_denom], %[div_numer]\n" + : [div_numer] "+f" (numerator) // outputs, "+" means r/w + : [div_denom] "f" (denominator) // inputs + : // clobbers + ); + + return numerator; +} + +//============================================================================== +// Fun with fsca, which does simultaneous sine and cosine in 3 cycles +//============================================================================== +// +// NOTE: GCC 4.7 has a bug that prevents it from working with fsca and complex +// numbers in m4-single-only mode, so GCC 4 users will get a RETURN_FSCA_STRUCT +// instead of a _Complex float. This may be much slower in some instances. +// +// VERY IMPORTANT USAGE INFORMATION (sine and cosine functions): +// +// Due to the nature in which the fsca instruction behaves, you MUST do the +// following in your code to get sine and cosine from these functions: +// +// _Complex float sine_cosine = [Call the fsca function here] +// float sine_value = __real__ sine_cosine; +// float cosine_value = __imag__ sine_cosine; +// Your output is now in sine_value and cosine_value. +// +// This is necessary because fsca outputs both sine and cosine simultaneously +// and uses a double register to do so. The fsca functions do not actually +// return a double--they return two floats--and using a complex float here is +// just a bit of hacking the C language to make GCC do something that's legal in +// assembly according to the SH4 calling convention (i.e. multiple return values +// stored in floating point registers FR0-FR3). This is better than using a +// struct of floats for optimization purposes--this will operate at peak +// performance even at -O0, whereas a struct will not be fast at low +// optimization levels due to memory accesses. +// +// Technically you may be able to use the complex return values as a complex +// number if you wanted to, but that's probably not what you're after and they'd +// be flipped anyways (in mathematical convention, sine is the imaginary part). +// + +// Notes: +// - From http://www.shared-ptr.com/sh_insns.html: +// The input angle is specified as a signed fraction in twos complement. +// The result of sin and cos is a single-precision floating-point number. +// 0x7FFFFFFF to 0x00000001: 360×2^15−360/2^16 to 360/2^16 degrees +// 0x00000000: 0 degree +// 0xFFFFFFFF to 0x80000000: −360/2^16 to −360×2^15 degrees +// - fsca format is 2^16 is 360 degrees, so a value of 1 is actually +// 1/182.044444444 of a degree or 1/10430.3783505 of a radian +// - fsca does a %360 automatically for values over 360 degrees +// +// Also: +// In order to make the best use of fsca units, a program must expect them from +// the outset and not "make them" by dividing radians or degrees to get them, +// otherwise it's just giving the 'fsca' instruction radians or degrees! +// + +// The following functions are available. +// Please see their definitions for other usage info, otherwise they may not +// work for you. +// +/* + // For integer input in native fsca units (fastest) + _Complex float MATH_fsca_Int(unsigned int input_int) + + // For integer input in degrees + _Complex float MATH_fsca_Int_Deg(unsigned int input_int) + + // For integer input in radians + _Complex float MATH_fsca_Int_Rad(unsigned int input_int) + + // For float input in native fsca units + _Complex float MATH_fsca_Float(float input_float) + + // For float input in degrees + _Complex float MATH_fsca_Float_Deg(float input_float) + + // For float input in radians + _Complex float MATH_fsca_Float_Rad(float input_float) +*/ + +//------------------------------------------------------------------------------ +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION +//------------------------------------------------------------------------------ +// +// This set of fsca functions is specifically for old versions of GCC. +// See later for functions for newer versions of GCC. +// + +// +// Integer input (faster) +// + +// For int input, input_int is in native fsca units (fastest) +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int(unsigned int input_int) +{ + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +// For int input, input_int is in degrees +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Deg(unsigned int input_int) +{ + // normalize whole number input degrees to fsca format + input_int = ((1527099483ULL * input_int) >> 23); + + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +// For int input, input_int is in radians +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Rad(unsigned int input_int) +{ + // normalize whole number input rads to fsca format + input_int = ((2734261102ULL * input_int) >> 18); + + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +// +// Float input (slower) +// + +// For float input, input_float is in native fsca units +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float(float input_float) +{ + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +// For float input, input_float is in degrees +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Deg(float input_float) +{ + input_float *= 182.044444444f; + + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +// For float input, input_float is in radians +static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Rad(float input_float) +{ + input_float *= 10430.3783505f; + + register float __sine __asm__("fr0"); + register float __cosine __asm__("fr1"); + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine + : "=w" (__sine), "=f" (__cosine) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + RETURN_FSCA_STRUCT output = {__sine, __cosine}; + return output; +} + +//------------------------------------------------------------------------------ +#else +//------------------------------------------------------------------------------ +// +// This set of fsca functions is specifically for newer versions of GCC. They +// work fine under GCC 9.2.0. +// + +// +// Integer input (faster) +// + +// For int input, input_int is in native fsca units (fastest) +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int(unsigned int input_int) +{ + _Complex float output; + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + return output; +} + +// For int input, input_int is in degrees +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Deg(unsigned int input_int) +{ + // normalize whole number input degrees to fsca format + input_int = ((1527099483ULL * input_int) >> 23); + + _Complex float output; + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + return output; +} + +// For int input, input_int is in radians +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Rad(unsigned int input_int) +{ + // normalize whole number input rads to fsca format + input_int = ((2734261102ULL * input_int) >> 18); + + _Complex float output; + + asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "r" (input_int) // inputs + : "fpul" // clobbers + ); + + return output; +} + +// +// Float input (slower) +// + +// For float input, input_float is in native fsca units +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float(float input_float) +{ + _Complex float output; + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + return output; +} + +// For float input, input_float is in degrees +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Deg(float input_float) +{ + input_float *= 182.044444444f; + + _Complex float output; + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + return output; +} + +// For float input, input_float is in radians +static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Rad(float input_float) +{ + input_float *= 10430.3783505f; + + _Complex float output; + + asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles + "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine + : [out] "=d" (output) // outputs + : [input_number] "f" (input_float) // inputs + : "fpul" // clobbers + ); + + return output; +} + +//------------------------------------------------------------------------------ +#endif +//------------------------------------------------------------------------------ + +//============================================================================== +// Hardware vector and matrix operations +//============================================================================== +// +// These functions each have very specific usage instructions. Please be sure to +// read them before use or else they won't seem to work right! +// +// The following functions are available. +// Please see their definitions for important usage info, otherwise they may not +// work for you. +// +/* + //------------------------------------------------------------------------------ + // Vector and matrix math operations + //------------------------------------------------------------------------------ + + // Inner/dot product (4x1 vec . 4x1 vec = scalar) + float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) + + // Sum of Squares (w^2 + x^2 + y^2 + z^2) + float MATH_Sum_of_Squares(float w, float x, float y, float z) + + // Cross product with bonus multiply (vec X vec = orthogonal vec, with an extra a*b=c) + RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) + + // Cross product (vec X vec = orthogonal vec) + RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) + + // Outer product (vec (X) vec = 4x4 matrix) + void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) + + // Matrix transform (4x4 matrix * 4x1 vec = 4x1 vec) + RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) + + // 4x4 Matrix transpose (XMTRX^T) + void MATH_Matrix_Transpose(void) + + // 4x4 Matrix product (XMTRX and one from memory) + void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) + + // 4x4 Matrix product (two from memory) + void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) + + //------------------------------------------------------------------------------ + // Matrix load and store operations + //------------------------------------------------------------------------------ + + // Load 4x4 XMTRX from memory + void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) + + // Store 4x4 XMTRX to memory + ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) + + // Get 4x1 column vector from XMTRX + RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) + + // Get 2x2 matrix from XMTRX quadrant + RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) +*/ + +//------------------------------------------------------------------------------ +// Vector and matrix math operations +//------------------------------------------------------------------------------ + +// Inner/dot product: vec . vec = scalar +// _ _ +// | y1 | +// [ x1 x2 x3 x4 ] . | y2 | = scalar +// | y3 | +// |_ y4 _| +// +// SH4 calling convention states we get 8 float arguments. Perfect! +static inline __attribute__((always_inline)) float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) +{ + // FR4-FR11 are the regs that are passed in, aka vectors FV4 and FV8. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tx1 = x1; + float tx2 = x2; + float tx3 = x3; + float tx4 = x4; + + float ty1 = y1; + float ty2 = y2; + float ty3 = y3; + float ty4 = y4; + + // vector FV4 + register float __x1 __asm__("fr4") = tx1; + register float __x2 __asm__("fr5") = tx2; + register float __x3 __asm__("fr6") = tx3; + register float __x4 __asm__("fr7") = tx4; + + // vector FV8 + register float __y1 __asm__("fr8") = ty1; + register float __y2 __asm__("fr9") = ty2; + register float __y3 __asm__("fr10") = ty3; + register float __y4 __asm__("fr11") = ty4; + + // take care of all the floats in one fell swoop + asm volatile ("fipr FV4, FV8\n" + : "+f" (__y4) // output (gets written to FR11) + : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3) // inputs + : // clobbers + ); + + return __y4; +} + +// Sum of Squares +// _ _ +// | w | +// [ w x y z ] . | x | = w^2 + x^2 + y^2 + z^2 = scalar +// | y | +// |_ z _| +// +static inline __attribute__((always_inline)) float MATH_Sum_of_Squares(float w, float x, float y, float z) +{ + // FR4-FR7 are the regs that are passed in, aka vector FV4. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tw = w; + float tx = x; + float ty = y; + float tz = z; + + // vector FV4 + register float __w __asm__("fr4") = tw; + register float __x __asm__("fr5") = tx; + register float __y __asm__("fr6") = ty; + register float __z __asm__("fr7") = tz; + + // take care of all the floats in one fell swoop + asm volatile ("fipr FV4, FV4\n" + : "+f" (__z) // output (gets written to FR7) + : "f" (__w), "f" (__x), "f" (__y) // inputs + : // clobbers + ); + + return __z; +} + +// Cross product: vec X vec = orthogonal vec +// _ _ _ _ _ _ +// | x1 | | y1 | | z1 | +// | x2 | X | y2 | = | z2 | +// |_ x3 _| |_ y3 _| |_ z3 _| +// +// With bonus multiply: +// +// a * b = c +// +// IMPORTANT USAGE INFORMATION (cross product): +// +// Return vector struct maps as below to the above diagram: +// +// typedef struct { +// float z1; +// float z2; +// float z3; +// float z4; // c is stored in z4, and c = a*b if using 'with mult' version (else c = 0) +// } RETURN_VECTOR_STRUCT; +// +// For people familiar with the unit vector notation, z1 == 'i', z2 == 'j', +// and z3 == 'k'. +// +// The cross product matrix will also be stored in XMTRX after this, so calling +// MATH_Matrix_Transform() on a vector after using this function will do a cross +// product with the same x1-x3 values and a multiply with the same 'a' value +// as used in this function. In this a situation, 'a' will be multiplied with +// the x4 parameter of MATH_Matrix_Transform(). a = 0 if not using the 'with mult' +// version of the cross product function. +// +// For reference, XMTRX will look like this: +// +// [ 0 -x3 x2 0 ] +// [ x3 0 -x1 0 ] +// [ -x2 x1 0 0 ] +// [ 0 0 0 a ] (<-- a = 0 if not using 'with mult') +// +// Similarly to how the sine and cosine functions use fsca and return 2 floats, +// the cross product functions actually return 4 floats. The first 3 are the +// cross product output, and the 4th is a*b. The SH4 only multiplies 4x4 +// matrices with 4x1 vectors, which is why the output is like that--but it means +// we also get a bonus float multiplication while we do our cross product! +// + +// Please do not call this function directly (notice the weird syntax); call +// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product_with_Mult(float x3, float a, float y3, float b, float x2, float x1, float y1, float y2) +{ + // FR4-FR11 are the regs that are passed in, in that order. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tx1 = x1; + float tx2 = x2; + float tx3 = x3; + float ta = a; + + float ty1 = y1; + float ty2 = y2; + float ty3 = y3; + float tb = b; + + register float __x1 __asm__("fr9") = tx1; // need to negate (need to move to fr6, then negate fr9) + register float __x2 __asm__("fr8") = tx2; // in place for matrix (need to move to fr2 then negate fr2) + register float __x3 __asm__("fr4") = tx3; // need to negate (move to fr1 first, then negate fr4) + register float __a __asm__("fr5") = ta; + + register float __y1 __asm__("fr10") = ty1; + register float __y2 __asm__("fr11") = ty2; + register float __y3 __asm__("fr6") = ty3; + register float __b __asm__("fr7") = tb; + + register float __z1 __asm__("fr0") = 0.0f; // z1 + register float __z2 __asm__("fr1") = 0.0f; // z2 (not moving x3 here yet since a double 0 is needed) + register float __z3 __asm__("fr2") = tx2; // z3 (this handles putting x2 in fr2) + register float __c __asm__("fr3") = 0.0f; // c + + // This actually does a matrix transform to do the cross product. + // It's this: + // _ _ _ _ + // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | + // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | + // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | + // [ 0 0 0 a ] |_ b _| |_ c _| + // + + asm volatile ( + // set up back bank's FV0 + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) + + // Save FR12-FR15, which are supposed to be preserved across functions calls. + // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). + "fmov DR12, XD12\n\t" + "fmov DR14, XD14\n\t" + + "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) + "fmov DR6, XD2\n\t" // fmov 'y3' and 'b' from FR6, FR7 into position (XF2, XF3) + + // pair move zeros for some speed in setting up front bank for matrix + "fmov DR0, DR10\n\t" // clear FR10, FR11 + "fmov DR0, DR12\n\t" // clear FR12, FR13 + "fschg\n\t" // switch back to single moves + // prepare front bank for XMTRX + "fmov FR5, FR15\n\t" // fmov 'a' into position + "fmov FR0, FR14\n\t" // clear out FR14 + "fmov FR0, FR7\n\t" // clear out FR7 + "fmov FR0, FR5\n\t" // clear out FR5 + + "fneg FR2\n\t" // set up 'x2' + "fmov FR9, FR6\n\t" // set up 'x1' + "fneg FR9\n\t" + "fmov FR4, FR1\n\t" // set up 'x3' + "fneg FR4\n\t" + // flip banks and matrix multiply + "frchg\n\t" + "ftrv XMTRX, FV0\n" + : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) + : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__a), "f" (__b) // inputs + : // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) + ); + + RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; + return output; +} + +// Please do not call this function directly (notice the weird syntax); call +// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product(float x3, float zero, float x1, float y3, float x2, float x1_2, float y1, float y2) +{ + // FR4-FR11 are the regs that are passed in, in that order. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tx1 = x1; + float tx2 = x2; + float tx3 = x3; + float tx1_2 = x1_2; + + float ty1 = y1; + float ty2 = y2; + float ty3 = y3; + float tzero = zero; + + register float __x1 __asm__("fr6") = tx1; // in place + register float __x2 __asm__("fr8") = tx2; // in place (fmov to fr2, negate fr2) + register float __x3 __asm__("fr4") = tx3; // need to negate (fmov to fr1, negate fr4) + + register float __zero __asm__("fr5") = tzero; // in place + register float __x1_2 __asm__("fr9") = tx1_2; // need to negate + + register float __y1 __asm__("fr10") = ty1; + register float __y2 __asm__("fr11") = ty2; + // no __y3 needed in this function + + register float __z1 __asm__("fr0") = tzero; // z1 + register float __z2 __asm__("fr1") = tzero; // z2 + register float __z3 __asm__("fr2") = ty3; // z3 + register float __c __asm__("fr3") = tzero; // c + + // This actually does a matrix transform to do the cross product. + // It's this: + // _ _ _ _ + // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | + // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | + // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | + // [ 0 0 0 0 ] |_ 0 _| |_ 0 _| + // + + asm volatile ( + // zero out FR7. For some reason, if this is done in C after __z3 is set: + // register float __y3 __asm__("fr7") = tzero; + // then GCC will emit a spurious stack push (pushing FR12). So just zero it here. + "fmov FR5, FR7\n\t" + // set up back bank's FV0 + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) + + // Save FR12-FR15, which are supposed to be preserved across functions calls. + // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). + "fmov DR12, XD12\n\t" + "fmov DR14, XD14\n\t" + + "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) + "fmov DR2, XD2\n\t" // fmov 'y3' and '0' from FR2, FR3 into position (XF2, XF3) + + // pair move zeros for some speed in setting up front bank for matrix + "fmov DR0, DR10\n\t" // clear FR10, FR11 + "fmov DR0, DR12\n\t" // clear FR12, FR13 + "fmov DR0, DR14\n\t" // clear FR14, FR15 + "fschg\n\t" // switch back to single moves + // prepare front bank for XMTRX + "fneg FR9\n\t" // set up 'x1' + "fmov FR8, FR2\n\t" // set up 'x2' + "fneg FR2\n\t" + "fmov FR4, FR1\n\t" // set up 'x3' + "fneg FR4\n\t" + // flip banks and matrix multiply + "frchg\n\t" + "ftrv XMTRX, FV0\n" + : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) + : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__zero), "f" (__x1_2) // inputs + : "fr7" // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) + ); + + RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; + return output; +} + +//------------------------------------------------------------------------------ +// Functions that wrap the xMATH_do_Cross_Product[_with_Mult]() functions to make +// it easier to organize parameters +//------------------------------------------------------------------------------ + +// Cross product with a bonus float multiply (c = a * b) +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) +{ + return xMATH_do_Cross_Product_with_Mult(x3, a, y3, b, x2, x1, y1, y2); +} + +// Plain cross product; does not use the bonus float multiply (c = 0 and a in the cross product matrix will be 0) +// This is a tiny bit faster than 'with_mult' (about 2 cycles faster) +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) +{ + return xMATH_do_Cross_Product(x3, 0.0f, x1, y3, x2, x1, y1, y2); +} + +// Outer product: vec (X) vec = matrix +// _ _ +// | x1 | +// | x2 | (X) [ y1 y2 y3 y4 ] = 4x4 matrix +// | x3 | +// |_ x4 _| +// +// This returns the floats in the back bank (XF0-15), which are inaccessible +// outside of using frchg or paired-move fmov. It's meant to set up a matrix for +// use with other matrix functions. GCC also does not touch the XFn bank. +// This will also wipe out anything stored in the float registers, as it uses the +// whole FPU register file (all 32 of the float registers). +static inline __attribute__((always_inline)) void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) +{ + // FR4-FR11 are the regs that are passed in, in that order. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tx1 = x1; + float tx2 = x2; + float tx3 = x3; + float tx4 = x4; + + float ty1 = y1; + float ty2 = y2; + float ty3 = y3; + float ty4 = y4; + + // vector FV4 + register float __x1 __asm__("fr4") = tx1; + register float __x2 __asm__("fr5") = tx2; + register float __x3 __asm__("fr6") = tx3; + register float __x4 __asm__("fr7") = tx4; + + // vector FV8 + register float __y1 __asm__("fr8") = ty1; + register float __y2 __asm__("fr9") = ty2; + register float __y3 __asm__("fr10") = ty3; // in place already + register float __y4 __asm__("fr11") = ty4; + + // This actually does a 4x4 matrix multiply to do the outer product. + // It's this: + // + // [ x1 x1 x1 x1 ] [ y1 0 0 0 ] [ x1y1 x1y2 x1y3 x1y4 ] + // [ x2 x2 x2 x2 ] [ 0 y2 0 0 ] = [ x2y1 x2y2 x2y3 x2y4 ] + // [ x3 x3 x3 x3 ] [ 0 0 y3 0 ] [ x3y1 x3y2 x3y3 x3y4 ] + // [ x4 x4 x4 x4 ] [ 0 0 0 y4 ] [ x4y1 x4y2 x4y3 x4y4 ] + // + + asm volatile ( + // zero out unoccupied front floats to make a double 0 in DR2 + "fldi0 FR2\n\t" + "fmov FR2, FR3\n\t" + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) + // fmov 'x1' and 'x2' from FR4, FR5 into position (XF0,4,8,12, XF1,5,9,13) + "fmov DR4, XD0\n\t" + "fmov DR4, XD4\n\t" + "fmov DR4, XD8\n\t" + "fmov DR4, XD12\n\t" + // fmov 'x3' and 'x4' from FR6, FR7 into position (XF2,6,10,14, XF3,7,11,15) + "fmov DR6, XD2\n\t" + "fmov DR6, XD6\n\t" + "fmov DR6, XD10\n\t" + "fmov DR6, XD14\n\t" + // set up front floats (y1-y4) + "fmov DR8, DR0\n\t" + "fmov DR8, DR4\n\t" + "fmov DR10, DR14\n\t" + // finish zeroing out front floats + "fmov DR2, DR6\n\t" + "fmov DR2, DR8\n\t" + "fmov DR2, DR12\n\t" + "fschg\n\t" // switch back to single-move mode + // zero out remaining values and matrix multiply 4x4 + "fmov FR2, FR1\n\t" + "ftrv XMTRX, FV0\n\t" + + "fmov FR6, FR4\n\t" + "ftrv XMTRX, FV4\n\t" + + "fmov FR8, FR11\n\t" + "ftrv XMTRX, FV8\n\t" + + "fmov FR12, FR14\n\t" + "ftrv XMTRX, FV12\n\t" + // Save output in XF regs + "frchg\n" + : // no outputs + : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__y4) // inputs + : "fr0", "fr1", "fr2", "fr3", "fr12", "fr13", "fr14", "fr15" // clobbers, can't avoid it + ); + // GCC will restore FR12-FR15 from the stack after this, so we really can't keep the output in the front bank. +} + +// Matrix transform: matrix * vector = vector +// _ _ _ _ +// [ ----------- ] | x1 | | z1 | +// [ ---XMTRX--- ] | x2 | = | z2 | +// [ ----------- ] | x3 | | z3 | +// [ ----------- ] |_ x4 _| |_ z4 _| +// +// IMPORTANT USAGE INFORMATION (matrix transform): +// +// Return vector struct maps 1:1 to the above diagram: +// +// typedef struct { +// float z1; +// float z2; +// float z3; +// float z4; +// } RETURN_VECTOR_STRUCT; +// +// Similarly to how the sine and cosine functions use fsca and return 2 floats, +// the matrix transform function actually returns 4 floats. The SH4 only multiplies +// 4x4 matrices with 4x1 vectors, which is why the output is like that. +// +// Multiply a matrix stored in the back bank (XMTRX) with an input vector +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) +{ + // The floats comprising FV4 are the regs that are passed in. + // Just need to make sure GCC doesn't modify anything, and these register vars do that job. + + // Temporary variables are necessary per GCC to avoid clobbering: + // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables + + float tx1 = x1; + float tx2 = x2; + float tx3 = x3; + float tx4 = x4; + + // output vector FV0 + register float __z1 __asm__("fr0") = tx1; + register float __z2 __asm__("fr1") = tx2; + register float __z3 __asm__("fr2") = tx3; + register float __z4 __asm__("fr3") = tx4; + + asm volatile ("ftrv XMTRX, FV0\n\t" + // have to do this to obey SH4 calling convention--output returned in FV0 + : "+w" (__z1), "+f" (__z2), "+f" (__z3), "+f" (__z4) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; + return output; +} + +// Matrix Transpose +// +// This does a matrix transpose on the matrix in XMTRX, which swaps rows with +// columns as follows (math notation is [XMTRX]^T): +// +// [ a b c d ] T [ a e i m ] +// [ e f g h ] = [ b f j n ] +// [ i j k l ] [ c g k o ] +// [ m n o p ] [ d h l p ] +// +// PLEASE NOTE: It is faster to avoid the need for a transpose altogether by +// structuring matrices and vectors accordingly. +static inline __attribute__((always_inline)) void MATH_Matrix_Transpose(void) +{ + asm volatile ( + "frchg\n\t" // fmov for singles only works on front bank + // FR0, FR5, FR10, and FR15 are already in place + // swap FR1 and FR4 + "flds FR1, FPUL\n\t" + "fmov FR4, FR1\n\t" + "fsts FPUL, FR4\n\t" + // swap FR2 and FR8 + "flds FR2, FPUL\n\t" + "fmov FR8, FR2\n\t" + "fsts FPUL, FR8\n\t" + // swap FR3 and FR12 + "flds FR3, FPUL\n\t" + "fmov FR12, FR3\n\t" + "fsts FPUL, FR12\n\t" + // swap FR6 and FR9 + "flds FR6, FPUL\n\t" + "fmov FR9, FR6\n\t" + "fsts FPUL, FR9\n\t" + // swap FR7 and FR13 + "flds FR7, FPUL\n\t" + "fmov FR13, FR7\n\t" + "fsts FPUL, FR13\n\t" + // swap FR11 and FR14 + "flds FR11, FPUL\n\t" + "fmov FR14, FR11\n\t" + "fsts FPUL, FR14\n\t" + // restore XMTRX to back bank + "frchg\n" + : // no outputs + : // no inputs + : "fpul" // clobbers + ); +} + +// Matrix product: matrix * matrix = matrix +// +// These use the whole dang floating point unit. +// +// [ ----------- ] [ ----------- ] [ ----------- ] +// [ ---Back---- ] [ ---Front--- ] = [ ---XMTRX--- ] +// [ ---Matrix-- ] [ ---Matrix-- ] [ ----------- ] +// [ --(XMTRX)-- ] [ ----------- ] [ ----------- ] +// +// Multiply a matrix stored in the back bank with a matrix loaded from memory +// Output is stored in the back bank (XMTRX) +static inline __attribute__((always_inline)) void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) +{ + /* + // This prefetching should help a bit if placed suitably far enough in advance (not here) + // Possibly right before this function call. Change the "front_matrix" variable appropriately. + // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. + __builtin_prefetch(front_matrix); + */ + + unsigned int prefetch_scratch; + + asm volatile ( + "mov %[fmtrx], %[pref_scratch]\n\t" // parallel-load address for prefetching (MT) + "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) + "fschg\n\t" // switch fmov to paired moves (FE) + "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) + // interleave loads and matrix multiply 4x4 + "fmov.d @%[fmtrx]+, DR0\n\t" // (LS) + "fmov.d @%[fmtrx]+, DR2\n\t" + "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec + "ftrv XMTRX, FV0\n\t" // (FE) + + "fmov.d @%[fmtrx]+, DR6\n\t" + "fmov.d @%[fmtrx]+, DR8\n\t" // prefetch should work for here + "ftrv XMTRX, FV4\n\t" + + "fmov.d @%[fmtrx]+, DR10\n\t" + "fmov.d @%[fmtrx]+, DR12\n\t" + "ftrv XMTRX, FV8\n\t" + + "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) + "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) + "ftrv XMTRX, FV12\n\t" // (FE) + // Save output in XF regs + "frchg\n" + : [fmtrx] "+r" ((unsigned int)front_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w + : // no inputs + : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) + ); +} + +// Load two 4x4 matrices and multiply them, storing the output into the back bank (XMTRX) +// +// MATH_Load_Matrix_Product() is slightly faster than doing this: +// MATH_Load_XMTRX(matrix1) +// MATH_Matrix_Product(matrix2) +// as it saves having to do 2 extraneous 'fschg' instructions. +// +static inline __attribute__((always_inline)) void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) +{ + /* + // This prefetching should help a bit if placed suitably far enough in advance (not here) + // Possibly right before this function call. Change the "matrix1" variable appropriately. + // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. + __builtin_prefetch(matrix1); + */ + + unsigned int prefetch_scratch; + + asm volatile ( + "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) + "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) + "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) + // back matrix + "fmov.d @%[bmtrx]+, XD0\n\t" // (LS) + "fmov.d @%[bmtrx]+, XD2\n\t" + "fmov.d @%[bmtrx]+, XD4\n\t" + "fmov.d @%[bmtrx]+, XD6\n\t" + "pref @%[fmtrx]\n\t" // prefetch fmtrx now while we wait (LS) + "fmov.d @%[bmtrx]+, XD8\n\t" // bmtrx prefetch should work for here + "fmov.d @%[bmtrx]+, XD10\n\t" + "fmov.d @%[bmtrx]+, XD12\n\t" + "mov %[fmtrx], %[pref_scratch]\n\t" // (MT) + "add #32, %[pref_scratch]\n\t" // store offset by 32 in r0 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) + "fmov.d @%[bmtrx], XD14\n\t" + "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) + // front matrix + // interleave loads and matrix multiply 4x4 + "fmov.d @%[fmtrx]+, DR0\n\t" + "fmov.d @%[fmtrx]+, DR2\n\t" + "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec + "ftrv XMTRX, FV0\n\t" // (FE) + + "fmov.d @%[fmtrx]+, DR6\n\t" + "fmov.d @%[fmtrx]+, DR8\n\t" + "ftrv XMTRX, FV4\n\t" + + "fmov.d @%[fmtrx]+, DR10\n\t" + "fmov.d @%[fmtrx]+, DR12\n\t" + "ftrv XMTRX, FV8\n\t" + + "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) + "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) + "ftrv XMTRX, FV12\n\t" // (FE) + // Save output in XF regs + "frchg\n" + : [bmtrx] "+&r" ((unsigned int)matrix1), [fmtrx] "+r" ((unsigned int)matrix2), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed + : // no inputs + : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) + ); +} + +//------------------------------------------------------------------------------ +// Matrix load and store operations +//------------------------------------------------------------------------------ + +// Load a matrix from memory into the back bank (XMTRX) +static inline __attribute__((always_inline)) void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) +{ + /* + // This prefetching should help a bit if placed suitably far enough in advance (not here) + // Possibly right before this function call. Change the "back_matrix" variable appropriately. + // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. + __builtin_prefetch(back_matrix); + */ + + unsigned int prefetch_scratch; + + asm volatile ( + "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) + "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) + "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) + "fmov.d @%[bmtrx]+, XD0\n\t" + "fmov.d @%[bmtrx]+, XD2\n\t" + "fmov.d @%[bmtrx]+, XD4\n\t" + "fmov.d @%[bmtrx]+, XD6\n\t" + "fmov.d @%[bmtrx]+, XD8\n\t" + "fmov.d @%[bmtrx]+, XD10\n\t" + "fmov.d @%[bmtrx]+, XD12\n\t" + "fmov.d @%[bmtrx], XD14\n\t" + "fschg\n" // switch back to single moves + : [bmtrx] "+r" ((unsigned int)back_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w + : // no inputs + : // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) + ); +} + +// Store XMTRX to memory +static inline __attribute__((always_inline)) ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) +{ + /* + // This prefetching should help a bit if placed suitably far enough in advance (not here) + // Possibly right before this function call. Change the "destination" variable appropriately. + // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. + __builtin_prefetch( (ALL_FLOATS_STRUCT*)((unsigned char*)destination + 32) ); // Store works backwards, so note the '+32' here + */ + + char * output = ((char*)destination) + sizeof(ALL_FLOATS_STRUCT) + 8; // ALL_FLOATS_STRUCT should be 64 bytes + + asm volatile ( + "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) + "pref @%[dest_base]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) + "fmov.d XD0, @-%[out_mtrx]\n\t" // These do *(--output) = XDn (LS) + "fmov.d XD2, @-%[out_mtrx]\n\t" + "fmov.d XD4, @-%[out_mtrx]\n\t" + "fmov.d XD6, @-%[out_mtrx]\n\t" + "fmov.d XD8, @-%[out_mtrx]\n\t" + "fmov.d XD10, @-%[out_mtrx]\n\t" + "fmov.d XD12, @-%[out_mtrx]\n\t" + "fmov.d XD14, @-%[out_mtrx]\n\t" + "fschg\n" // switch back to single moves + : [out_mtrx] "+&r" ((unsigned int)output) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed + : [dest_base] "r" ((unsigned int)destination) // inputs + : "memory" // clobbers + ); + + return destination; +} + +// Returns FV0, 4, 8, or 12 from XMTRX +// +// Sorry, it has to be done 4 at a time like this due to calling convention +// limits; under optimal optimization conditions, we only get 4 float registers +// for return values; any more and they get pushed to memory. +// +// IMPORTANT USAGE INFORMATION (get XMTRX vector) +// +// XMTRX format, using the front bank's FVn notation: +// +// FV0 FV4 FV8 FV12 +// --- --- --- ---- +// [ xf0 xf4 xf8 xf12 ] +// [ xf1 xf5 xf9 xf13 ] +// [ xf2 xf6 xf10 xf14 ] +// [ xf3 xf7 xf11 xf15 ] +// +// Return vector maps to XMTRX as below depending on the FVn value passed in: +// +// typedef struct { +// float z1; // will contain xf0, 4, 8 or 12 +// float z2; // will contain xf1, 5, 9, or 13 +// float z3; // will contain xf2, 6, 10, or 14 +// float z4; // will contain xf3, 7, 11, or 15 +// } RETURN_VECTOR_STRUCT; +// +// Valid values of 'which' are 0, 4, 8, or 12, corresponding to FV0, FV4, FV8, +// or FV12, respectively. Other values will return 0 in all four return values. +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) +{ + register float __z1 __asm__("fr0"); + register float __z2 __asm__("fr1"); + register float __z3 __asm__("fr2"); + register float __z4 __asm__("fr3"); + + // Note: only paired moves can access XDn regs + asm volatile ("cmp/eq #0, %[select]\n\t" // if(which == 0), 1 -> T else 0 -> T + "bt.s 0f\n\t" // do FV0 + " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T + "bt.s 4f\n\t" // do FV4 + " cmp/eq #8, %[select]\n\t" // if(which == 8), 1 -> T else 0 -> T + "bt.s 8f\n\t" // do FV8 + " cmp/eq #12, %[select]\n\t" // if(which == 12), 1 -> T else 0 -> T + "bf.s 1f\n" // exit if not even FV12 was true, otherwise do FV12 + "12:\n\t" + " fschg\n\t" // paired moves for FV12 (and exit case) + "fmov XD14, DR2\n\t" + "fmov XD12, DR0\n\t" + "bt.s 2f\n" // done + "8:\n\t" + " fschg\n\t" // paired moves for FV8, back to singles for FV12 + "fmov XD10, DR2\n\t" + "fmov XD8, DR0\n\t" + "bf.s 2f\n" // done + "4:\n\t" + " fschg\n\t" // paired moves for FV4, back to singles for FV8 + "fmov XD6, DR2\n\t" + "fmov XD4, DR0\n\t" + "bf.s 2f\n" // done + "0:\n\t" + " fschg\n\t" // paired moves for FV0, back to singles for FV4 + "fmov XD2, DR2\n\t" + "fmov XD0, DR0\n\t" + "bf.s 2f\n" // done + "1:\n\t" + " fschg\n\t" // back to singles for FV0 and exit case + "fldi0 FR0\n\t" // FR0-3 get zeroed out, then + "fmov FR0, FR1\n\t" + "fmov FR0, FR2\n\t" + "fmov FR0, FR3\n" + "2:\n" + : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs + : [select] "z" (which) // inputs + : "t" // clobbers + ); + + RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; + return output; +} + +// Returns a 2x2 matrix from a quadrant of XMTRX +// +// Sorry, it has to be done 4 at a time like this due to calling convention +// limits; under optimal optimization conditions, we only get 4 float registers +// for return values; any more and they get pushed to memory. +// +// IMPORTANT USAGE INFORMATION (get XMTRX 2x2) +// +// Each 2x2 quadrant is of the form: +// +// [ a b ] +// [ c d ] +// +// Return vector maps to the 2x2 matrix as below: +// +// typedef struct { +// float z1; // a +// float z2; // c +// float z3; // b +// float z4; // d +// } RETURN_VECTOR_STRUCT; +// +// (So the function does a 2x2 transpose in storing the values relative to the +// order stored in XMTRX.) +// +// Valid values of 'which' are 1, 2, 3, or 4, corresponding to the following +// quadrants of XMTRX: +// +// 1 2 +// [ xf0 xf4 ] | [ xf8 xf12 ] +// [ xf1 xf5 ] | [ xf9 xf13 ] +// -- 3 -- | -- 4 -- +// [ xf2 xf6 ] | [ xf10 xf14 ] +// [ xf3 xf7 ] | [ xf11 xf15 ] +// +// Other input values will return 0 in all four return floats. +static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) +{ + register float __z1 __asm__("fr0"); + register float __z2 __asm__("fr1"); + register float __z3 __asm__("fr2"); + register float __z4 __asm__("fr3"); + + // Note: only paired moves can access XDn regs + asm volatile ("cmp/eq #1, %[select]\n\t" // if(which == 1), 1 -> T else 0 -> T + "bt.s 1f\n\t" // do quadrant 1 + " cmp/eq #2, %[select]\n\t" // if(which == 2), 1 -> T else 0 -> T + "bt.s 2f\n\t" // do quadrant 2 + " cmp/eq #3, %[select]\n\t" // if(which == 3), 1 -> T else 0 -> T + "bt.s 3f\n\t" // do quadrant 3 + " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T + "bf.s 0f\n" // exit if nothing was true, otherwise do quadrant 4 + "4:\n\t" + " fschg\n\t" // paired moves for quadrant 4 (and exit case) + "fmov XD14, DR2\n\t" + "fmov XD10, DR0\n\t" + "bt.s 5f\n" // done + "3:\n\t" + " fschg\n\t" // paired moves for quadrant 3, back to singles for 4 + "fmov XD6, DR2\n\t" + "fmov XD2, DR0\n\t" + "bf.s 5f\n" // done + "2:\n\t" + " fschg\n\t" // paired moves for quadrant 2, back to singles for 3 + "fmov XD12, DR2\n\t" + "fmov XD8, DR0\n\t" + "bf.s 5f\n" // done + "1:\n\t" + " fschg\n\t" // paired moves for quadrant 1, back to singles for 2 + "fmov XD4, DR2\n\t" + "fmov XD0, DR0\n\t" + "bf.s 5f\n" // done + "0:\n\t" + " fschg\n\t" // back to singles for quadrant 1 and exit case + "fldi0 FR0\n\t" // FR0-3 get zeroed out, then + "fmov FR0, FR1\n\t" + "fmov FR0, FR2\n\t" + "fmov FR0, FR3\n" + "5:\n" + : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs + : [select] "z" (which) // inputs + : "t" // clobbers + ); + + RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; + return output; +} + +// It is not possible to return an entire 4x4 matrix in registers, as the only +// registers allowed for return values are R0-R3 and FR0-FR3. All others are +// marked caller save, which means they could be restored from stack and clobber +// anything returned in them. +// +// In general, writing the entire required math routine in one asm function is +// the best way to go for performance reasons anyways, and in that situation one +// can just throw calling convention to the wind until returning back to C. + +//============================================================================== +// Miscellaneous Functions +//============================================================================== +// +// The following functions are provided as examples of ways in which these math +// functions can be used. +// +// Reminder: 1 fsca unit = 1/182.044444444 of a degree or 1/10430.3783505 of a radian +// In order to make the best use of fsca units, a program must expect them from +// the outset and not "make them" by dividing radians or degrees to get them, +// otherwise it's just giving the 'fsca' instruction radians or degrees! +// +/* + + //------------------------------------------------------------------------------ + // Commonly useful functions + //------------------------------------------------------------------------------ + + // Returns 1 if point 't' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not + int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) + + //------------------------------------------------------------------------------ + // Interpolation + //------------------------------------------------------------------------------ + + // Linear interpolation + float MATH_Lerp(float a, float b, float t) + + // Speherical interpolation ('theta' in fsca units) + float MATH_Slerp(float a, float b, float t, float theta) + + //------------------------------------------------------------------------------ + // Fast Sinc functions (unnormalized, sin(x)/x version) + //------------------------------------------------------------------------------ + // Just pass in MATH_pi * x for normalized versions :) + + // Sinc function (fsca units) + float MATH_Fast_Sincf(float x) + + // Sinc function (degrees) + float MATH_Fast_Sincf_Deg(float x) + + // Sinc function (rads) + float MATH_Fast_Sincf_Rad(float x) + + //------------------------------------------------------------------------------ + // Kaiser Window + //------------------------------------------------------------------------------ + + // Generates mipmaps. Angle 'x' in radians. + float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) + + // Generates mipmaps. Angle 'x' in fsca units. + float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) + +*/ + +//------------------------------------------------------------------------------ +// Commonly useful functions +//------------------------------------------------------------------------------ + +// Returns 1 if point 'pt' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not +// Determines triangle center using barycentric coordinate transformation +// Adapted from: https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle +// Specifically the answer by user 'adreasdr' in addition to the comment by user 'urraka' on the answer from user 'Andreas Brinck' +// +// The notation here assumes v0x is the x-component of v0, v0y is the y-component of v0, etc. +// +static inline __attribute__((always_inline)) int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) +{ + float sdot = MATH_fipr(v0y, -v0x, v2y - v0y, v0x - v2x, v2x, v2y, ptx, pty); + float tdot = MATH_fipr(v0x, -v0y, v0y - v1y, v1x - v0x, v1y, v1x, ptx, pty); + + float areadot = MATH_fipr(-v1y, v0y, v0x, v1x, v2x, -v1x + v2x, v1y - v2y, v2y); + + // 'areadot' could be negative depending on the winding of the triangle + if(areadot < 0.0f) + { + sdot *= -1.0f; + tdot *= -1.0f; + areadot *= -1.0f; + } + + if( (sdot > 0.0f) && (tdot > 0.0f) && (areadot > (sdot + tdot)) ) + { + return 1; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// Interpolation +//------------------------------------------------------------------------------ + +// Linear interpolation +static inline __attribute__((always_inline)) float MATH_Lerp(float a, float b, float t) +{ + return MATH_fmac(t, (b-a), a); +} + +// Speherical interpolation ('theta' in fsca units) +static inline __attribute__((always_inline)) float MATH_Slerp(float a, float b, float t, float theta) +{ + // a is an element of v0, b is an element of v1 + // v = ( v0 * sin(theta - t * theta) + v1 * sin(t * theta) ) / sin(theta) + // by using sine/cosine identities and properties, this can be optimized to: + // v = v0 * cos(-t * theta) + ( v0 * ( cos(theta) * sin(-t * theta) ) - sin(-t * theta) * v1 ) / sin(theta) + // which only requires two calls to fsca. + // Specifically, sin(a + b) = sin(a)cos(b) + cos(a)sin(b) & sin(-a) = -sin(a) + + // MATH_fsca_* functions return reverse-ordered complex numbers for speed reasons (i.e. normally sine is the imaginary part) + // This could be made even faster by using MATH_fsca_Int() with 'theta' and 't' as unsigned ints + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(theta); + float sine_value_theta = sine_cosine.sine; + float cosine_value_theta = sine_cosine.cosine; + + RETURN_FSCA_STRUCT sine_cosine2 = MATH_fsca_Float(-t * theta); + float sine_value_minus_t_theta = sine_cosine2.sine; + float cosine_value_minus_t_theta = sine_cosine2.cosine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float(theta); + float sine_value_theta = __real__ sine_cosine; + float cosine_value_theta = __imag__ sine_cosine; + + _Complex float sine_cosine2 = MATH_fsca_Float(-t * theta); + float sine_value_minus_t_theta = __real__ sine_cosine2; + float cosine_value_minus_t_theta = __imag__ sine_cosine2; + +#endif + + float numer = a * cosine_value_theta * sine_value_minus_t_theta - sine_value_minus_t_theta * b; + float output_float = a * cosine_value_minus_t_theta + MATH_Fast_Divide(numer, sine_value_theta); + + return output_float; +} + +//------------------------------------------------------------------------------ +// Fast Sinc (unnormalized, sin(x)/x version) +//------------------------------------------------------------------------------ +// +// Just pass in MATH_pi * x for normalized versions :) +// + +// Sinc function (fsca units) +static inline __attribute__((always_inline)) float MATH_Fast_Sincf(float x) +{ + if(x == 0.0f) + { + return 1.0f; + } + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); + float sine_value = sine_cosine.sine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float(x); + float sine_value = __real__ sine_cosine; + +#endif + + return MATH_Fast_Divide(sine_value, x); +} + +// Sinc function (degrees) +static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Deg(float x) +{ + if(x == 0.0f) + { + return 1.0f; + } + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Deg(x); + float sine_value = sine_cosine.sine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float_Deg(x); + float sine_value = __real__ sine_cosine; + +#endif + + return MATH_Fast_Divide(sine_value, x); +} + +// Sinc function (rads) +static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Rad(float x) +{ + if(x == 0.0f) + { + return 1.0f; + } + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); + float sine_value = sine_cosine.sine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float_Rad(x); + float sine_value = __real__ sine_cosine; + +#endif + + return MATH_Fast_Divide(sine_value, x); +} + +//------------------------------------------------------------------------------ +// Kaiser Window +//------------------------------------------------------------------------------ +// +// These use regular divides because they only need to be run once during loads, +// not during runtime. +// +// Adapted from public domain NVidia Filter.cpp: +// https://github.com/castano/nvidia-texture-tools/blob/master/src/nvimage/Filter.cpp +// (as of 3/23/2020) +// + +// +// Kaiser window utility functions +// + +// Utility function for 0th-order bessel function +static inline __attribute__((always_inline)) float MATH_Bessel0(float x) +{ + const float EPSILON_RATIO = 1e-6f; + float xh, sum, power, ds, k; + // int k; + + xh = 0.5f * x; + sum = 1.0f; + power = 1.0f; + k = 0.0f; // k = 0; + ds = 1.0; + while (ds > (sum * EPSILON_RATIO)) + { + k += 1.0f; // ++k; + power = power * (xh / k); + ds = power * power; + sum = sum + ds; + } + + return sum; +} + +// Utility for kaiser window's expected sincf() format (radians) +static inline __attribute__((always_inline)) float MATH_NV_Sincf_Rad(const float x) +{ + // Does SH4 need this correction term? x86's sinf() definitely does, + // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. + if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f + { + return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) + } + else + { + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); + float sine_value = sine_cosine.sine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float_Rad(x); + float sine_value = __real__ sine_cosine; + +#endif + + return sine_value / x; + } +} + +// Utility for kaiser window's expected sincf() format (fsca units) +static inline __attribute__((always_inline)) float MATH_NV_Sincf(const float x) +{ + // Does SH4 need this correction term? x86's sinf() definitely does, + // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. + if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f + { + return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) + } + else + { + +#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION + + RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); + float sine_value = sine_cosine.sine; + +#else + + _Complex float sine_cosine = MATH_fsca_Float(x); + float sine_value = __real__ sine_cosine; + +#endif + + return sine_value / x; + } +} + +// +// Kaiser window mipmap generator main functions +// + +// Generates mipmaps. Angle 'x' in radians. +static inline __attribute__((always_inline)) float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) +{ + const float sinc_value = MATH_NV_Sincf_Rad(MATH_pi * x * stretch); + const float t = x / m_width; + + if ((1 - t * t) >= 0) + { + return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); + } + else + { + return 0; + } +} + +// Generates mipmaps. Angle 'x' in fsca units. +static inline __attribute__((always_inline)) float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) +{ + const float sinc_value = MATH_NV_Sincf(MATH_pi * x * stretch); + const float t = x / m_width; + + if ((1 - t * t) >= 0) + { + return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); + } + else + { + return 0; + } +} + +//============================================================================== +// Miscellaneous Snippets +//============================================================================== +// +// The following snippets are best implemented manually in user code (they can't +// be put into their own functions without incurring performance penalties). +// +// They also serve as examples of how one might use the functions in this header. +// +/* + Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) +*/ + +// +// Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) +// +// magnitude = sqrt(x^2 + y^2 + z^2) +// (x, y, z) = 1/magnitude * (x, y, z) +// +// x, y, z, and magnitude are assumed already existing floats +// + +/* -- start -- + + // Don't need an 'else' with this (if length is 0, x = y = z = 0) + magnitude = 0; + + if(__builtin_expect(x || y || z, 1)) + { + temp = MATH_Sum_of_Squares(x, y, z, 0); // temp = x^2 + y^2 + z^2 + 0^2 + float normalizer = MATH_fsrra(temp); // 1/sqrt(temp) + x = normalizer * x; + y = normalizer * y; + z = normalizer * z; + magnitude = MATH_Fast_Invert(normalizer); + } + +-- end -- */ + + +#endif /* __SH4_MATH_H_ */ \ No newline at end of file diff --git a/engine/inc/uf/utils/math/vector/pod.inl b/engine/inc/uf/utils/math/vector/pod.inl index 300f0ca7..bda8d2d1 100644 --- a/engine/inc/uf/utils/math/vector/pod.inl +++ b/engine/inc/uf/utils/math/vector/pod.inl @@ -71,19 +71,29 @@ template // Divides two vectors of same type and size T /*UF_API*/ uf::vector::divide( const T& left, const T& right ) { #if UF_USE_SIMD return uf::simd::div( left, right ); -#endif +#elif UF_ENV_DREAMCAST + T res; + for ( std::size_t i = 0; i < T::size; ++i ) res[i] = MATH_Fast_Divide(left[i], right[i]); + return res; +#else T res; for ( std::size_t i = 0; i < T::size; ++i ) res[i] = left[i] / right[i]; return res; +#endif } template // Divides this vector by a scalar T /*UF_API*/ uf::vector::divide( const T& vector, const typename T::type_t& scalar ) { #if UF_USE_SIMD return uf::simd::div( vector, scalar ); -#endif +#elif UF_ENV_DREAMCAST + T res; + for ( std::size_t i = 0; i < T::size; ++i ) res[i] = MATH_Fast_Divide(vector[i], scalar); + return res; +#else T res; for ( std::size_t i = 0; i < T::size; ++i ) res[i] = vector[i] / scalar; return res; +#endif } template // Compute the sum of all components typename T::type_t /*UF_API*/ uf::vector::sum( const T& vector ) { @@ -172,7 +182,9 @@ T& /*UF_API*/ uf::vector::normalize( T& vector ) { // Complex arithmetic template // Compute the dot product between two vectors typename T::type_t /*UF_API*/ uf::vector::dot( const T& left, const T& right ) { -#if UF_USE_SIMD +#if UF_ENV_DREAMCAST + return MATH_fipr( UF_EZ_VEC4(left, T::size), UF_EZ_VEC4(right, T::size) ); +#elif UF_USE_SIMD return uf::simd::dot( left, right ); #endif return uf::vector::sum(uf::vector::multiply(left, right)); @@ -185,7 +197,11 @@ template // Linearly interpolate between two vectors T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, double delta, bool clamp ) { delta = fmax( 0, fmin(1,delta) ); // from + ( ( to - from ) * delta ) -#if UF_USE_SIMD +#if UF_ENV_DREAMCAST + T res; + for ( auto i = 0; i < T::size; ++i ) res[i] = MATH_Lerp( from[i], to[i], delta ); + return res; +#elif UF_USE_SIMD return uf::simd::add(from, uf::simd::mul( uf::simd::sub(to, from), (float) delta) ); #endif return uf::vector::add(from, uf::vector::multiply( uf::vector::subtract(to, from), delta ) ); @@ -194,7 +210,11 @@ template // Linearly interpolate between two vectors T /*UF_API*/ uf::vector::lerp( const T& from, const T& to, const T& delta, bool clamp ) { //delta = fmax( 0, fmin(1,delta) ); // from + ( ( to - from ) * delta ) -#if UF_USE_SIMD +#if UF_ENV_DREAMCAST + T res; + for ( auto i = 0; i < T::size; ++i ) res[i] = MATH_Lerp( from[i], to[i], delta[i] ); + return res; +#elif UF_USE_SIMD return uf::simd::add(from, uf::simd::mul( uf::simd::sub(to, from), delta) ); #endif return uf::vector::add(from, uf::vector::multiply( uf::vector::subtract(to, from), delta ) ); @@ -224,7 +244,10 @@ T /*UF_API*/ uf::vector::mix( const T& x, const T& y, double a, bool clamp ) { } template // Compute the distance between two vectors (doesn't sqrt) typename T::type_t /*UF_API*/ uf::vector::distanceSquared( const T& a, const T& b ) { -#if UF_USE_SIMD +#if UF_ENV_DREAMCAST + T delta = uf::vector::subtract(b, a); + return MATH_Sum_of_Squares( UF_EZ_VEC4( delta, T::size ) ); +#elif UF_USE_SIMD uf::simd::value delta = uf::simd::sub( b, a ); return uf::vector::sum( uf::simd::vector( uf::simd::mul( delta, delta ) ) ); #else @@ -235,6 +258,9 @@ typename T::type_t /*UF_API*/ uf::vector::distanceSquared( const T& a, const T& } template // Compute the distance between two vectors typename T::type_t /*UF_API*/ uf::vector::distance( const T& a, const T& b ) { +#if UF_ENV_DREAMCAST + return MATH_Fast_Sqrt(uf::vector::distanceSquared(a,b)); +#endif return sqrt(uf::vector::distanceSquared(a,b)); } template // Gets the magnitude of the vector @@ -243,12 +269,18 @@ typename T::type_t /*UF_API*/ uf::vector::magnitude( const T& vector ) { } template // Compute the norm of the vector typename T::type_t /*UF_API*/ uf::vector::norm( const T& vector ) { +#if UF_ENV_DREAMCAST + return MATH_Fast_Sqrt( uf::vector::magnitude(vector) ); +#endif return sqrt( uf::vector::magnitude(vector) ); } template // Normalizes a vector T /*UF_API*/ uf::vector::normalize( const T& vector ) { typename T::type_t norm = uf::vector::norm(vector); if ( norm == 0 ) return vector; +#if UF_ENV_DREAMCAST + return uf::vector::multiply(vector, MATH_fsrra(norm)); +#endif return uf::vector::divide(vector, norm); } template // Normalizes a vector @@ -284,6 +316,9 @@ T /*UF_API*/ uf::vector::cross( const T& a, const T& b ) { uf::simd::value res = _mm_shuffle_ps(tmp2,tmp2,_MM_SHUFFLE(3,0,2,1)); return res; #endif +#elif UF_ENV_DREAMCAST + auto res = MATH_Cross_Product( a.x, a.y, a.z, b.x, b.y, b.z ); + return *((T*) &res); #endif return T{ a.y * b.z - b.y * a.z, diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index b841207f..76a33906 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -174,6 +174,8 @@ std::string uf::Asset::load( const std::string& uri, const std::string& hash, co #if UF_USE_OPENGL_FIXED_FUNCTION // force disable use of a texture atlas, for now metadata[uri]["flags"]["ATLAS"] = false; + metadata[uri]["flags"]["SEPARATE"] = true; + metadata[uri]["flags"]["NORMALS"] = true; #else metadata[uri]["flags"]["ATLAS"] = true; #endif diff --git a/engine/src/engine/behavior/behavior.cpp b/engine/src/engine/behavior/behavior.cpp index 5343ca51..e6521151 100644 --- a/engine/src/engine/behavior/behavior.cpp +++ b/engine/src/engine/behavior/behavior.cpp @@ -26,7 +26,7 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { #define FUNCTION_AS_VARIABLE(x) x -#define UF_BEHAVIOR_POLYFILL UF_BEHAVIOR_POLYFILL_SAFE +#define UF_BEHAVIOR_POLYFILL UF_BEHAVIOR_POLYFILL_FAST /* // if ( this->hasComponent() ) {\ // auto& metadata = this->getComponent();\ @@ -38,121 +38,46 @@ void uf::Behaviors::removeBehavior( const pod::Behavior& behavior ) { // multithreading = metadata["system"]["behavior"][#f]["multithreading"].as();\ // }\ */ + #define UF_BEHAVIOR_POLYFILL_SAFE(f)\ bool headLoopChildren = true;\ bool forwardIteration = true;\ - bool multithreading = false;\ - auto function = [&]() -> int {\ - if ( headLoopChildren ) {\ - if ( forwardIteration )\ - for ( auto& behavior : this->m_behaviors )\ - behavior.f(self);\ - else\ - for ( auto it = this->m_behaviors.rbegin(); it != this->m_behaviors.rend(); ++it )\ - it->f(self);\ - } else {\ - if ( forwardIteration ) {\ - auto it = this->m_behaviors.begin();\ - for ( ++it; it != this->m_behaviors.end(); ++it )\ - it->f(self);\ - if ( (it = this->m_behaviors.begin()) != this->m_behaviors.end() ) {\ - it->f(self);\ - }\ - } else {\ - auto it = this->m_behaviors.rbegin();\ - for ( ++it; it != this->m_behaviors.rend(); ++it )\ - it->f(self);\ - if ( (it = this->m_behaviors.rbegin()) != this->m_behaviors.rend() ) {\ - it->f(self);\ - }\ - }\ - }\ - return 0;\ - };\ - if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true ); else function(); - -#define UF_BEHAVIOR_POLYFILL_FAST(f)\ - if ( this->m_behaviors.empty() ) return;\ - uf::Object& self = *((uf::Object*) this);\ - bool headLoopChildren = true;\ - bool forwardIteration = true;\ - bool multithreading = false;\ - bool useWorkers = false;\ - std::vector> jobs;\ - if ( this->hasComponent() ) {\ - auto& metadata = this->getComponent();\ - if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["head loop children"] ) )\ - headLoopChildren = metadata["system"]["behavior"][#f]["head loop children"].as();\ - if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["forward iteration"] ) )\ - forwardIteration = metadata["system"]["behavior"][#f]["forward iteration"].as();\ - if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["multithreading"] ) )\ - multithreading = metadata["system"]["behavior"][#f]["multithreading"].as();\ - if ( !ext::json::isNull( metadata["system"]["behavior"][#f]["use workers"] ) )\ - useWorkers = metadata["system"]["behavior"][#f]["use workers"].as();\ - }\ if ( headLoopChildren ) {\ - if ( forwardIteration ) {\ - auto it = this->m_behaviors.begin();\ - if ( it != this->m_behaviors.end() ) {\ + if ( forwardIteration )\ + for ( auto& behavior : this->m_behaviors ){\ + behavior.f(self);\ + }\ + else\ + for ( auto it = this->m_behaviors.rbegin(); it != this->m_behaviors.rend(); ++it )\ it->f(self);\ - }\ - for ( ++it; it != this->m_behaviors.end(); ++it ) {\ - auto function = [&]() -> int {\ - it->f(self);\ - return 0;\ - };\ - if ( multithreading && useWorkers ) jobs.emplace_back(function);\ - else if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true );\ - else function();\ - }\ - } else {\ - auto it = this->m_behaviors.rbegin();\ - if ( it != this->m_behaviors.rend() ) {\ - it->f(self);\ - }\ - for ( ++it; it != this->m_behaviors.rend(); ++it ) {\ - auto function = [&]() -> int {\ - it->f(self);\ - return 0;\ - };\ - if ( multithreading && useWorkers ) jobs.emplace_back(function);\ - else if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true );\ - else function();\ - }\ - }\ } else {\ if ( forwardIteration ) {\ auto it = this->m_behaviors.begin();\ - for ( ++it; it != this->m_behaviors.end(); ++it ) {\ - auto function = [&]() -> int {\ - it->f(self);\ - return 0;\ - };\ - if ( multithreading && useWorkers ) jobs.emplace_back(function);\ - else if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true );\ - else function();\ - }\ + for ( ++it; it != this->m_behaviors.end(); ++it )\ + it->f(self);\ if ( (it = this->m_behaviors.begin()) != this->m_behaviors.end() ) {\ it->f(self);\ }\ } else {\ auto it = this->m_behaviors.rbegin();\ - for ( ++it; it != this->m_behaviors.rend(); ++it ) {\ - auto function = [&]() -> int {\ - it->f(self);\ - return 0;\ - };\ - if ( multithreading && useWorkers ) jobs.emplace_back(function);\ - else if ( multithreading ) uf::thread::add( uf::thread::fetchWorker(), function, true );\ - else function();\ - }\ + for ( ++it; it != this->m_behaviors.rend(); ++it )\ + it->f(self);\ if ( (it = this->m_behaviors.rbegin()) != this->m_behaviors.rend() ) {\ it->f(self);\ }\ }\ - }\ - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + } +#define UF_BEHAVIOR_POLYFILL_FAST(f)\ + for ( auto& behavior : this->m_behaviors ) behavior.f(self); +/* +#define UF_BEHAVIOR_POLYFILL_FAST(f)\ + for ( auto& behavior : this->m_behaviors ) {\ + UF_TIMER_TRACE_INIT();\ + behavior.f(self);\ + UF_TIMER_TRACE(self.getName() << ": " << self.getUid() << " | " << behavior.type.name() );\ + } +*/ void uf::Behaviors::initialize() { uf::Object& self = *((uf::Object*) this); @@ -162,12 +87,16 @@ void uf::Behaviors::initialize() { void uf::Behaviors::tick() { uf::Object& self = *((uf::Object*) this); if ( !self.isValid() ) return; +// UF_TIMER_TRACE_INIT(); UF_BEHAVIOR_POLYFILL(tick) +// UF_TIMER_TRACE(self.getName() << ": " << self.getUid()); } void uf::Behaviors::render() { uf::Object& self = *((uf::Object*) this); if ( !self.isValid() ) return; +// UF_TIMER_TRACE_INIT(); UF_BEHAVIOR_POLYFILL(render) +// UF_TIMER_TRACE(self.getName() << ": " << self.getUid()); } void uf::Behaviors::destroy() { uf::Object& self = *((uf::Object*) this); diff --git a/engine/src/engine/entity/behavior.cpp b/engine/src/engine/entity/behavior.cpp index 741edadc..8a09fc39 100644 --- a/engine/src/engine/entity/behavior.cpp +++ b/engine/src/engine/entity/behavior.cpp @@ -1,47 +1,30 @@ #include +#include #include UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Entity) uf::Entity::Entity() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Entity) #define this ((uf::Entity*) &self) void uf::EntityBehavior::initialize( uf::Object& self ) { - if ( !this->isValid() ) this->m_uid = ++uf::Entity::uids; - // sanitize children -/* - for ( auto& kv : this->m_children ) { - if ( !uf::instantiator::valid(kv) ) { - std::cout << "FOUND INVALID CHILD IN " << this->getName() << ": " << this->getUid() << ": " << kv << std::endl; - kv = NULL; - } - } -*/ + if ( !this->isValid() ) this->setUid(); } + + void uf::EntityBehavior::tick( uf::Object& self ) { - for ( uf::Entity* kv : this->m_children ) { - if ( !kv ) continue; - if ( !kv->isValid() ) continue; - kv->tick(); - } + if ( !uf::scene::useGraph ) for ( uf::Entity* kv : this->getChildren() ) if ( kv->isValid() ) kv->tick(); } void uf::EntityBehavior::render( uf::Object& self ) { - for ( uf::Entity* kv : this->m_children ) { - if ( !kv ) continue; - if ( !kv->isValid() ) continue; - kv->render(); - } + if ( !uf::scene::useGraph ) for ( uf::Entity* kv : this->getChildren() ) if ( kv->isValid() ) kv->render(); } void uf::EntityBehavior::destroy( uf::Object& self ) { - for ( uf::Entity* kv : this->m_children ) { - if ( !kv ) continue; + for ( uf::Entity* kv : this->getChildren() ) { if ( !kv->isValid() ) continue; kv->destroy(); if ( uf::Entity::deleteChildrenOnDestroy ) delete kv; } - this->m_children.clear(); - this->m_uid = 0; - if ( this->hasParent() ) - this->getParent().removeChild(*this); - + this->getChildren().clear(); + this->unsetUid(); + if ( this->hasParent() ) this->getParent().removeChild(*this); if ( uf::Entity::deleteComponentsOnDestroy ) this->destroyComponents(); } #undef this diff --git a/engine/src/engine/entity/entity.cpp b/engine/src/engine/entity/entity.cpp index 0872c117..5e1cf69c 100644 --- a/engine/src/engine/entity/entity.cpp +++ b/engine/src/engine/entity/entity.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -11,9 +12,16 @@ uf::Entity::~Entity(){ this->destroy(); } bool uf::Entity::isValid() const { -// if ( uf::Entity::memoryPool.size() == 0 ) return false; if ( uf::Entity::memoryPool.size() > 0 && !uf::Entity::memoryPool.exists((void*) this) ) return false; - return 0 < this->m_uid && this->m_uid <= uf::Entity::uids; + return this && 0 < this->m_uid && this->m_uid <= uf::Entity::uids; +} +void uf::Entity::setUid() { + uf::scene::invalidateGraph(); + this->m_uid = ++uf::Entity::uids; +} +void uf::Entity::unsetUid() { + uf::scene::invalidateGraph(); + this->m_uid = 0; } bool uf::Entity::hasParent() const { return this->m_parent; diff --git a/engine/src/engine/instantiator/instantiator.cpp b/engine/src/engine/instantiator/instantiator.cpp index 13ef7fc0..18e0aba5 100644 --- a/engine/src/engine/instantiator/instantiator.cpp +++ b/engine/src/engine/instantiator/instantiator.cpp @@ -4,7 +4,8 @@ #include pod::NamedTypes* uf::instantiator::objects = NULL; -pod::NamedTypes* uf::instantiator::behaviors = NULL; +//pod::NamedTypes* uf::instantiator::behaviors = NULL; +std::unordered_map* uf::instantiator::behaviors = NULL; uf::Entity* uf::instantiator::reuse( size_t size ) { uf::Entity* laxed = NULL; @@ -93,17 +94,18 @@ bool uf::instantiator::valid( uf::Entity* pointer ) { #endif } +void uf::instantiator::registerBehavior( const std::string& name, const pod::Behavior& behavior ) { + if ( !uf::instantiator::behaviors ) uf::instantiator::behaviors = new std::unordered_map;\ + (*uf::instantiator::behaviors)[name] = behavior; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Registered behavior for " << name << " | " << behavior.type); +} void uf::instantiator::registerBinding( const std::string& object, const std::string& behavior ) { if ( !objects ) objects = new pod::NamedTypes; -/* - if ( !uf::instantiator::objects->has( object ) ) { - // uf::instantiator::registerObject( object ); - } -*/ + if ( !behaviors ) behaviors = new std::unordered_map; auto& instantiator = uf::instantiator::objects->get( object ); instantiator.behaviors.emplace_back( behavior ); - if ( UF_INSTANTIATOR_ANNOUNCE ) std::cout << "Registered binding: " << object << " and " << behavior << ": " << instantiator.behaviors.size() << std::endl; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Registered binding: " << object << " and " << behavior << ": " << instantiator.behaviors.size()); } uf::Entity& uf::instantiator::instantiate( const std::string& name ) { @@ -120,14 +122,16 @@ uf::Entity& uf::instantiator::instantiate( const std::string& name ) { void uf::instantiator::bind( const std::string& name, uf::Entity& entity ) { // was actually a behavior name, single bind if ( !uf::instantiator::objects->has( name, false ) ) { - if ( !uf::instantiator::behaviors->has( name, false ) ) return; - auto& behavior = uf::instantiator::behaviors->get( name ); + if ( uf::instantiator::behaviors->count( name ) == 0 ) return; + auto& behavior = (*uf::instantiator::behaviors)[name]; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Attaching " << name << " | " << behavior.type << " to " << entity.getName()); entity.addBehavior(behavior); return; } auto& instantiator = uf::instantiator::objects->get( name ); for ( auto& name : instantiator.behaviors ) { - auto& behavior = uf::instantiator::behaviors->get( name ); + auto& behavior = (*uf::instantiator::behaviors)[name]; + if ( UF_INSTANTIATOR_ANNOUNCE ) UF_DEBUG_MSG("Attaching " << name << " | " << behavior.type << " to " << entity.getName()); entity.addBehavior(behavior); } } @@ -135,14 +139,14 @@ void uf::instantiator::bind( const std::string& name, uf::Entity& entity ) { void uf::instantiator::unbind( const std::string& name, uf::Entity& entity ) { // was actually a behavior name, single bind if ( !uf::instantiator::objects->has( name, false ) ) { - if ( !uf::instantiator::behaviors->has( name, false ) ) return; - auto& behavior = uf::instantiator::behaviors->get( name ); + if ( !uf::instantiator::behaviors->count( name ) == 0 ) return; + auto& behavior = (*uf::instantiator::behaviors)[name]; entity.removeBehavior(behavior); return; } auto& instantiator = uf::instantiator::objects->get( name ); for ( auto& name : instantiator.behaviors ) { - auto& behavior = uf::instantiator::behaviors->get( name ); + auto& behavior = (*uf::instantiator::behaviors)[name]; entity.removeBehavior(behavior); } } \ No newline at end of file diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 16fade92..8090efc4 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -130,14 +130,28 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { }); } void uf::ObjectBehavior::destroy( uf::Object& self ) { - uf::Serializer& metadata = this->getComponent(); - for( auto it = metadata["system"]["hooks"]["alloc"].begin() ; it != metadata["system"]["hooks"]["alloc"].end() ; ++it ) { +#if UF_ENTITY_METADATA_USE_JSON + auto& metadata = this->getComponent(); + ext::json::forEach( metadata["system"]["hooks"]["bound"], [&]( const std::string& key, ext::json::Value& value ){ + ext::json::forEach( value, [&]( ext::json::Value& id ){ + uf::hooks.removeHook(key, id.as()); + }); + }); +/* + for( auto it = metadata["system"]["hooks"]["bound"].begin() ; it != metadata["system"]["hooks"]["bound"].end() ; ++it ) { std::string name = it.key(); - for ( size_t i = 0; i < metadata["system"]["hooks"]["alloc"][name].size(); ++i ) { - size_t id = metadata["system"]["hooks"]["alloc"][name][(int) i].as(); + for ( size_t i = 0; i < metadata["system"]["hooks"]["bound"][name].size(); ++i ) { + size_t id = metadata["system"]["hooks"]["bound"][name][(int) i].as(); uf::hooks.removeHook(name, id); } } +*/ +#else + auto& metadata = this->getComponent(); + for ( auto pair : metadata.hooks.bound ) { + for ( auto id : pair.second ) uf::hooks.removeHook(pair.first, id); + } +#endif if ( this->hasComponent() ) { auto& audio = this->getComponent(); @@ -155,37 +169,49 @@ void uf::ObjectBehavior::destroy( uf::Object& self ) { } void uf::ObjectBehavior::tick( uf::Object& self ) { // listen for metadata file changes - uf::Serializer& metadata = this->getComponent(); +#if UF_ENTITY_METADATA_USE_JSON + auto& metadata = this->getComponent(); +#if !UF_ENV_DREAMCAST if ( metadata["system"]["hot reload"]["enabled"].as() ) { size_t mtime = uf::io::mtime( metadata["system"]["source"].as() ); if ( metadata["system"]["hot reload"]["mtime"].as() < mtime ) { std::cout << "File reload detected: " << ": " << metadata["system"]["source"].as() << ", " << metadata["system"]["hot reload"]["mtime"] << " -> " << mtime << std::endl; metadata["system"]["hot reload"]["mtime"] = mtime; this->reload(); - //this->queueHook("metadata:Reload.%UID%"); } } - +#endif // Call queued hooks { + auto& queue = metadata["system"]["hooks"]["queue"]; if ( !uf::Object::timer.running() ) uf::Object::timer.start(); float curTime = uf::Object::timer.elapsed().asDouble(); uf::Serializer newQueue = ext::json::array(); - if ( !ext::json::isNull( metadata["system"]["hooks"]["queue"] ) ) { - ext::json::forEach(metadata["system"]["hooks"]["queue"], [&](ext::json::Value& member){ + if ( !ext::json::isNull( queue ) ) { + ext::json::forEach(queue, [&](ext::json::Value& member){ if ( !ext::json::isObject(member) ) return; uf::Serializer payload = member["payload"]; std::string name = member["name"].as(); float timeout = member["timeout"].as(); - if ( timeout < curTime ) { - this->callHook( name, payload ); - } else { - newQueue.emplace_back(member); - } + if ( timeout < curTime ) this->callHook( name, payload ); + else newQueue.emplace_back(member); }); } - if ( ext::json::isObject( metadata ) ) metadata["system"]["hooks"]["queue"] = newQueue; + if ( ext::json::isObject( metadata ) ) queue = newQueue; } +#else + auto& metadata = this->getComponent(); + { + auto& queue = metadata.hooks.queue; + if ( !uf::Object::timer.running() ) uf::Object::timer.start(); + float curTime = uf::Object::timer.elapsed().asDouble(); + for ( auto it = queue.begin(); it != queue.end(); ) { + auto& q = *it; + if ( q.timeout < curTime ) { this->callHook( q.name, q.payload ); it = queue.erase( it ); } + else ++it; + } + } +#endif } void uf::ObjectBehavior::render( uf::Object& self ) {} #undef this diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index 77774448..28452d3c 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -16,17 +16,7 @@ UF_BEHAVIOR_REGISTER_CPP(uf::GltfBehavior) #define this (&self) void uf::GltfBehavior::initialize( uf::Object& self ) { - uf::Serializer& metadata = this->getComponent(); - metadata["textures"]["additional"] = ext::json::array(); //Json::Value(Json::arrayValue); - // Default load: GLTF model - this->addHook( "asset:Load.%UID%", [&](ext::json::Value& json){ - std::string filename = json["filename"].as(); - std::string category = json["category"].as(); - if ( category != "" && category != "images" ) return; - if ( category == "" && uf::io::extension(filename) != "png" ) return; - auto& vector = metadata["textures"]["additional"]; - vector[vector.size()] = filename; - }); + auto& metadata = this->getComponent(); this->addHook( "animation:Set.%UID%", [&](ext::json::Value& json){ std::string name = json["name"].as(); @@ -55,7 +45,7 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { } auto& graph = this->getComponent(); uf::Object* objectPointer = graph.root.entity; - objectPointer->process([&]( uf::Entity* entity ) { + graph.root.entity->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& graphic = entity->getComponent(); if ( !(graph.mode & ext::gltf::LoadMode::LOAD) ) { @@ -97,21 +87,6 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { } } } - - for ( int i = 0; i < metadata["textures"]["additional"].size(); ++i ) { - std::string filename = metadata["textures"]["additional"][i].as(); - auto& scene = uf::scene::getCurrentScene(); - auto& assetLoader = scene.getComponent(); - const uf::Image* imagePointer = NULL; - if ( !assetLoader.has(filename) ) return; - imagePointer = &assetLoader.get(filename); - if ( !imagePointer ) continue; - uf::Image image = *imagePointer; - auto& texture = graphic.material.textures.emplace_back(); - texture.loadFromImage( image ); - } - graphic.process = true; - #if UF_USE_VULKAN { auto& shader = graphic.material.getShader("vertex"); @@ -164,21 +139,19 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { } } #endif + graphic.process = true; }); - this->addChild(objectPointer->as()); + this->addChild(graph.root.entity->as()); auto& transform = this->getComponent>(); - objectPointer->getComponent>().reference = &transform; + graph.root.entity->getComponent>().reference = &transform; - objectPointer->initialize(); - objectPointer->process([&]( uf::Entity* entity ) { + graph.root.entity->initialize(); + graph.root.entity->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) { if ( entity->getUid() == 0 ) entity->initialize(); return; } - auto& eMetadata = entity->getComponent(); - eMetadata["textures"]["map"] = metadata["textures"]["map"]; - // if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) uf::instantiator::bind( "RenderBehavior", *entity ); uf::instantiator::bind( "GltfBehavior", *entity ); uf::instantiator::unbind( "RenderBehavior", *entity ); if ( entity->getUid() == 0 ) entity->initialize(); @@ -189,9 +162,8 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { uf::graph::animate( graph, metadata["model"]["animation"].as() ); } if ( metadata["model"]["print animations"].as() ) { - uf::Serializer json = ext::json::array(); //Json::Value(Json::arrayValue); + uf::Serializer json = ext::json::array(); for ( auto pair : graph.animations ) json.emplace_back( pair.first ); - uf::iostream << "Animations found: " << json << "\n"; } } }); @@ -204,54 +176,9 @@ void uf::GltfBehavior::destroy( uf::Object& self ) { } void uf::GltfBehavior::tick( uf::Object& self ) { /* Animation change test */ - if ( this->hasComponent() ) { - std::vector animations = { "wank","walk","sit_wank","run","idle_wank","sit","idle" }; - bool anyNumber = - uf::Window::isKeyPressed("1") || - uf::Window::isKeyPressed("2") || - uf::Window::isKeyPressed("3") || - uf::Window::isKeyPressed("4") || - uf::Window::isKeyPressed("5") || - uf::Window::isKeyPressed("6") || - uf::Window::isKeyPressed("7") || - uf::Window::isKeyPressed("8") || - uf::Window::isKeyPressed("9") || - uf::Window::isKeyPressed("0"); - TIMER(1, anyNumber && ) { - auto& graph = this->getComponent(); - std::string target = ""; - if ( uf::Window::isKeyPressed("1") && animations.size() >= 1 ) target = animations[0]; - else if ( uf::Window::isKeyPressed("2") && animations.size() >= 2 ) target = animations[1]; - else if ( uf::Window::isKeyPressed("3") && animations.size() >= 3 ) target = animations[2]; - else if ( uf::Window::isKeyPressed("4") && animations.size() >= 4 ) target = animations[3]; - else if ( uf::Window::isKeyPressed("5") && animations.size() >= 5 ) target = animations[4]; - else if ( uf::Window::isKeyPressed("6") && animations.size() >= 6 ) target = animations[5]; - else if ( uf::Window::isKeyPressed("7") && animations.size() >= 7 ) target = animations[6]; - else if ( uf::Window::isKeyPressed("8") && animations.size() >= 8 ) target = animations[7]; - else if ( uf::Window::isKeyPressed("9") && animations.size() >= 9 ) target = animations[8]; - else if ( uf::Window::isKeyPressed("0") && animations.size() >= 10 ) target = animations[9]; - std::cout << "CHANGING ANIMATION TO " << target << std::endl; - // graph.animationSettings.loop = false; - uf::graph::animate( graph, target, 1 / 0.125f ); - } - } - /* Update animations */ if ( this->hasComponent() ) { auto& graph = this->getComponent(); - if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { - uf::graph::update( graph ); - } - /* - auto& transform = this->getComponent>(); - auto& node = graph.node->children.size() == 1 ? *graph.node->children[0] : *graph.node; - pod::Matrix4f nodeMatrix = node.transform.model; - pod::Node* currentParent = uf::graph::find(graph, node.parent); - while ( currentParent ) { - nodeMatrix = currentParent->transform.model * nodeMatrix; - currentParent = uf::graph::find(graph, currentParent->parent); - } - transform.model = nodeMatrix; - */ + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) uf::graph::update( graph ); } #if UF_USE_OPENGL /* Update uniforms */ if ( this->hasComponent() ) { @@ -317,42 +244,6 @@ void uf::GltfBehavior::tick( uf::Object& self ) { auto& storageBuffer = *graphic.getStorageBuffer("Models"); graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/ ); } - /* - if ( graph.materials.empty() && graphic.hasStorage("Materials") ) { - auto& shader = graphic.material.getShader("fragment"); - std::vector materials( graph.materials.size() ); - for ( size_t i = 0; i < graph.materials.size(); ++i ) { - materials[i] = graph.materials[i].storage; - materials[i].indexMappedTarget = graph.mode & ext::gltf::LoadMode::ATLAS ? 0 : i; - materials[i].factorMappedBlend = graph.mode & ext::gltf::LoadMode::ATLAS ? 1.0f : 0.0f; - } - { - size_t texturesLen = graphic.material.textures.size(); - ext::json::forEach(metadata["textures"]["map"], [&]( const std::string& key, const ext::json::Value& mapping ){ - uint32_t from = std::stoi(key); - if ( mapping["alpha cutoff"].is() ) { - materials[from].factorAlphaCutoff = mapping["alpha cutoff"].as(); - } - if ( mapping["to"].is() ) { - uint32_t to = mapping["to"].as(); - float blend = 1.0f; - if ( mapping["factor"].as() == "sin(time)" ) { - blend = sin(uf::physics::time::current)*0.5f+0.5f; - } else if ( mapping["factor"].as() == "cos(time)" ) { - blend = cos(uf::physics::time::current)*0.5f+0.5f; - } else if ( mapping["factor"].is() ) { - blend = mapping["factor"].as(); - } - if ( from >= texturesLen || to >= texturesLen ) return; - materials[from].indexMappedTarget = to; - materials[from].factorMappedBlend = blend; - } - }); - } - auto& storageBuffer = *graphic.getStorageBuffer("Materials"); - graphic.updateBuffer( (void*) materials.data(), materials.size() * sizeof(pod::Material::Storage), graph.root.materialBufferIndex /storageBuffer/ ); - } - */ } #endif } diff --git a/engine/src/engine/object/behaviors/loading.cpp b/engine/src/engine/object/behaviors/loading.cpp index 13c70f65..99b558db 100644 --- a/engine/src/engine/object/behaviors/loading.cpp +++ b/engine/src/engine/object/behaviors/loading.cpp @@ -18,7 +18,7 @@ void uf::LoadingBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); this->addHook( "system:Load.Finished.%UID%", [&](ext::json::Value& json){ metadata["system"]["loaded"] = true; - this->removeBehavior(); + this->removeBehavior(pod::Behavior{.type = uf::LoadingBehavior::type}); auto& parent = this->getParent(); auto& scene = uf::scene::getCurrentScene(); @@ -27,29 +27,23 @@ void uf::LoadingBehavior::initialize( uf::Object& self ) { uf::Serializer payload; payload["uid"] = parent.getUid(); parent.getParent().removeChild(parent); - - std::function filter = [&]( uf::Entity* entity ) { + parent.process([&]( uf::Entity* entity ) { if ( !entity || !entity->isValid() || !entity->hasComponent>() ) return; auto& transform = entity->getComponent>(); transform.scale = { 0, 0, 0 }; entity->render(); - }; - parent.process(filter); - + }); scene.queueHook("system:Destroy", payload); } return; }); -} -void uf::LoadingBehavior::destroy( uf::Object& self ) { - } void uf::LoadingBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); if ( metadata["system"]["loaded"].as() ) return; size_t loading = 0; size_t loaded = 1; - std::function filter = [&]( uf::Entity* entity ) { + this->process([&]( uf::Entity* entity ) { if ( !entity || !entity->isValid() || !entity->hasComponent() ) return; auto& metadata = entity->getComponent(); if ( metadata["system"]["load"]["ignore"].is() ) return; @@ -57,38 +51,12 @@ void uf::LoadingBehavior::tick( uf::Object& self ) { ++loading; if ( metadata["system"]["load"]["progress"].as() < metadata["system"]["load"]["total"].as() ) return; ++loaded; - }; - this->process(filter); + }); if ( loading == loaded ) { metadata["system"]["loaded"] = true; this->callHook("system:Load.Finished.%UID%"); } -/* - auto& metadata = this->getComponent(); - if ( !metadata["system"]["loaded"].as() ) { - size_t loading = 0; - size_t loaded = 0; - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity || !entity->isValid() || !entity->hasComponent() ) return; - auto& metadata = entity->getComponent(); - if ( ext::json::isNull( metadata["system"]["load"] ) ) return; - ++loading; - if ( metadata["system"]["load"]["progress"].as() < 1.0f ) return; - ++loaded; - }; - this->process(filter); - - if ( loading == loaded ) { - this->callHook("system:Load.Finished.%UID%"); - } - auto& metadata = this->getComponent(); - if ( metadata["system"]["load"]["progress"].as() >= 1.0f ) { - this->callHook("system:Load.Finished.%UID%"); - } - } -*/ -} -void uf::LoadingBehavior::render( uf::Object& self ) { - } +void uf::LoadingBehavior::render( uf::Object& self ) {} +void uf::LoadingBehavior::destroy( uf::Object& self ) {} #undef this \ No newline at end of file diff --git a/engine/src/engine/object/behaviors/lua.cpp b/engine/src/engine/object/behaviors/lua.cpp index c221d216..da2147e8 100644 --- a/engine/src/engine/object/behaviors/lua.cpp +++ b/engine/src/engine/object/behaviors/lua.cpp @@ -28,21 +28,12 @@ void uf::LuaBehavior::initialize( uf::Object& self ) { assetPointer = &assetLoader.get(filename); if ( !assetPointer ) return; pod::LuaScript script = *assetPointer; - // script.header = "local ent = entities.get("+ std::to_string((uint) this->getUid()) +")"; script.env["ent"] = &this->as(); ext::lua::run( script ); - - return; }); #endif } -void uf::LuaBehavior::destroy( uf::Object& self ) { - -} -void uf::LuaBehavior::tick( uf::Object& self ) { - -} -void uf::LuaBehavior::render( uf::Object& self ) { - -} +void uf::LuaBehavior::destroy( uf::Object& self ) {} +void uf::LuaBehavior::tick( uf::Object& self ) {} +void uf::LuaBehavior::render( uf::Object& self ) {} #undef this \ No newline at end of file diff --git a/engine/src/engine/object/behaviors/render.cpp b/engine/src/engine/object/behaviors/render.cpp index 629003a9..6f687576 100644 --- a/engine/src/engine/object/behaviors/render.cpp +++ b/engine/src/engine/object/behaviors/render.cpp @@ -16,7 +16,6 @@ UF_BEHAVIOR_REGISTER_CPP(uf::RenderBehavior) #define this (&self) void uf::RenderBehavior::initialize( uf::Object& self ) {} -void uf::RenderBehavior::destroy( uf::Object& self ) {} void uf::RenderBehavior::tick( uf::Object& self ) {} void uf::RenderBehavior::render( uf::Object& self ) { if ( !this->hasComponent() ) return; @@ -80,4 +79,5 @@ void uf::RenderBehavior::render( uf::Object& self ) { #endif #endif } +void uf::RenderBehavior::destroy( uf::Object& self ) {} #undef this \ No newline at end of file diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index ea04f805..59d3717a 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -19,27 +20,24 @@ UF_OBJECT_REGISTER_BEGIN(uf::Object) UF_OBJECT_REGISTER_BEHAVIOR(uf::ObjectBehavior) UF_OBJECT_REGISTER_END() uf::Object::Object() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Object) -/* -void uf::Object::queueHook( const std::string& name, const std::string& payload, double timeout ) { - if ( !uf::Object::timer.running() ) uf::Object::timer.start(); - float start = uf::Object::timer.elapsed().asDouble(); - uf::Serializer queue; - queue["name"] = name; - queue["payload"] = uf::Serializer{payload}; - queue["timeout"] = start + timeout; - uf::Serializer& metadata = this->getComponent(); - metadata["system"]["hooks"]["queue"].emplace_back(queue); -} -*/ void uf::Object::queueHook( const std::string& name, const ext::json::Value& payload, double timeout ) { if ( !uf::Object::timer.running() ) uf::Object::timer.start(); - float start = uf::Object::timer.elapsed().asDouble(); + double start = uf::Object::timer.elapsed().asDouble(); +#if UF_ENTITY_METADATA_USE_JSON uf::Serializer queue; queue["name"] = name; queue["payload"] = payload; queue["timeout"] = start + timeout; uf::Serializer& metadata = this->getComponent(); metadata["system"]["hooks"]["queue"].emplace_back(queue); +#else + auto& metadata = this->getComponent(); + auto& queue = metadata.hooks.queue.emplace_back(uf::ObjectBehavior::Metadata::Queued{ + .name = name, + .payload = payload, + .timeout = start + timeout, + }); +#endif } std::string uf::Object::formatHookName( const std::string& n, size_t uid, bool fetch ) { if ( fetch ) { @@ -81,39 +79,6 @@ uf::Hooks::return_t uf::Object::callHook( const std::string& name, const ext::js uf::Hooks::return_t uf::Object::callHook( const std::string& name, const uf::Serializer& serializer ) { return uf::hooks.call( this->formatHookName( name ), (const ext::json::Value&) serializer ); } -/* -std::vector uf::Object::callHook( const std::string& name, const ext::json::Value& payload ) { - std::vector jsons; - auto results = uf::hooks.call( this->formatHookName( name ), payload ); - for ( auto& result : results ) { - if ( result.is() ) jsons.emplace_back( uf::Serializer(result.as()) ); - else if ( result.is() ) jsons.emplace_back( result.as() ); - else if ( result.is() ) jsons.emplace_back( result.as() ); - } - return jsons; -} -*/ -/* -std::vector uf::Object::callHook( const std::string& name, const std::string& payload ) { - std::vector strings; - auto results = uf::hooks.call( this->formatHookName( name ), payload ); - for ( auto& result : results ) { - if ( result.is() ) { - strings.emplace_back( result.as() ); - } - } - return strings; -} -*/ -/* -std::size_t uf::Object::addHook( const std::string& name, const uf::HookHandler::Readable::function_t& callback ) { - std::string parsed = this->formatHookName( name ); - std::size_t id = uf::hooks.addHook( parsed, callback ); - uf::Serializer& metadata = this->getComponent(); - metadata["system"]["hooks"]["alloc"][parsed].emplace_back(id); - return id; -} -*/ bool uf::Object::load( const std::string& f, bool inheritRoot ) { uf::Serializer json; std::string root = ""; @@ -152,14 +117,8 @@ bool uf::Object::reload( bool hard ) { transform = uf::transform::decode( json["transform"], transform ); transform.reference = reference; } -/* - for ( auto it = json["metadata"].begin(); it != json["metadata"].end(); ++it ) { - metadata[it.key()] = json["metadata"][it.key()]; - } -*/ payload["new"] = metadata; - uf::iostream << "Updated metadata for " << uf::string::toString( this ) << "\n"; - + UF_DEBUG_MSG("Updated metadata for " << uf::string::toString( this )); this->queueHook("object:Reload.%UID%", payload); return true; } @@ -177,11 +136,8 @@ bool uf::Object::load( const uf::Serializer& _json ) { do { std::string filename = chain["import"].is() ? chain["import"].as() : chain["include"].as(); filename = grabURI( filename, root ); - // std::cout << "Importing: " << filename << std::endl; chain.readFromFile( filename ); - // set new root root = uf::io::directory( filename ); - // get real path for assets to merge separately ext::json::forEach(chain["assets"], [&](ext::json::Value& value){ if ( ext::json::isObject( value ) ) value["filename"] = grabURI( value["filename"].as(), root ); else value = grabURI( value.as(), root ); diff --git a/engine/src/engine/scene/behavior.cpp b/engine/src/engine/scene/behavior.cpp index 5247d3c3..8c7435ac 100644 --- a/engine/src/engine/scene/behavior.cpp +++ b/engine/src/engine/scene/behavior.cpp @@ -6,7 +6,6 @@ UF_BEHAVIOR_ENTITY_CPP_BEGIN(uf::Scene) #define this ((uf::Scene*) &self) void uf::SceneBehavior::initialize( uf::Object& self ) { -// uf::renderer::scenes.push_back(this); uf::renderer::states::rebuild = true; this->addHook( "system:Renderer.QueueRebuild", [&](ext::json::Value& json){ @@ -23,10 +22,8 @@ void uf::SceneBehavior::initialize( uf::Object& self ) { this->queueHook("system:Renderer.QueueRebuild"); }); } -void uf::SceneBehavior::tick( uf::Object& self ) { -} -void uf::SceneBehavior::render( uf::Object& self ) { -} +void uf::SceneBehavior::tick( uf::Object& self ) {} +void uf::SceneBehavior::render( uf::Object& self ) {} void uf::SceneBehavior::destroy( uf::Object& self ) { uf::renderer::states::rebuild = true; } diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index 762b3182..00e8cf31 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -37,21 +37,21 @@ const uf::Entity& uf::Scene::getController() const { uf::Scene& scene = *const_cast(this); return scene.getController(); } -std::vector uf::scene::scenes; -uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& filename ) { - uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; -// uf::scene::scenes.insert(uf::scene::scenes.begin(), scene); - uf::scene::scenes.emplace_back( scene ); - +std::vector uf::scene::scenes; +std::vector uf::scene::graph; +bool uf::scene::queuedInvalidation = false; +bool uf::scene::useGraph = true; + +uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& filename ) { std::string target = name; - + uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; + uf::scene::scenes.emplace_back( scene ); +/* std::regex regex("^(TestScene_?)?(.+?)(_?Scene)?$"); std::smatch match; - - if ( std::regex_search( target, match, regex ) ) { - target = match[2]; - } + if ( std::regex_search( target, match, regex ) ) target = match[2]; +*/ target = uf::string::lowercase( target ); scene->load(filename != "" ? filename : "./scenes/" + target + "/scene.json"); scene->initialize(); @@ -59,10 +59,7 @@ uf::Scene& uf::scene::loadScene( const std::string& name, const std::string& fil } uf::Scene& uf::scene::loadScene( const std::string& name, const uf::Serializer& data ) { uf::Scene* scene = uf::instantiator::objects->has( name ) ? (uf::Scene*) &uf::instantiator::instantiate( name ) : new uf::Scene; - -// uf::scene::scenes.insert(uf::scene::scenes.begin(), scene); uf::scene::scenes.emplace_back( scene ); - if ( data != "" ) scene->load(data); scene->initialize(); return *scene; @@ -71,33 +68,57 @@ void uf::scene::unloadScene() { uf::Scene* current = uf::scene::scenes.back(); current->destroy(); uf::scene::scenes.pop_back(); - //delete current; } uf::Scene& uf::scene::getCurrentScene() { return *uf::scene::scenes.back(); } +void uf::scene::invalidateGraph() { + uf::scene::queuedInvalidation = true; +} +std::vector uf::scene::generateGraph() { + // invalidate it by clearing the graph + if ( uf::scene::queuedInvalidation ) { + uf::scene::graph.clear(); + uf::scene::queuedInvalidation = false; + } + + if ( !uf::scene::graph.empty() ) return uf::scene::graph; + + for ( uf::Scene* scene : uf::scene::scenes ) { + if ( !scene ) continue; + scene->process([&]( uf::Entity* entity ) { + auto& metadata = entity->getComponent(); + if ( !metadata.system.ignoreGraph ) uf::scene::graph.emplace_back(entity); + }); + } + uf::renderer::states::rebuild = true; + return uf::scene::graph; +} + void uf::scene::tick() { - // uf::scene::getCurrentScene().tick(); +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + uf::Timer TIMER_TRACE; +// UF_DEBUG_MSG("==== START TICK ===="); + for ( auto it = graph.rbegin(); it != graph.rend(); ++it ) { + (*it)->tick(); +// UF_DEBUG_MSG(TIMER_TRACE.elapsed().asMicroseconds() << " us\t" << (*it)->getName() << ": " << (*it)->getUid()); + } +// UF_DEBUG_MSG("==== END TICK ===="); +} else { for ( auto scene : scenes ) scene->tick(); } +} void uf::scene::render() { - // uf::scene::getCurrentScene().render(); +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto it = graph.rbegin(); it != graph.rend(); ++it ) { + (*it)->render(); + } +} else { for ( auto scene : scenes ) scene->render(); } +} void uf::scene::destroy() { - while ( !scenes.empty() ) { - unloadScene(); - } -} -/* -uf::Camera& uf::Scene::getCamera() { - if ( !::camera ) ::camera = this->getPlayer().getComponentPointer(); - return *::camera; -} -uf::Player& uf::Scene::getPlayer() { - return *((uf::Player*) this->findByName("Player")); -} -const uf::Player& uf::Scene::getPlayer() const { - return *((const uf::Player*) this->findByName("Player")); -} -*/ \ No newline at end of file + while ( !scenes.empty() ) unloadScene(); +} \ No newline at end of file diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 807ffc04..f4da6f44 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -2,8 +2,14 @@ #include #include #include +#include #define UF_VK_TESTING 1 +#if UF_ENV_DREAMCAST + #define UF_GRAPH_LOAD_MULTITHREAD 0 +#else + #define UF_GRAPH_LOAD_MULTITHREAD 1 +#endif namespace { void initializeGraphics( pod::Graph& graph, uf::Object& entity ) { @@ -33,6 +39,7 @@ namespace { auto& atlas = *graph.atlas; auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( atlas.getAtlas() ); + atlas.getAtlas().clear(); } else { graphic.material.textures.emplace_back().aliasTexture(uf::renderer::Texture2D::empty); for ( auto& image : graph.images ) { @@ -49,6 +56,7 @@ namespace { } } texture.loadFromImage( image ); + image.clear(); } } #endif @@ -155,6 +163,7 @@ void uf::graph::process( pod::Graph& graph ) { } } texture.loadFromImage( image ); + image.clear(); } else { for ( size_t i = 0; i < graph.textures.size() && i < graph.images.size(); ++i ) { auto& image = graph.images[i]; @@ -171,6 +180,7 @@ void uf::graph::process( pod::Graph& graph ) { } } texture.loadFromImage( image ); + image.clear(); } } #endif @@ -238,17 +248,18 @@ void uf::graph::process( pod::Graph& graph ) { auto& mesh = entity->getComponent(); auto& metadata = entity->getComponent(); std::string nodeName = metadata["system"]["graph"]["name"].as(); - #if 0 + #if 1 if ( graph.mode & ext::gltf::LoadMode::NORMALS ) { // bool invert = false; bool INVERTED = graph.mode & ext::gltf::LoadMode::INVERT; - if ( !mesh.indices.empty() ) { + if ( mesh.indices.empty() ) { for ( size_t i = 0; i < mesh.vertices.size(); i+=3 ) { auto& a = mesh.vertices[i+(INVERTED ? 0 : 0)].position; auto& b = mesh.vertices[i+(INVERTED ? 1 : 2)].position; auto& c = mesh.vertices[i+(INVERTED ? 2 : 1)].position; pod::Vector3f normal = uf::vector::normalize( uf::vector::cross( b - a, c - a ) ); + mesh.vertices[i+0].normal = normal; mesh.vertices[i+1].normal = normal; mesh.vertices[i+2].normal = normal; @@ -367,6 +378,16 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) if ( !info["preserve position"].as() ) childTransform.position = flatten.position; if ( !info["preserve orientation"].as() ) childTransform.orientation = flatten.orientation; } + if ( info["ignore"].as() ) { + auto& metadata = entity.getComponent(); + metadata.system.ignoreGraph = true; + } + #if UF_ENV_DREAMCAST + if ( info["superfluous"].as() ) { + auto& metadata = entity.getComponent(); + metadata.system.ignoreGraph = true; + } + #endif } // create as light for ( auto& l : graph.lights ) { @@ -890,7 +911,7 @@ namespace { pod::Graph uf::graph::load( const std::string& filename, ext::gltf::load_mode_t mode, const uf::Serializer& metadata ) { #if UF_ENV_DREAMCAST - #define UF_DEBUG_TRACE_MSG(X) UF_DEBUG_MSG(X); malloc_stats(); + #define UF_DEBUG_TRACE_MSG(X) UF_DEBUG_MSG(X); //malloc_stats(); uf::Timer timer(false); if ( !timer.running() ) timer.start(); #else @@ -905,7 +926,120 @@ pod::Graph uf::graph::load( const std::string& filename, ext::gltf::load_mode_t graph.name = serializer["name"].as(); graph.mode = mode; // serializer["mode"].as(); graph.metadata = metadata; // serializer["metadata"]; - +#if UF_GRAPH_LOAD_MULTITHREAD + std::vector> jobs; + jobs.emplace_back([&]{ + // load mesh information + UF_DEBUG_TRACE_MSG("Reading meshes..."); + graph.meshes.reserve( serializer["meshes"].size() ); + ext::json::forEach( serializer["meshes"], [&]( ext::json::Value& value ){ + auto& mesh = graph.meshes.emplace_back(); + if ( value.is() ) { + UF_DEBUG_TRACE_MSG(directory + "/" + value.as()); + uf::Serializer json; + json.readFromFile( directory + "/" + value.as() ); + decode( json, mesh ); + + } else { + decode( value, mesh ); + } + }); + return 0; + }); + jobs.emplace_back([&]{ + // load images + UF_DEBUG_TRACE_MSG("Reading images..."); + graph.images.reserve( serializer["images"].size() ); + ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){ + auto& image = graph.images.emplace_back(); + if ( value.is() ) { + std::string filename = directory + "/" + value.as(); + #if UF_ENV_DREAMCAST + std::string dtex = uf::string::replace( filename, ".png", ".dtex" ); + if ( uf::io::exists(dtex) ) filename = dtex; + #endif + UF_DEBUG_TRACE_MSG("Reading image " << filename); + image.open(filename, false); + } else { + decode( value, image ); + } + }); + return 0; + }); + jobs.emplace_back([&]{ + // load texture information + UF_DEBUG_TRACE_MSG("Reading texture information..."); + graph.textures.reserve( serializer["textures"].size() ); + ext::json::forEach( serializer["textures"], [&]( ext::json::Value& value ){ + decode( value, graph.textures.emplace_back() ); + }); + return 0; + }); + jobs.emplace_back([&]{ + // load sampler information + UF_DEBUG_TRACE_MSG("Reading sampler information..."); + graph.samplers.reserve( serializer["samplers"].size() ); + ext::json::forEach( serializer["samplers"], [&]( ext::json::Value& value ){ + decode( value, graph.samplers.emplace_back() ); + }); + return 0; + }); + jobs.emplace_back([&]{ + // load material information + UF_DEBUG_TRACE_MSG("Reading material information..."); + graph.materials.reserve( serializer["materials"].size() ); + ext::json::forEach( serializer["materials"], [&]( ext::json::Value& value ){ + decode( value, graph.materials.emplace_back() ); + }); + return 0; + }); + jobs.emplace_back([&]{ + // load light information + UF_DEBUG_TRACE_MSG("Reading lighting information..."); + graph.lights.reserve( serializer["lighting"].size() ); + ext::json::forEach( serializer["lighting"], [&]( ext::json::Value& value ){ + decode( value, graph.lights.emplace_back() ); + }); + return 0; + }); + jobs.emplace_back([&]{ + // load animation information + UF_DEBUG_TRACE_MSG("Reading animation information..."); + graph.animations.reserve( serializer["animations"].size() ); + ext::json::forEach( serializer["animations"], [&]( ext::json::Value& value ){ + if ( value.is() ) { + uf::Serializer json; + json.readFromFile( directory + "/" + value.as() ); + std::string key = json["name"].as(); + decode( json, graph.animations[key] ); + } else { + std::string key = value["name"].as(); + decode( value, graph.animations[key] ); + } + }); + return 0; + }); + jobs.emplace_back([&]{ + // load skin information + UF_DEBUG_TRACE_MSG("Reading skinning information..."); + graph.skins.reserve( serializer["skins"].size() ); + ext::json::forEach( serializer["skins"], [&]( ext::json::Value& value ){ + decode( value, graph.skins.emplace_back() ); + }); + return 0; + }); + jobs.emplace_back([&]{ + // load node information + UF_DEBUG_TRACE_MSG("Reading nodes..."); + graph.nodes.reserve( serializer["nodes"].size() ); + ext::json::forEach( serializer["nodes"], [&]( ext::json::Value& value ){ + decode( value, graph.nodes.emplace_back() ); + }); + decode(serializer["root"], graph.root); + return 0; + }); + if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); +#else // load mesh information UF_DEBUG_TRACE_MSG("Reading meshes..."); graph.meshes.reserve( serializer["meshes"].size() ); @@ -927,8 +1061,13 @@ pod::Graph uf::graph::load( const std::string& filename, ext::gltf::load_mode_t ext::json::forEach( serializer["images"], [&]( ext::json::Value& value ){ auto& image = graph.images.emplace_back(); if ( value.is() ) { - UF_DEBUG_TRACE_MSG("Reading image " << directory << "/" << value.as()); - image.open(directory + "/" + value.as(), false); + std::string filename = directory + "/" + value.as(); + #if UF_ENV_DREAMCAST + std::string dtex = uf::string::replace( filename, ".png", ".dtex" ); + if ( uf::io::exists(dtex) ) filename = dtex; + #endif + UF_DEBUG_TRACE_MSG("Reading image " << filename); + image.open(filename, false); } else { decode( value, image ); } @@ -984,7 +1123,7 @@ pod::Graph uf::graph::load( const std::string& filename, ext::gltf::load_mode_t decode( value, graph.nodes.emplace_back() ); }); decode(serializer["root"], graph.root); - +#endif // generate atlas if ( graph.mode & ext::gltf::LoadMode::ATLAS ) { if ( graph.atlas ) delete graph.atlas; graph.atlas = new uf::Atlas; UF_DEBUG_TRACE_MSG("Generating atlas..."); @@ -1161,16 +1300,99 @@ void uf::graph::save( const std::string& filename, const pod::Graph& graph ) { uf::Serializer serializer; // store metadata +/* serializer["name"] = graph.name; serializer["mode"] = graph.mode; serializer["metadata"] = graph.metadata; serializer["metadata"]["mesh optimization"] = 0; +*/ bool saveSeparately = graph.metadata["debug"]["export"]["split"].as(); bool compression = graph.metadata["debug"]["export"]["compression"].as(); // store images - if ( saveSeparately ) { - uf::io::mkdir(directory); - } + if ( saveSeparately ) uf::io::mkdir(directory); + +#if UF_GRAPH_LOAD_MULTITHREAD + std::vector> jobs; + jobs.emplace_back([&]{ + ext::json::reserve( serializer["images"], graph.images.size() ); + if ( saveSeparately ) { + for ( size_t i = 0; i < graph.images.size(); ++i ) { + std::string f = "image."+std::to_string(i)+(compression?".jpg":".png"); + graph.images[i].save(directory + "/" + f); + serializer["images"].emplace_back(f); + } + } else { + for ( auto& image : graph.images ) serializer["images"].emplace_back( encode(image, compression) ); + } + return 0; + }); + jobs.emplace_back([&]{ + // store texture information + ext::json::reserve( serializer["textures"], graph.textures.size() ); + for ( auto& texture : graph.textures ) serializer["textures"].emplace_back( encode(texture, compression) ); + return 0; + }); + jobs.emplace_back([&]{ + // store sampler information + ext::json::reserve( serializer["samplers"], graph.samplers.size() ); + for ( auto& sampler : graph.samplers ) serializer["samplers"].emplace_back( encode(sampler, compression) ); + return 0; + }); + jobs.emplace_back([&]{ + // store material information + ext::json::reserve( serializer["materials"], graph.materials.size() ); + for ( auto& material : graph.materials ) serializer["materials"].emplace_back( encode(material, compression) ); + return 0; + }); + jobs.emplace_back([&]{ + // store light information + ext::json::reserve( serializer["lighting"], graph.lights.size() ); + for ( auto& light : graph.lights ) serializer["lighting"].emplace_back( encode(light, compression) ); + return 0; + }); + jobs.emplace_back([&]{ + // store animation information + ext::json::reserve( serializer["animations"], graph.animations.size() ); + if ( saveSeparately ) { + for ( auto pair : graph.animations ) { + std::string f = "animation."+pair.first+".json"; + encode(pair.second, compression).writeToFile(directory+"/" + f); + serializer["animations"].emplace_back(f); + } + } else { + for ( auto pair : graph.animations ) serializer["animations"][pair.first] = encode(pair.second, compression); + } + return 0; + }); + jobs.emplace_back([&]{ + // store skin information + ext::json::reserve( serializer["skins"], graph.skins.size() ); + for ( auto& skin : graph.skins ) serializer["skins"].emplace_back( encode(skin, compression) ); + return 0; + }); + jobs.emplace_back([&]{ + // store mesh information + ext::json::reserve( serializer["meshes"], graph.meshes.size() ); + if ( saveSeparately ) { + for ( size_t i = 0; i < graph.meshes.size(); ++i ) { + std::string f = "mesh."+std::to_string(i)+".json"; + encode(graph.meshes[i], compression).writeToFile(directory+"/" + f); + serializer["meshes"].emplace_back(f); + } + } else { + for ( auto& mesh : graph.meshes ) serializer["meshes"].emplace_back( encode(mesh, compression) ); + } + return 0; + }); + jobs.emplace_back([&]{ + // store node information + ext::json::reserve( serializer["nodes"], graph.nodes.size() ); + for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, compression) ); + serializer["root"] = encode(graph.root, compression); + return 0; + }); + if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); +#else ext::json::reserve( serializer["images"], graph.images.size() ); if ( saveSeparately ) { for ( size_t i = 0; i < graph.images.size(); ++i ) { @@ -1222,6 +1444,7 @@ void uf::graph::save( const std::string& filename, const pod::Graph& graph ) { ext::json::reserve( serializer["nodes"], graph.nodes.size() ); for ( auto& node : graph.nodes ) serializer["nodes"].emplace_back( encode(node, compression) ); serializer["root"] = encode(graph.root, compression); +#endif if ( saveSeparately ) target = directory + "/graph.json"; if ( graph.metadata["debug"]["export"]["precision"].is() ) { diff --git a/engine/src/ext/lua/usertypes/asset.cpp b/engine/src/ext/lua/usertypes/asset.cpp index 05c3d5c2..82c46613 100644 --- a/engine/src/ext/lua/usertypes/asset.cpp +++ b/engine/src/ext/lua/usertypes/asset.cpp @@ -1,7 +1,6 @@ #include #if UF_USE_LUA #include - UF_LUA_REGISTER_USERTYPE(uf::Asset, UF_LUA_REGISTER_USERTYPE_DEFINE( load, []( uf::Asset& asset, sol::variadic_args va ) { auto it = va.begin(); diff --git a/engine/src/ext/lua/usertypes/audio.cpp b/engine/src/ext/lua/usertypes/audio.cpp index bb090bbd..1e016785 100644 --- a/engine/src/ext/lua/usertypes/audio.cpp +++ b/engine/src/ext/lua/usertypes/audio.cpp @@ -1,7 +1,6 @@ #include #if UF_USE_LUA #include - UF_LUA_REGISTER_USERTYPE(uf::Audio, sol::call_constructor, sol::initializers( []( uf::Audio& self ){}, []( uf::Audio& self, const std::string& filename = "", double volume = 1 ){ diff --git a/engine/src/ext/lua/usertypes/camera.cpp b/engine/src/ext/lua/usertypes/camera.cpp index 9a3b30a8..a8f3beb6 100644 --- a/engine/src/ext/lua/usertypes/camera.cpp +++ b/engine/src/ext/lua/usertypes/camera.cpp @@ -1,7 +1,6 @@ #include #if UF_USE_LUA #include - UF_LUA_REGISTER_USERTYPE(uf::Camera, UF_LUA_REGISTER_USERTYPE_DEFINE( getTransform, []( uf::Camera& self ) { return self.getTransform(); diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index 42bca2c2..0762b561 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -68,11 +68,11 @@ namespace { UF_LUA_UPDATE_COMPONENT(uf::Camera) }, "bind", [](uf::Object& self, const std::string& type, sol::protected_function fun ) { - if ( !self.hasBehavior() ) uf::instantiator::bind( "LuaBehavior", self ); + if ( !self.hasBehavior({.type = uf::LuaBehavior::type}) ) uf::instantiator::bind( "LuaBehavior", self ); pod::Behavior* behaviorPointer = NULL; auto& behaviors = self.getBehaviors(); for ( auto& b : behaviors ) { - if ( b.type != self.getType() ) continue; + if ( b.type != uf::LuaBehavior::type ) continue; behaviorPointer = &b; break; } diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp index 649c8a8e..b2b854f8 100644 --- a/engine/src/ext/opengl/commands.cpp +++ b/engine/src/ext/opengl/commands.cpp @@ -254,6 +254,7 @@ void ext::opengl::CommandBuffer::submit() { GL_ERROR_CHECK(glClearColor(info->color[0], info->color[1], info->color[2], info->color[3])); GL_ERROR_CHECK(glClearDepth(info->depth)); GL_ERROR_CHECK(glClear(info->bits)); + GL_ERROR_CHECK(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &info->color[0])); } break; case ext::opengl::enums::Command::VIEWPORT: { InfoViewport* info = (InfoViewport*) header; @@ -330,6 +331,7 @@ void ext::opengl::CommandBuffer::submit() { vertexBufferInfo = NULL; indexBufferInfo = NULL; } break; + /* case ext::opengl::enums::Command::GENERATE_TEXTURE: { InfoGenerateTexture* info = (InfoGenerateTexture*) header; if ( state == 2 && VERBOSE_SUBMIT ) std::cout << "["<descriptor.image << " | " << info->data << "\n"; @@ -353,6 +355,7 @@ void ext::opengl::CommandBuffer::submit() { } GL_ERROR_CHECK(glBindTexture(info->descriptor.viewType, 0)); } break; + */ default: { if ( state == 2 && VERBOSE_SUBMIT ) { std::cout << "["<type << ": " << info.data().len << std::endl;; diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index 781d1b97..b9cf2519 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -138,6 +138,7 @@ void UF_API ext::opengl::removeRenderMode( ext::opengl::RenderMode* mode, bool f if ( free ) delete mode; ext::opengl::states::rebuild = true; } + void UF_API ext::opengl::initialize() { device.initialize(); // swapchain.initialize( device ); @@ -168,13 +169,10 @@ void UF_API ext::opengl::initialize() { renderMode->createCommandBuffers(); } } - if ( !jobs.empty() ) { - uf::thread::batchWorkers( jobs ); - } + if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); // bind shaders -#if !UF_ENV_DREAMCAST { - ext::opengl::Shader::bind( "./data/shaders/gltf/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { + ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/instanced.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { if ( !userdata ) return; ext::gltf::mesh_t::vertex_t* verticesSrc = (ext::gltf::mesh_t::vertex_t*) userdata; @@ -195,10 +193,12 @@ void UF_API ext::opengl::initialize() { uf::renderer::VertexDescriptor vertexAttributePosition, vertexAttributeUv, + vertexAttributeNormal, vertexAttributeId; for ( auto& attribute : graphic.descriptor.geometry.attributes.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; + else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; else if ( attribute.name == "id" ) vertexAttributeId = attribute; } @@ -223,19 +223,22 @@ void UF_API ext::opengl::initialize() { const pod::Vector3f& position = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); const pod::Vector2ui& id = *((pod::Vector2ui*) (vertexSrc + vertexAttributeId.offset)); + const pod::Vector3f& normal = *((pod::Vector3f*) (vertexSrc + vertexAttributeNormal.offset)); const pod::Vector2f& uv = *((pod::Vector2f*) (vertexSrc + vertexAttributeUv.offset)); pod::Vector3f& positionDst = *((pod::Vector3f*) (vertexDst + vertexAttributePosition.offset)); + pod::Vector3f& normalDst = *((pod::Vector3f*) (vertexDst + vertexAttributeNormal.offset)); pod::Vector2f& uvDst = *((pod::Vector2f*) (vertexDst + vertexAttributeUv.offset)); auto& model = instances[id.x]; auto& material = materials[id.y]; auto& texture = textures[material.indexAlbedo]; - positionDst = uf::matrix::multiply( model, pod::Vector4f{ position[0], position[1], position[2], 1.0f } ); + positionDst = uf::matrix::multiply( model, position, 1.0f ); + normalDst = uf::vector::normalize( uf::matrix::multiply( model, normal, 0.0f ) ); } }); - ext::opengl::Shader::bind( "./data/shaders/gltf/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { + ext::opengl::Shader::bind( uf::io::root + "shaders/gltf/skinned.vert.spv", [](const ext::opengl::Shader& shader, const ext::opengl::Graphic& graphic, void* userdata) { if ( !userdata ) return; ext::gltf::mesh_t::vertex_t* verticesSrc = (ext::gltf::mesh_t::vertex_t*) userdata; @@ -252,11 +255,13 @@ void UF_API ext::opengl::initialize() { size_t vertices = vertexBuffer.range / vertexStride; uf::renderer::VertexDescriptor vertexAttributePosition, + vertexAttributeNormal, vertexAttributeJoints, vertexAttributeWeights; for ( auto& attribute : graphic.descriptor.geometry.attributes.descriptor ) { if ( attribute.name == "position" ) vertexAttributePosition = attribute; + else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; else if ( attribute.name == "joints" ) vertexAttributeJoints = attribute; else if ( attribute.name == "weights" ) vertexAttributeWeights = attribute; } @@ -275,34 +280,49 @@ void UF_API ext::opengl::initialize() { uint8_t* vertexDst = vertexDstPointer + (currentIndex * vertexStride); const pod::Vector3f& position = *((pod::Vector3f*) (vertexSrc + vertexAttributePosition.offset)); + const pod::Vector3f& normal = *((pod::Vector3f*) (vertexSrc + vertexAttributeNormal.offset)); const pod::Vector4ui& joints = *((pod::Vector4ui*) (vertexSrc + vertexAttributeJoints.offset)); const pod::Vector4f& weights = *((pod::Vector4f*) (vertexSrc + vertexAttributeWeights.offset)); pod::Vector3f& positionDst = *((pod::Vector3f*) (vertexDst + vertexAttributePosition.offset)); + pod::Vector3f& normalDst = *((pod::Vector3f*) (vertexDst + vertexAttributeNormal.offset)); pod::Matrix4f model = jointMatrices[joints[0]] * weights[0] + jointMatrices[joints[1]] * weights[1] + jointMatrices[joints[2]] * weights[2] + jointMatrices[joints[3]] * weights[3]; - positionDst = uf::matrix::multiply( model, pod::Vector4f{ position[0], position[1], position[2], 1.0f } ); + + positionDst = uf::matrix::multiply( model, position, 1.0f ); + normalDst = uf::vector::normalize( uf::matrix::multiply( model, normal, 0.0f ) ); } }); } -#endif } void UF_API ext::opengl::tick(){ + uf::Timer timer(false); + if ( !timer.running() ) timer.start(); + ext::opengl::mutex.lock(); if ( ext::opengl::states::resized || ext::opengl::settings::experimental::rebuildOnTickBegin ) { ext::opengl::states::rebuild = true; } - - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; ext::opengl::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized || !graphic.process || graphic.initialized ) return; + if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; graphic.initializePipeline(); ext::opengl::states::rebuild = true; - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + ext::opengl::Graphic& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process || graphic.initialized ) return; + graphic.initializePipeline(); + ext::opengl::states::rebuild = true; + }); } +} for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; if ( !renderMode->device ) { @@ -311,39 +331,30 @@ void UF_API ext::opengl::tick(){ } renderMode->tick(); } - std::vector> jobs; for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; if ( ext::opengl::states::rebuild || renderMode->rebuild ) { if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) { - jobs.emplace_back([&]{ - renderMode->createCommandBuffers(); - return 0; - }); - } else { - renderMode->createCommandBuffers(); - } + if ( settings::experimental::multithreadedCommandRecording ) jobs.emplace_back([&]{ renderMode->createCommandBuffers(); return 0; }); + else renderMode->createCommandBuffers(); } } - if ( !jobs.empty() ) { - uf::thread::batchWorkers( jobs ); - } - + if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); +/* ext::opengl::device.activateContext(); - ext::opengl::device.commandBuffer.end(); ext::opengl::device.commandBuffer.submit(); ext::opengl::device.commandBuffer.flush(); ext::opengl::device.commandBuffer.start(); - +*/ ext::opengl::states::rebuild = false; ext::opengl::states::resized = false; ext::opengl::mutex.unlock(); } void UF_API ext::opengl::render(){ ext::opengl::mutex.lock(); +#if !UF_ENV_DREAMCAST if ( hasRenderMode("Gui", true) ) { RenderMode& primary = getRenderMode("Gui", true); auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); @@ -358,110 +369,19 @@ void UF_API ext::opengl::render(){ auto it = std::find( renderModes.begin(), renderModes.end(), &primary ); if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() ); } - +#endif ext::opengl::device.activateContext(); for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; if ( !renderMode->execute ) continue; ext::opengl::currentRenderMode = renderMode; - for ( uf::Scene* scene : uf::scene::scenes ) scene->render(); + uf::scene::render(); renderMode->render(); } -/* - { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black - glClearDepth(1.0); // Enables Clearing Of The Depth Buffer - glDepthFunc(GL_LESS); // The Type Of Depth Test To Do - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); // Reset The Projection Matrix - - gluPerspective(45.0f, (GLfloat) settings::width / (GLfloat) settings::height, 0.1f, 100.0f); // Calculate The Aspect Ratio Of The Window - glMatrixMode(GL_MODELVIEW); - - glLoadIdentity(); // Reset The View - glTranslatef(-3.0f, 1.5f, -10.0f); // Move Left 1.5 Units And Into The Screen 6.0 - - // draw a triangle - glBegin(GL_TRIANGLES); // start drawing a polygon - glVertex3f( 0.0f, 1.0f, 0.0f); // Top - glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right - glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left - glEnd(); // we're done with the polygon - - glTranslatef(3.0f, 0.0f, 0.0f); // Move Right 3 Units - - // draw a square (quadrilateral) - glBegin(GL_QUADS); // start drawing a polygon (4 sided) - glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left - glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right - glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right - glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left - glEnd(); // done with the polygon - - glTranslatef(3.0f, 0.0f, 0.0f); - - glBegin(GL_POLYGON); // start drawing a polygon (4 sided) - glVertex3f(-0.0f, 1.0f, 0.0f); // Top Left - glVertex3f(-0.75f, 0.75f, 0.0f); - glVertex3f(-1.0f, 0.0f, 0.0f); // Top Right - glVertex3f(-0.75f,-0.75f, 0.0f); // Bottom Right - glVertex3f(-0.0f,-1.0f, 0.0f); // Bottom Left - glVertex3f( 0.75f,-0.75f, 0.0f); // Bottom Right - glVertex3f( 1.0f, 0.0f, 0.0f); // Top Right - glVertex3f( 0.75f, 0.75f, 0.0f); - glEnd(); // done with the polygon - - glTranslatef(-6.0f, -3.0f, 0.0f); - - // draw a triangle - glBegin(GL_POLYGON); // start drawing a polygon - glVertex3f( 0.0f, 1.0f, 0.0f); // Top - glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right - glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left - glEnd(); // we're done with the polygon - - glTranslatef(3.0f, 0.0f, 0.0f); // Move Right 3 Units - - // draw a square (quadrilateral) - glBegin(GL_POLYGON); // start drawing a polygon (4 sided) - glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left - glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right - glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right - glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left - glEnd(); // done with the polygon - - glTranslatef(3.0f, 0.0f, 0.0f); - - glBegin(GL_POLYGON); // start drawing a polygon (4 sided) - glVertex3f(-0.0f, 1.0f, 0.0f); // Top Left - glVertex3f(-0.75f, 0.75f, 0.0f); - glVertex3f(-1.0f, 0.0f, 0.0f); // Top Right - glVertex3f(-0.75f,-0.75f, 0.0f); // Bottom Right - glVertex3f(-0.0f,-1.0f, 0.0f); // Bottom Left - glVertex3f( 0.75f,-0.75f, 0.0f); // Bottom Right - glVertex3f( 1.0f, 0.0f, 0.0f); // Top Right - glVertex3f( 0.75f, 0.75f, 0.0f); - glEnd(); // done with the polygon - #if UF_ENV_DREAMCAST - glKosSwapBuffers(); - #else - device.activateContext().display(); - #endif - } -*/ ext::opengl::currentRenderMode = NULL; - if ( ext::opengl::settings::experimental::waitOnRenderEnd ) { - synchronize(); - } + if ( ext::opengl::settings::experimental::waitOnRenderEnd ) synchronize(); #if UF_USE_OPENVR -/* - if ( ext::openvr::context ) { - ext::openvr::postSubmit(); - } -*/ + // if ( ext::openvr::context ) ext::openvr::postSubmit(); #endif ext::opengl::mutex.unlock(); } @@ -470,17 +390,23 @@ void UF_API ext::opengl::destroy() { synchronize(); Texture2D::empty.destroy(); - - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; uf::Graphic& graphic = entity->getComponent(); graphic.destroy(); - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + uf::Graphic& graphic = entity->getComponent(); + graphic.destroy(); + }); } - +} for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; renderMode->destroy(); diff --git a/engine/src/ext/opengl/rendermode.cpp b/engine/src/ext/opengl/rendermode.cpp index a16eadf6..7e5cacef 100644 --- a/engine/src/ext/opengl/rendermode.cpp +++ b/engine/src/ext/opengl/rendermode.cpp @@ -56,6 +56,15 @@ void ext::opengl::RenderMode::createCommandBuffers() { this->execute = true; std::vector graphics; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; + ext::opengl::Graphic& graphic = entity->getComponent(); + if ( !graphic.initialized || !graphic.process ) continue; + graphics.push_back(&graphic); + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process([&]( uf::Entity* entity ) { @@ -65,6 +74,7 @@ void ext::opengl::RenderMode::createCommandBuffers() { graphics.push_back(&graphic); }); } +} this->synchronize(); // bindPipelines( graphics ); @@ -90,6 +100,15 @@ void ext::opengl::RenderMode::bindPipelines() { this->execute = true; std::vector graphics; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; + ext::opengl::Graphic& graphic = entity->getComponent(); + if ( !graphic.initialized || !graphic.process ) continue; + graphics.push_back(&graphic); + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process([&]( uf::Entity* entity ) { @@ -100,6 +119,7 @@ void ext::opengl::RenderMode::bindPipelines() { graphics.push_back(&graphic); }); } +} this->synchronize(); this->bindPipelines( graphics ); diff --git a/engine/src/ext/opengl/rendermodes/base.cpp b/engine/src/ext/opengl/rendermodes/base.cpp index b000101e..c88229ff 100644 --- a/engine/src/ext/opengl/rendermodes/base.cpp +++ b/engine/src/ext/opengl/rendermodes/base.cpp @@ -65,11 +65,23 @@ void ext::opengl::BaseRenderMode::initialize( Device& device ) { GL_ERROR_CHECK(glDepthFunc(GL_LESS)); } GL_ERROR_CHECK(glEnable(GL_DEPTH_TEST)); - GL_ERROR_CHECK(glShadeModel(GL_SMOOTH)); GL_ERROR_CHECK(glEnable(GL_TEXTURE_2D)); GL_ERROR_CHECK(glEnable(GL_BLEND)); GL_ERROR_CHECK(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + GL_ERROR_CHECK(glEnable(GL_LIGHTING)); +// GL_ERROR_CHECK(glEnable(GL_NORMALIZE)); + GL_ERROR_CHECK(glEnable(GL_COLOR_MATERIAL)); + GL_ERROR_CHECK(glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)); + GL_ERROR_CHECK(glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR)); +#if UF_USE_DREAMCAST + GL_ERROR_CHECK(glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0)); + GL_ERROR_CHECK(glShadeModel(GL_SMOOTH)); +#else + GL_ERROR_CHECK(glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1)); + GL_ERROR_CHECK(glShadeModel(GL_SMOOTH)); +#endif + ext::opengl::RenderMode::initialize( device ); } diff --git a/engine/src/ext/opengl/texture.cpp b/engine/src/ext/opengl/texture.cpp index 2973fc20..af37b8b8 100644 --- a/engine/src/ext/opengl/texture.cpp +++ b/engine/src/ext/opengl/texture.cpp @@ -96,44 +96,61 @@ void ext::opengl::Texture::loadFromImage( Device& device, enums::Format::type_t format ) { - switch ( image.getChannels() ) { - // R - case 1: - switch ( image.getBpp() ) { - case 8: - format = enums::Format::R8_UNORM; - break; - default: - UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); - break; - } - break; - // RGB - case 3: - switch ( image.getBpp() ) { - case 24: - format = enums::Format::R8G8B8_UNORM; - break; - default: - UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); - break; - } - break; - // RGBA - case 4: - switch ( image.getBpp() ) { - case 32: - format = enums::Format::R8G8B8A8_UNORM; - break; - default: - UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); - break; - } - break; - default: - UF_EXCEPTION("unsupported channels of " + std::to_string(image.getChannels())); - break; - } + if ( image.getFormat() > 0 ) { + internalFormat = image.getFormat(); + } else + switch ( image.getChannels() ) { + // R + case 1: + switch ( image.getBpp() ) { + case 8: + format = enums::Format::R8_UNORM; + break; + default: + UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); + break; + } + break; + // RB + case 2: + switch ( image.getBpp() ) { + case 16: + format = enums::Format::R8G8_UNORM; + break; + default: + UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); + break; + } + break; + // RGB + case 3: + switch ( image.getBpp() ) { + case 24: + format = enums::Format::R8G8B8_UNORM; + break; + default: + UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); + break; + } + break; + // RGBA + case 4: + switch ( image.getBpp() ) { + case 16: + format = enums::Format::R4G4B4A4_UNORM_PACK16; + break; + case 32: + format = enums::Format::R8G8B8A8_UNORM; + break; + default: + UF_EXCEPTION("unsupported BPP of " + std::to_string(image.getBpp())); + break; + } + break; + default: + UF_EXCEPTION("unsupported channels of " + std::to_string(image.getChannels())); + break; + } // convert to power of two //image.padToPowerOfTwo(); @@ -225,15 +242,37 @@ void ext::opengl::Texture::update( uf::Image& image, uint32_t layer ) { return this->update( (void*) image.getPixelsPtr(), image.getPixels().size(), layer ); } void ext::opengl::Texture::update( void* data, size_t bufferSize, uint32_t layer ) { +#if UF_ENV_DREAMCAST + if ( internalFormat > 0 ) { + GL_ERROR_CHECK(glBindTexture(viewType, image)); + GL_ERROR_CHECK(glCompressedTexImage2DARB( viewType, 0, internalFormat, width, height, 0, bufferSize, data)); + GL_ERROR_CHECK(glBindTexture(viewType, 0)); + return; + } +#endif GLenum format = GL_RGBA; GLenum type = GL_UNSIGNED_BYTE; switch ( this->format ) { #if !UF_ENV_DREAMCAST - case enums::Format::R8_UNORM: format = GL_RED;; break; - case enums::Format::R8G8_UNORM: format = GL_RG;; break; + case enums::Format::R8_UNORM: + format = GL_RED; + break; #endif - case enums::Format::R8G8B8_UNORM: format = GL_RGB;; break; - case enums::Format::R8G8B8A8_UNORM: format = GL_RGBA;; break; + #if !UF_ENV_DREAMCAST + case enums::Format::R8G8_UNORM: + format = GL_RG; + break; + #endif + case enums::Format::R8G8B8_UNORM: + format = GL_RGB; + break; + case enums::Format::R4G4B4A4_UNORM_PACK16: + format = GL_RGBA; + type = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case enums::Format::R8G8B8A8_UNORM: + format = GL_RGBA; + break; } GL_ERROR_CHECK(glBindTexture(viewType, image)); switch ( viewType ) { diff --git a/engine/src/ext/vulkan/rendermode.cpp b/engine/src/ext/vulkan/rendermode.cpp index 37231236..957392ce 100644 --- a/engine/src/ext/vulkan/rendermode.cpp +++ b/engine/src/ext/vulkan/rendermode.cpp @@ -72,16 +72,25 @@ void ext::vulkan::RenderMode::createCommandBuffers() { this->execute = true; std::vector graphics; - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( !graphic.initialized || !graphic.process ) return; + if ( !graphic.initialized || !graphic.process ) continue; graphics.push_back(&graphic); - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + ext::vulkan::Graphic& graphic = entity->getComponent(); + if ( !graphic.initialized || !graphic.process ) return; + graphics.push_back(&graphic); + }); } +} this->synchronize(); // bindPipelines( graphics ); @@ -115,18 +124,26 @@ void ext::vulkan::RenderMode::bindPipelines() { this->execute = true; std::vector graphics; - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( !graphic.initialized ) return; - if ( !graphic.process ) return; + if ( !graphic.initialized || !graphic.process ) continue; graphics.push_back(&graphic); - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + ext::vulkan::Graphic& graphic = entity->getComponent(); + if ( !graphic.initialized ) return; + if ( !graphic.process ) return; + graphics.push_back(&graphic); + }); } - +} this->synchronize(); this->bindPipelines( graphics ); } diff --git a/engine/src/ext/vulkan/vulkan.cpp b/engine/src/ext/vulkan/vulkan.cpp index 5f7d17a4..c056945b 100644 --- a/engine/src/ext/vulkan/vulkan.cpp +++ b/engine/src/ext/vulkan/vulkan.cpp @@ -206,135 +206,101 @@ void ext::vulkan::removeRenderMode( ext::vulkan::RenderMode* mode, bool free ) { ext::vulkan::states::rebuild = true; } -void ext::vulkan::initialize( /*uint8_t stage*/ ) { -/* - switch ( stage ) { - case 0: { -*/ - device.initialize(); - swapchain.initialize( device ); - { - std::vector pixels = { - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - }; - Texture2D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; - Texture2D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; - Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); - } - { - std::vector pixels = { - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - }; - Texture3D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; - Texture3D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; - Texture3D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 2, 1, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); - } - { - std::vector pixels = { - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - - 255, 0, 255, 255, 0, 0, 0, 255, - 0, 0, 0, 255, 255, 0, 255, 255, - }; - TextureCube::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; - TextureCube::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; - TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); - } - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - renderMode->initialize(device); - } - std::vector> jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) { - jobs.emplace_back([&]{ - renderMode->createCommandBuffers(); - return 0; - }); - } else { - renderMode->createCommandBuffers(); - } - } - if ( !jobs.empty() ) { - uf::thread::batchWorkers( jobs ); - } -/* - } break; - case 1: { - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; - ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized ) return; - - graphic.initializePipeline(); - ext::vulkan::states::rebuild = true; - }; - for ( uf::Scene* scene : uf::scene::scenes ) { - if ( !scene ) continue; - scene->process(filter); - } - } - case 2: { - std::vector> jobs; - for ( auto& renderMode : renderModes ) { - if ( !renderMode ) continue; - if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); - if ( settings::experimental::multithreadedCommandRecording ) { - jobs.emplace_back([&]{ - renderMode->createCommandBuffers(); - return 0; - }); - } else { - renderMode->createCommandBuffers(); - } - } - if ( !jobs.empty() ) { - uf::thread::batchWorkers( jobs ); - } - } break; - default: { - UF_EXCEPTION("invalid stage id"); - } break; +void ext::vulkan::initialize() { + device.initialize(); + swapchain.initialize( device ); + { + std::vector pixels = { + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + }; + Texture2D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; + Texture2D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; + Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); + } + { + std::vector pixels = { + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + }; + Texture3D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; + Texture3D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; + Texture3D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 2, 1, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); + } + { + std::vector pixels = { + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + + 255, 0, 255, 255, 0, 0, 0, 255, + 0, 0, 0, 255, 255, 0, 255, 255, + }; + TextureCube::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST; + TextureCube::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST; + TextureCube::empty.fromBuffers( (void*) &pixels[0], pixels.size(), ext::vulkan::enums::Format::R8G8B8A8_UNORM, 2, 2, 1, 6, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT ); + } + for ( auto& renderMode : renderModes ) { + if ( !renderMode ) continue; + renderMode->initialize(device); + } + std::vector> jobs; + for ( auto& renderMode : renderModes ) { + if ( !renderMode ) continue; + if ( settings::experimental::individualPipelines ) renderMode->bindPipelines(); + if ( settings::experimental::multithreadedCommandRecording ) { + jobs.emplace_back([&]{ + renderMode->createCommandBuffers(); + return 0; + }); + } else { + renderMode->createCommandBuffers(); + } + } + if ( !jobs.empty() ) { + uf::thread::batchWorkers( jobs ); } -*/ } void ext::vulkan::tick() { ext::vulkan::mutex.lock(); if ( ext::vulkan::states::resized || ext::vulkan::settings::experimental::rebuildOnTickBegin ) { ext::vulkan::states::rebuild = true; } - - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; ext::vulkan::Graphic& graphic = entity->getComponent(); - if ( graphic.initialized || !graphic.process || graphic.initialized ) return; + if ( graphic.initialized || !graphic.process || graphic.initialized ) continue; graphic.initializePipeline(); ext::vulkan::states::rebuild = true; - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + ext::vulkan::Graphic& graphic = entity->getComponent(); + if ( graphic.initialized || !graphic.process || graphic.initialized ) return; + graphic.initializePipeline(); + ext::vulkan::states::rebuild = true; + }); } +} for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; if ( !renderMode->device ) { @@ -388,7 +354,7 @@ void ext::vulkan::render() { if ( !renderMode ) continue; if ( !renderMode->execute ) continue; ext::vulkan::currentRenderMode = renderMode; - for ( uf::Scene* scene : uf::scene::scenes ) scene->render(); + uf::scene::render(); renderMode->render(); } @@ -410,17 +376,23 @@ void ext::vulkan::destroy() { Texture2D::empty.destroy(); Texture3D::empty.destroy(); TextureCube::empty.destroy(); - - std::function filter = [&]( uf::Entity* entity ) { - if ( !entity->hasComponent() ) return; +if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( !entity->hasComponent() ) continue; uf::Graphic& graphic = entity->getComponent(); graphic.destroy(); - }; + } +} else { for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; - scene->process(filter); + scene->process([&]( uf::Entity* entity ) { + if ( !entity->hasComponent() ) return; + uf::Graphic& graphic = entity->getComponent(); + graphic.destroy(); + }); } - +} for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue; renderMode->destroy(); diff --git a/engine/src/spec/controller/dreamcast.cpp b/engine/src/spec/controller/dreamcast.cpp new file mode 100644 index 00000000..643131f4 --- /dev/null +++ b/engine/src/spec/controller/dreamcast.cpp @@ -0,0 +1,114 @@ +#include +#ifdef UF_ENV_DREAMCAST + +#include +#include +#include +#include +namespace { + struct { + maple_device_t* device = NULL; + cont_state_t* state = NULL; + } controller; + + std::string GetKeyName( uint32_t code ) { + switch ( code ) { + case CONT_C: return "C"; + case CONT_B: return "B"; + case CONT_A: return "A"; + case CONT_START: return "START"; + case CONT_DPAD_UP: return "L_DPAD_UP"; + case CONT_DPAD_DOWN: return "L_DPAD_DOWN"; + case CONT_DPAD_LEFT: return "L_DPAD_LEFT"; + case CONT_DPAD_RIGHT: return "L_DPAD_RIGHT"; + case CONT_Z: return "Z"; + case CONT_Y: return "Y"; + case CONT_X: return "X"; + case CONT_D: return "D"; + case CONT_DPAD2_UP: return "R_DPAD_UP"; + case CONT_DPAD2_DOWN: return "R_DPAD_DOWN"; + case CONT_DPAD2_LEFT: return "R_DPAD_LEFT"; + case CONT_DPAD2_RIGHT: return "R_DPAD_RIGHT"; + } + return ""; + } + uint32_t GetKeyCode( const std::string& _name ) { + std::string name = uf::string::uppercase( _name ); + if ( name == "C" ) return CONT_C; + else if ( name == "B" ) return CONT_B; + else if ( name == "A" ) return CONT_A; + else if ( name == "START" ) return CONT_START; + else if ( name == "L_DPAD_UP" ) return CONT_DPAD_UP; + else if ( name == "L_DPAD_DOWN" ) return CONT_DPAD_DOWN; + else if ( name == "L_DPAD_LEFT" ) return CONT_DPAD_LEFT; + else if ( name == "L_DPAD_RIGHT" ) return CONT_DPAD_RIGHT; + else if ( name == "Z" ) return CONT_Z; + else if ( name == "Y" ) return CONT_Y; + else if ( name == "X" ) return CONT_X; + else if ( name == "D" ) return CONT_D; + else if ( name == "R_DPAD_UP" ) return CONT_DPAD2_UP; + else if ( name == "R_DPAD_DOWN" ) return CONT_DPAD2_DOWN; + else if ( name == "R_DPAD_LEFT" ) return CONT_DPAD2_LEFT; + else if ( name == "R_DPAD_RIGHT" ) return CONT_DPAD2_RIGHT; + else if ( name == "DPAD_UP" ) return CONT_DPAD_UP; + else if ( name == "DPAD_DOWN" ) return CONT_DPAD_DOWN; + else if ( name == "DPAD_LEFT" ) return CONT_DPAD_LEFT; + else if ( name == "DPAD_RIGHT" ) return CONT_DPAD_RIGHT; + return 0; + } +} + +void spec::dreamcast::controller::initialize() { + ::controller.device = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); +} +void spec::dreamcast::controller::tick() { + if ( !::controller.device ) ::controller.device = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if ( ::controller.device ) ::controller.state = (cont_state_t*) maple_dev_status(::controller.device); +#if 0 + std::vector str; + pod::Vector2f joystick = { analog("L_JOYSTICK_X"), analog("L_JOYSTICK_Y") }; + if ( joystick ) str.emplace_back("Joystick: " + uf::vector::toString(joystick)); + if ( pressed("C") ) str.emplace_back("C"); + if ( pressed("B") ) str.emplace_back("B"); + if ( pressed("A") ) str.emplace_back("A"); + if ( pressed("START") ) str.emplace_back("START"); + if ( pressed("L_DPAD_UP") ) str.emplace_back("L_DPAD_UP"); + if ( pressed("L_DPAD_DOWN") ) str.emplace_back("L_DPAD_DOWN"); + if ( pressed("L_DPAD_LEFT") ) str.emplace_back("L_DPAD_LEFT"); + if ( pressed("L_DPAD_RIGHT") ) str.emplace_back("L_DPAD_RIGHT"); + if ( pressed("Z") ) str.emplace_back("Z"); + if ( pressed("Y") ) str.emplace_back("Y"); + if ( pressed("X") ) str.emplace_back("X"); + if ( pressed("D") ) str.emplace_back("D"); + if ( pressed("R_DPAD_UP") ) str.emplace_back("R_DPAD_UP"); + if ( pressed("R_DPAD_DOWN") ) str.emplace_back("R_DPAD_DOWN"); + if ( pressed("R_DPAD_LEFT") ) str.emplace_back("R_DPAD_LEFT"); + if ( pressed("R_DPAD_RIGHT") ) str.emplace_back("R_DPAD_RIGHT"); + if ( !str.empty() ) UF_DEBUG_MSG(uf::string::join( str, " | " )); +#endif +} +void spec::dreamcast::controller::terminate() { +} +bool spec::dreamcast::controller::connected( size_t i ) { + return ::controller.state; +} +bool spec::dreamcast::controller::pressed( const std::string& str, size_t i ) { + if ( !::controller.state ) return false; + return ::controller.state->buttons & GetKeyCode( str ); +} +float spec::dreamcast::controller::analog( const std::string& str, size_t i ) { +#define NORMALIZE(X) ((float) (X) / (float) std::numeric_limits::max()) + if ( !::controller.state ) return false; + + if ( str == "L_TRIGGER" ) return NORMALIZE(::controller.state->ltrig); + else if ( str == "R_TRIGGER" ) return NORMALIZE(::controller.state->rtrig); + else if ( str == "JOYSTICK_X" ) return NORMALIZE(::controller.state->joyx); + else if ( str == "JOYSTICK_Y" ) return NORMALIZE(::controller.state->joyy); + else if ( str == "L_JOYSTICK_X" ) return NORMALIZE(::controller.state->joyx); + else if ( str == "L_JOYSTICK_Y" ) return NORMALIZE(::controller.state->joyy); + else if ( str == "R_JOYSTICK_X" ) return NORMALIZE(::controller.state->joy2x); + else if ( str == "R_JOYSTICK_Y" ) return NORMALIZE(::controller.state->joy2y); + return 0.0f; +} + +#endif \ No newline at end of file diff --git a/engine/src/spec/controller/universal.cpp b/engine/src/spec/controller/universal.cpp new file mode 100644 index 00000000..fcfc27ee --- /dev/null +++ b/engine/src/spec/controller/universal.cpp @@ -0,0 +1,8 @@ +#include + +void spec::uni::controller::initialize() {} +void spec::uni::controller::tick() {} +void spec::uni::controller::terminate() {} +bool spec::uni::controller::connected( size_t ) { return false; } +bool spec::uni::controller::pressed( const std::string&, size_t ) { return false; } +float spec::uni::controller::analog( const std::string&, size_t ) { return 0; } \ No newline at end of file diff --git a/engine/src/spec/controller/unknown.cpp b/engine/src/spec/controller/unknown.cpp new file mode 100644 index 00000000..947fe375 --- /dev/null +++ b/engine/src/spec/controller/unknown.cpp @@ -0,0 +1,5 @@ +#include + +#ifdef UF_ENV_UNKNOWN + +#endif \ No newline at end of file diff --git a/engine/src/spec/controller/windows.cpp b/engine/src/spec/controller/windows.cpp new file mode 100644 index 00000000..bb835d69 --- /dev/null +++ b/engine/src/spec/controller/windows.cpp @@ -0,0 +1,79 @@ +#include +#include + +#ifdef UF_ENV_WINDOWS +#if UF_USE_OPENVR + #include +#endif + +void spec::win32::controller::initialize() {} +void spec::win32::controller::tick() {} +void spec::win32::controller::terminate() {} +bool spec::win32::controller::connected( size_t i ) { +#if UF_USE_OPENVR + if ( ext::openvr::controllerActive( i ) ) return true; +#endif + return false; +} +bool spec::win32::controller::pressed( const std::string& _name, size_t i ) { + std::string name = uf::string::uppercase(_name); +#if UF_USE_OPENVR + if ( ext::openvr::context ) { + std::string key = ""; + if ( name == "R_DPAD_UP" ) { i = vr::Controller_Hand::Hand_Right; key = "dpadUp"; } + else if ( name == "R_DPAD_DOWN" ) { i = vr::Controller_Hand::Hand_Right; key = "dpadDown"; } + else if ( name == "R_DPAD_LEFT" ) { i = vr::Controller_Hand::Hand_Right; key = "dpadLeft"; } + else if ( name == "R_DPAD_RIGHT" ) { i = vr::Controller_Hand::Hand_Right; key = "dpadRight"; } + else if ( name == "R_JOYSTICK" ) { i = vr::Controller_Hand::Hand_Right; key = "thumbclick"; } + else if ( name == "R_A" ) { i = vr::Controller_Hand::Hand_Right; key = "a"; } + else if ( name == "R_B" ) { i = vr::Controller_Hand::Hand_Right; key = "b"; } + else if ( name == "DPAD_UP" && i == vr::Controller_Hand::Hand_Right ) key = "dpadUp"; + else if ( name == "DPAD_DOWN" && i == vr::Controller_Hand::Hand_Right ) key = "dpadDown"; + else if ( name == "DPAD_LEFT" && i == vr::Controller_Hand::Hand_Right ) key = "dpadLeft"; + else if ( name == "DPAD_RIGHT" && i == vr::Controller_Hand::Hand_Right ) key = "dpadRight"; + else if ( name == "JOYSTICK" && i == vr::Controller_Hand::Hand_Right ) key = "thumbclick"; + else if ( name == "A" && i == vr::Controller_Hand::Hand_Right ) key = "a"; + else if ( name == "B" && i == vr::Controller_Hand::Hand_Right ) key = "b"; + + else if ( name == "L_DPAD_UP" ) { i = vr::Controller_Hand::Hand_Left; key = "dpadUp"; } + else if ( name == "L_DPAD_DOWN" ) { i = vr::Controller_Hand::Hand_Left; key = "dpadDown"; } + else if ( name == "L_DPAD_LEFT" ) { i = vr::Controller_Hand::Hand_Left; key = "dpadLeft"; } + else if ( name == "L_DPAD_RIGHT" ) { i = vr::Controller_Hand::Hand_Left; key = "dpadRight"; } + else if ( name == "L_JOYSTICK" ) { i = vr::Controller_Hand::Hand_Left; key = "thumbclick"; } + else if ( name == "L_A" ) { i = vr::Controller_Hand::Hand_Left; key = "a"; } + else if ( name == "L_B" ) { i = vr::Controller_Hand::Hand_Left; key = "b"; } + else if ( name == "DPAD_UP" && i == vr::Controller_Hand::Hand_Left ) key = "dpadUp"; + else if ( name == "DPAD_DOWN" && i == vr::Controller_Hand::Hand_Left ) key = "dpadDown"; + else if ( name == "DPAD_LEFT" && i == vr::Controller_Hand::Hand_Left ) key = "dpadLeft"; + else if ( name == "DPAD_RIGHT" && i == vr::Controller_Hand::Hand_Left ) key = "dpadRight"; + else if ( name == "JOYSTICK" && i == vr::Controller_Hand::Hand_Left ) key = "thumbclick"; + else if ( name == "A" && i == vr::Controller_Hand::Hand_Left ) key = "a"; + else if ( name == "B" && i == vr::Controller_Hand::Hand_Left ) key = "b"; + + if ( name != "" ) return ext::openvr::controllerState( i, key )["state"].as(); + } +#endif + return false; +} +float spec::win32::controller::analog( const std::string&, size_t i ) { +#if UF_USE_OPENVR + if ( ext::openvr::context ) { + size_t offset = 0; + std::string key = ""; + if ( name == "R_JOYSTICK_X" ) { i = vr::Controller_Hand::Hand_Right; key = "thumbstick"; offset = 0; } + else if ( name == "JOYSTICK_X" && i == vr::Controller_Hand::Hand_Right ) { key = "thumbstick"; offset = 0;} + else if ( name == "R_JOYSTICK_Y" ) { i = vr::Controller_Hand::Hand_Right; key = "thumbstick"; offset = 1; } + else if ( name == "JOYSTICK_Y" && i == vr::Controller_Hand::Hand_Right ) { key = "thumbstick"; offset = 1; } + + else if ( name == "L_JOYSTICK_X" ) { i = vr::Controller_Hand::Hand_Left; key = "thumbstick"; offset = 0; } + else if ( name == "JOYSTICK_X" && i == vr::Controller_Hand::Hand_Left ) { key = "thumbstick"; offset = 0;} + else if ( name == "L_JOYSTICK_Y" ) { i = vr::Controller_Hand::Hand_Left; key = "thumbstick"; offset = 1; } + else if ( name == "JOYSTICK_Y" && i == vr::Controller_Hand::Hand_Left ) { key = "thumbstick"; offset = 1; } + + if ( name != "" ) return ext::openvr::controllerState( i, key )["analog"]["position"][offset].as(); + } +#endif + return 0; +} + +#endif \ No newline at end of file diff --git a/engine/src/spec/window/dreamcast.cpp b/engine/src/spec/window/dreamcast.cpp index 33424848..8a70bf63 100644 --- a/engine/src/spec/window/dreamcast.cpp +++ b/engine/src/spec/window/dreamcast.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #if UF_ENV_DREAMCAST @@ -14,6 +15,8 @@ INIT_MALLOCSTATS -- Enable a call to malloc_stats() right before shutdown */ +#include + extern uint8 romdisk[]; KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS); KOS_INIT_ROMDISK(romdisk); @@ -21,8 +24,237 @@ KOS_INIT_ROMDISK(romdisk); namespace { struct { maple_device_t* device = NULL; - cont_state_t* state = NULL; - } controller, keyboard; + kbd_state_t* state = NULL; + } keyboard; + struct { + maple_device_t* device = NULL; + mouse_state_t* state = NULL; + } mouse; + + bool GetModifier( uint8_t modifier ) { + if ( !::keyboard.state ) return false; + return ::keyboard.state->cond.modifiers & modifier; + } + std::vector GetKeys() { + std::vector keys; + keys.reserve(6); + for ( size_t i = 0; i < MAX_PRESSED_KEYS && ::keyboard.state; ++i ) keys.emplace_back(::keyboard.state->cond.keys[i]); + return keys; + } + uint8_t GetKeyState( uint8_t key ) { + if ( !::keyboard.state || key < MAX_KBD_KEYS ) return 0; + return ::keyboard.state->matrix[key]; + } + std::string GetKeyName( uint8_t key ) { + switch ( key ) { + case KBD_KEY_A: return "A"; + case KBD_KEY_B: return "B"; + case KBD_KEY_C: return "C"; + case KBD_KEY_D: return "D"; + case KBD_KEY_E: return "E"; + case KBD_KEY_F: return "F"; + case KBD_KEY_G: return "G"; + case KBD_KEY_H: return "H"; + case KBD_KEY_I: return "I"; + case KBD_KEY_J: return "J"; + case KBD_KEY_K: return "K"; + case KBD_KEY_L: return "L"; + case KBD_KEY_M: return "M"; + case KBD_KEY_N: return "N"; + case KBD_KEY_O: return "O"; + case KBD_KEY_P: return "P"; + case KBD_KEY_Q: return "Q"; + case KBD_KEY_R: return "R"; + case KBD_KEY_S: return "S"; + case KBD_KEY_T: return "T"; + case KBD_KEY_U: return "U"; + case KBD_KEY_V: return "V"; + case KBD_KEY_W: return "W"; + case KBD_KEY_X: return "X"; + case KBD_KEY_Y: return "Y"; + case KBD_KEY_Z: return "Z"; + case KBD_KEY_1: return "1"; + case KBD_KEY_2: return "2"; + case KBD_KEY_3: return "3"; + case KBD_KEY_4: return "4"; + case KBD_KEY_5: return "5"; + case KBD_KEY_6: return "6"; + case KBD_KEY_7: return "7"; + case KBD_KEY_8: return "8"; + case KBD_KEY_9: return "9"; + case KBD_KEY_0: return "0"; + case KBD_KEY_NONE: return "NONE"; + case KBD_KEY_ERROR: return "ERROR"; + case KBD_KEY_ERR2: return "ERR2"; + case KBD_KEY_ERR3: return "ERR3"; + case KBD_KEY_ENTER: return "ENTER"; + case KBD_KEY_ESCAPE: return "ESCAPE"; + case KBD_KEY_BACKSPACE: return "BACKSPACE"; + case KBD_KEY_TAB: return "TAB"; + case KBD_KEY_SPACE: return "SPACE"; + case KBD_KEY_MINUS: return "MINUS"; + case KBD_KEY_PLUS: return "PLUS"; + case KBD_KEY_LBRACKET: return "LBRACKET"; + case KBD_KEY_RBRACKET: return "RBRACKET"; + case KBD_KEY_BACKSLASH: return "BACKSLASH"; + case KBD_KEY_SEMICOLON: return "SEMICOLON"; + case KBD_KEY_QUOTE: return "QUOTE"; + case KBD_KEY_TILDE: return "TILDE"; + case KBD_KEY_COMMA: return "COMMA"; + case KBD_KEY_PERIOD: return "PERIOD"; + case KBD_KEY_SLASH: return "SLASH"; + case KBD_KEY_CAPSLOCK: return "CAPSLOCK"; + case KBD_KEY_F1: return "F1"; + case KBD_KEY_F2: return "F2"; + case KBD_KEY_F3: return "F3"; + case KBD_KEY_F4: return "F4"; + case KBD_KEY_F5: return "F5"; + case KBD_KEY_F6: return "F6"; + case KBD_KEY_F7: return "F7"; + case KBD_KEY_F8: return "F8"; + case KBD_KEY_F9: return "F9"; + case KBD_KEY_F10: return "F10"; + case KBD_KEY_F11: return "F11"; + case KBD_KEY_F12: return "F12"; + case KBD_KEY_PRINT: return "PRINT"; + case KBD_KEY_SCRLOCK: return "SCRLOCK"; + case KBD_KEY_PAUSE: return "PAUSE"; + case KBD_KEY_INSERT: return "INSERT"; + case KBD_KEY_HOME: return "HOME"; + case KBD_KEY_PGUP: return "PGUP"; + case KBD_KEY_DEL: return "DEL"; + case KBD_KEY_END: return "END"; + case KBD_KEY_PGDOWN: return "PGDOWN"; + case KBD_KEY_RIGHT: return "RIGHT"; + case KBD_KEY_LEFT: return "LEFT"; + case KBD_KEY_DOWN: return "DOWN"; + case KBD_KEY_UP: return "UP"; + case KBD_KEY_PAD_NUMLOCK: return "PAD_NUMLOCK"; + case KBD_KEY_PAD_DIVIDE: return "PAD_DIVIDE"; + case KBD_KEY_PAD_MULTIPLY: return "PAD_MULTIPLY"; + case KBD_KEY_PAD_MINUS: return "PAD_MINUS"; + case KBD_KEY_PAD_PLUS: return "PAD_PLUS"; + case KBD_KEY_PAD_ENTER: return "PAD_ENTER"; + case KBD_KEY_PAD_1: return "PAD_1"; + case KBD_KEY_PAD_2: return "PAD_2"; + case KBD_KEY_PAD_3: return "PAD_3"; + case KBD_KEY_PAD_4: return "PAD_4"; + case KBD_KEY_PAD_5: return "PAD_5"; + case KBD_KEY_PAD_6: return "PAD_6"; + case KBD_KEY_PAD_7: return "PAD_7"; + case KBD_KEY_PAD_8: return "PAD_8"; + case KBD_KEY_PAD_9: return "PAD_9"; + case KBD_KEY_PAD_0: return "PAD_0"; + case KBD_KEY_PAD_PERIOD: return "PAD_PERIOD"; + case KBD_KEY_S3: return "S3"; + } + return ""; + } + uint8_t GetKeyCode( const std::string& _key ) { + std::string key = uf::string::uppercase(_key); + + if ( key == "A" ) return KBD_KEY_A; + else if ( key == "B" ) return KBD_KEY_B; + else if ( key == "C" ) return KBD_KEY_C; + else if ( key == "D" ) return KBD_KEY_D; + else if ( key == "E" ) return KBD_KEY_E; + else if ( key == "F" ) return KBD_KEY_F; + else if ( key == "G" ) return KBD_KEY_G; + else if ( key == "H" ) return KBD_KEY_H; + else if ( key == "I" ) return KBD_KEY_I; + else if ( key == "J" ) return KBD_KEY_J; + else if ( key == "K" ) return KBD_KEY_K; + else if ( key == "L" ) return KBD_KEY_L; + else if ( key == "M" ) return KBD_KEY_M; + else if ( key == "N" ) return KBD_KEY_N; + else if ( key == "O" ) return KBD_KEY_O; + else if ( key == "P" ) return KBD_KEY_P; + else if ( key == "Q" ) return KBD_KEY_Q; + else if ( key == "R" ) return KBD_KEY_R; + else if ( key == "S" ) return KBD_KEY_S; + else if ( key == "T" ) return KBD_KEY_T; + else if ( key == "U" ) return KBD_KEY_U; + else if ( key == "V" ) return KBD_KEY_V; + else if ( key == "W" ) return KBD_KEY_W; + else if ( key == "X" ) return KBD_KEY_X; + else if ( key == "Y" ) return KBD_KEY_Y; + else if ( key == "Z" ) return KBD_KEY_Z; + else if ( key == "1" ) return KBD_KEY_1; + else if ( key == "2" ) return KBD_KEY_2; + else if ( key == "3" ) return KBD_KEY_3; + else if ( key == "4" ) return KBD_KEY_4; + else if ( key == "5" ) return KBD_KEY_5; + else if ( key == "6" ) return KBD_KEY_6; + else if ( key == "7" ) return KBD_KEY_7; + else if ( key == "8" ) return KBD_KEY_8; + else if ( key == "9" ) return KBD_KEY_9; + else if ( key == "0" ) return KBD_KEY_0; + else if ( key == "NONE" ) return KBD_KEY_NONE; + else if ( key == "ERROR" ) return KBD_KEY_ERROR; + else if ( key == "ERR2" ) return KBD_KEY_ERR2; + else if ( key == "ERR3" ) return KBD_KEY_ERR3; + else if ( key == "ENTER" ) return KBD_KEY_ENTER; + else if ( key == "ESCAPE" ) return KBD_KEY_ESCAPE; + else if ( key == "BACKSPACE" ) return KBD_KEY_BACKSPACE; + else if ( key == "TAB" ) return KBD_KEY_TAB; + else if ( key == "SPACE" ) return KBD_KEY_SPACE; + else if ( key == "MINUS" ) return KBD_KEY_MINUS; + else if ( key == "PLUS" ) return KBD_KEY_PLUS; + else if ( key == "LBRACKET" ) return KBD_KEY_LBRACKET; + else if ( key == "RBRACKET" ) return KBD_KEY_RBRACKET; + else if ( key == "BACKSLASH" ) return KBD_KEY_BACKSLASH; + else if ( key == "SEMICOLON" ) return KBD_KEY_SEMICOLON; + else if ( key == "QUOTE" ) return KBD_KEY_QUOTE; + else if ( key == "TILDE" ) return KBD_KEY_TILDE; + else if ( key == "COMMA" ) return KBD_KEY_COMMA; + else if ( key == "PERIOD" ) return KBD_KEY_PERIOD; + else if ( key == "SLASH" ) return KBD_KEY_SLASH; + else if ( key == "CAPSLOCK" ) return KBD_KEY_CAPSLOCK; + else if ( key == "F1" ) return KBD_KEY_F1; + else if ( key == "F2" ) return KBD_KEY_F2; + else if ( key == "F3" ) return KBD_KEY_F3; + else if ( key == "F4" ) return KBD_KEY_F4; + else if ( key == "F5" ) return KBD_KEY_F5; + else if ( key == "F6" ) return KBD_KEY_F6; + else if ( key == "F7" ) return KBD_KEY_F7; + else if ( key == "F8" ) return KBD_KEY_F8; + else if ( key == "F9" ) return KBD_KEY_F9; + else if ( key == "F10" ) return KBD_KEY_F10; + else if ( key == "F11" ) return KBD_KEY_F11; + else if ( key == "F12" ) return KBD_KEY_F12; + else if ( key == "PRINT" ) return KBD_KEY_PRINT; + else if ( key == "SCRLOCK" ) return KBD_KEY_SCRLOCK; + else if ( key == "PAUSE" ) return KBD_KEY_PAUSE; + else if ( key == "INSERT" ) return KBD_KEY_INSERT; + else if ( key == "HOME" ) return KBD_KEY_HOME; + else if ( key == "PGUP" ) return KBD_KEY_PGUP; + else if ( key == "DEL" ) return KBD_KEY_DEL; + else if ( key == "END" ) return KBD_KEY_END; + else if ( key == "PGDOWN" ) return KBD_KEY_PGDOWN; + else if ( key == "RIGHT" ) return KBD_KEY_RIGHT; + else if ( key == "LEFT" ) return KBD_KEY_LEFT; + else if ( key == "DOWN" ) return KBD_KEY_DOWN; + else if ( key == "UP" ) return KBD_KEY_UP; + else if ( key == "PAD_NUMLOCK" ) return KBD_KEY_PAD_NUMLOCK; + else if ( key == "PAD_DIVIDE" ) return KBD_KEY_PAD_DIVIDE; + else if ( key == "PAD_MULTIPLY" ) return KBD_KEY_PAD_MULTIPLY; + else if ( key == "PAD_MINUS" ) return KBD_KEY_PAD_MINUS; + else if ( key == "PAD_PLUS" ) return KBD_KEY_PAD_PLUS; + else if ( key == "PAD_ENTER" ) return KBD_KEY_PAD_ENTER; + else if ( key == "PAD_1" ) return KBD_KEY_PAD_1; + else if ( key == "PAD_2" ) return KBD_KEY_PAD_2; + else if ( key == "PAD_3" ) return KBD_KEY_PAD_3; + else if ( key == "PAD_4" ) return KBD_KEY_PAD_4; + else if ( key == "PAD_5" ) return KBD_KEY_PAD_5; + else if ( key == "PAD_6" ) return KBD_KEY_PAD_6; + else if ( key == "PAD_7" ) return KBD_KEY_PAD_7; + else if ( key == "PAD_8" ) return KBD_KEY_PAD_8; + else if ( key == "PAD_9" ) return KBD_KEY_PAD_9; + else if ( key == "PAD_0" ) return KBD_KEY_PAD_0; + else if ( key == "PAD_PERIOD" ) return KBD_KEY_PAD_PERIOD; + else if ( key == "S3" ) return KBD_KEY_S3; + return 0; + } } UF_API_CALL spec::dreamcast::Window::Window() : @@ -69,9 +301,7 @@ UF_API_CALL spec::dreamcast::Window::Window( const spec::dreamcast::Window::vect this->create(size, title); } void UF_API_CALL spec::dreamcast::Window::create( const spec::dreamcast::Window::vector_t& _size, const spec::dreamcast::Window::title_t& title ) { - //dbglog_set_level(DBG_WARNING); - ::controller.device = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); - ::keyboard.device = maple_enum_type(0, MAPLE_FUNC_KEYBOARD); + ::keyboard.device = maple_enum_type(1, MAPLE_FUNC_KEYBOARD); } spec::dreamcast::Window::~Window() { @@ -124,16 +354,73 @@ bool UF_API_CALL spec::dreamcast::Window::hasFocus() const { #include -void UF_API_CALL spec::dreamcast::Window::processEvents() { - if ( !::controller.device ) ::controller.device = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); +void UF_API_CALL spec::dreamcast::Window::processEvents() { if ( !::keyboard.device ) ::keyboard.device = maple_enum_type(0, MAPLE_FUNC_KEYBOARD); + if ( ::keyboard.device ) ::keyboard.state = (kbd_state_t*) maple_dev_status(::keyboard.device); + + if ( !::mouse.device ) ::mouse.device = maple_enum_type(0, MAPLE_FUNC_MOUSE); + if ( ::mouse.device ) ::mouse.state = (mouse_state_t*) maple_dev_status(::mouse.device); - if ( ::controller.device ) ::controller.state = (cont_state_t*) maple_dev_status(::controller.device); - if ( ::keyboard.device ) ::keyboard.state = (cont_state_t*) maple_dev_status(::keyboard.device); + /* Key inputs */ if ( this->m_asyncParse ) { + std::vector keys = GetKeys(); - if ( ::controller.state ) { - if ( ::controller.state->buttons & CONT_START ) { + struct Event { + std::string type = "unknown"; + std::string invoker = "???"; + struct { + int state; + std::string code; + uint32_t raw; + bool async; + + struct { + bool alt; + bool ctrl; + bool shift; + bool sys; + } modifier; + } key; + }; + Event event; { + event.type = "window:Key"; + event.invoker = "window"; + event.key.state = -1; + event.key.code = "NULL"; + event.key.raw = 0; + event.key.async = true; + event.key.modifier = { + .alt = GetModifier(KBD_MOD_LALT) || GetModifier(KBD_MOD_RALT), + .ctrl = GetModifier(KBD_MOD_LCTRL) || GetModifier(KBD_MOD_RCTRL), + .shift = GetModifier(KBD_MOD_LSHIFT) || GetModifier(KBD_MOD_RSHIFT), + .sys = GetModifier(KBD_MOD_S1) || GetModifier(KBD_MOD_S2), + }; + } + /* Readable (JSON) + Optimal (Userdata) event */ { + uf::Serializer json; + /* Set up JSON data*/ { + json["type"] = event.type + "." + ((event.key.state == -1)?"Pressed":"Released"); + json["invoker"] = event.invoker; + json["key"]["state"] = (event.key.state == -1) ? "Down" : "Up"; + json["key"]["async"] = event.key.async; + json["key"]["modifier"]["alt"] = event.key.modifier.alt; + json["key"]["modifier"]["control"] = event.key.modifier.ctrl; + json["key"]["modifier"]["shift"] = event.key.modifier.shift; + json["key"]["modifier"]["system"] = event.key.modifier.sys; + } + /* Loop through key inputs */ { + for ( auto& key : keys ) { + auto code = GetKeyName(key); + event.key.code = code; + event.key.raw = key; + event.key.state = GetKeyState(key); + + json["key"]["code"] = code; + json["key"]["raw"] = key; + this->pushEvent(event.type, json); + this->pushEvent(event.type + "." + code, json); + } + } } } } @@ -199,31 +486,9 @@ void UF_API_CALL spec::dreamcast::Window::switchToFullscreen( bool borderless ) } bool UF_API_CALL spec::dreamcast::Window::isKeyPressed(const std::string& key) { - if ( !::controller.state ) return false; - - if ( (key == "Up") && (::controller.state->buttons & CONT_DPAD_UP) ) return true; - if ( (key == "Down") && (::controller.state->buttons & CONT_DPAD_DOWN) ) return true; - if ( (key == "Left") && (::controller.state->buttons & CONT_DPAD_LEFT) ) return true; - if ( (key == "Right") && (::controller.state->buttons & CONT_DPAD_RIGHT) ) return true; - - if ( (key == "Up2") && (::controller.state->buttons & CONT_DPAD2_UP) ) return true; - if ( (key == "Down2") && (::controller.state->buttons & CONT_DPAD2_DOWN) ) return true; - if ( (key == "Left2") && (::controller.state->buttons & CONT_DPAD2_LEFT) ) return true; - if ( (key == "Right2") && (::controller.state->buttons & CONT_DPAD2_RIGHT) ) return true; - - if ( (key == "Start") && (::controller.state->buttons & CONT_START) ) return true; - - if ( (key == "A") && (::controller.state->buttons & CONT_A) ) return true; - if ( (key == "B") && (::controller.state->buttons & CONT_B) ) return true; - if ( (key == "C") && (::controller.state->buttons & CONT_C) ) return true; - if ( (key == "D") && (::controller.state->buttons & CONT_D) ) return true; - if ( (key == "X") && (::controller.state->buttons & CONT_X) ) return true; - if ( (key == "Y") && (::controller.state->buttons & CONT_Y) ) return true; - if ( (key == "Z") && (::controller.state->buttons & CONT_Z) ) return true; - + auto code = GetKeyCode(key); + auto keys = GetKeys(); + for ( auto key : keys ) if ( key == code ) return true; return false; } -std::string UF_API_CALL spec::dreamcast::Window::getKey(/*WPARAM key, LPARAM flags*/) { - return ""; -} #endif \ No newline at end of file diff --git a/engine/src/spec/window/windows.cpp b/engine/src/spec/window/windows.cpp index 4e8e5fb0..017cb855 100644 --- a/engine/src/spec/window/windows.cpp +++ b/engine/src/spec/window/windows.cpp @@ -1,10 +1,11 @@ #include #include #include +#include #define USE_OPTIMAL 0 -#if defined(UF_ENV_WINDOWS) && (!defined(UF_USE_SFML) || (defined(UF_USE_SFML) && UF_USE_SFML == 0)) +#if UF_ENV_WINDOWS && (!UF_USE_SFML || (UF_USE_SFML && UF_USE_SFML == 0)) namespace { int windowCount = 0; std::wstring className = L"uf::Window::Class"; @@ -55,6 +56,467 @@ namespace { if ((message == WM_SYSCOMMAND) && (wParam == SC_KEYMENU)) return 0; return DefWindowProcW(handle, message, wParam, lParam); } + + std::vector GetKeys() { + std::vector keys; + keys.reserve(8); + + if ( GetAsyncKeyState('A') & 0x8000 ) keys.push_back('A'); + if ( GetAsyncKeyState('B') & 0x8000 ) keys.push_back('B'); + if ( GetAsyncKeyState('C') & 0x8000 ) keys.push_back('C'); + if ( GetAsyncKeyState('D') & 0x8000 ) keys.push_back('D'); + if ( GetAsyncKeyState('E') & 0x8000 ) keys.push_back('E'); + if ( GetAsyncKeyState('F') & 0x8000 ) keys.push_back('F'); + if ( GetAsyncKeyState('G') & 0x8000 ) keys.push_back('G'); + if ( GetAsyncKeyState('H') & 0x8000 ) keys.push_back('H'); + if ( GetAsyncKeyState('I') & 0x8000 ) keys.push_back('I'); + if ( GetAsyncKeyState('J') & 0x8000 ) keys.push_back('J'); + if ( GetAsyncKeyState('K') & 0x8000 ) keys.push_back('K'); + if ( GetAsyncKeyState('L') & 0x8000 ) keys.push_back('L'); + if ( GetAsyncKeyState('M') & 0x8000 ) keys.push_back('M'); + if ( GetAsyncKeyState('N') & 0x8000 ) keys.push_back('N'); + if ( GetAsyncKeyState('O') & 0x8000 ) keys.push_back('O'); + if ( GetAsyncKeyState('P') & 0x8000 ) keys.push_back('P'); + if ( GetAsyncKeyState('Q') & 0x8000 ) keys.push_back('Q'); + if ( GetAsyncKeyState('R') & 0x8000 ) keys.push_back('R'); + if ( GetAsyncKeyState('S') & 0x8000 ) keys.push_back('S'); + if ( GetAsyncKeyState('T') & 0x8000 ) keys.push_back('T'); + if ( GetAsyncKeyState('U') & 0x8000 ) keys.push_back('U'); + if ( GetAsyncKeyState('V') & 0x8000 ) keys.push_back('V'); + if ( GetAsyncKeyState('W') & 0x8000 ) keys.push_back('W'); + if ( GetAsyncKeyState('X') & 0x8000 ) keys.push_back('X'); + if ( GetAsyncKeyState('Y') & 0x8000 ) keys.push_back('Y'); + if ( GetAsyncKeyState('Z') & 0x8000 ) keys.push_back('Z'); + if ( GetAsyncKeyState('0') & 0x8000 ) keys.push_back('0'); + if ( GetAsyncKeyState('1') & 0x8000 ) keys.push_back('1'); + if ( GetAsyncKeyState('2') & 0x8000 ) keys.push_back('2'); + if ( GetAsyncKeyState('3') & 0x8000 ) keys.push_back('3'); + if ( GetAsyncKeyState('4') & 0x8000 ) keys.push_back('4'); + if ( GetAsyncKeyState('5') & 0x8000 ) keys.push_back('5'); + if ( GetAsyncKeyState('6') & 0x8000 ) keys.push_back('6'); + if ( GetAsyncKeyState('7') & 0x8000 ) keys.push_back('7'); + if ( GetAsyncKeyState('8') & 0x8000 ) keys.push_back('8'); + if ( GetAsyncKeyState('9') & 0x8000 ) keys.push_back('9'); + if ( GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) keys.push_back(VK_ESCAPE); + if ( GetAsyncKeyState(VK_LCONTROL) & 0x8000 ) keys.push_back(VK_LCONTROL); + if ( GetAsyncKeyState(VK_LSHIFT) & 0x8000 ) keys.push_back(VK_LSHIFT); + if ( GetAsyncKeyState(VK_LMENU) & 0x8000 ) keys.push_back(VK_LMENU); + if ( GetAsyncKeyState(VK_LWIN) & 0x8000 ) keys.push_back(VK_LWIN); + if ( GetAsyncKeyState(VK_RCONTROL) & 0x8000 ) keys.push_back(VK_RCONTROL); + if ( GetAsyncKeyState(VK_RSHIFT) & 0x8000 ) keys.push_back(VK_RSHIFT); + if ( GetAsyncKeyState(VK_RMENU) & 0x8000 ) keys.push_back(VK_RMENU); + if ( GetAsyncKeyState(VK_RWIN) & 0x8000 ) keys.push_back(VK_RWIN); + if ( GetAsyncKeyState(VK_APPS) & 0x8000 ) keys.push_back(VK_APPS); + if ( GetAsyncKeyState(VK_OEM_4) & 0x8000 ) keys.push_back(VK_OEM_4); + if ( GetAsyncKeyState(VK_OEM_6) & 0x8000 ) keys.push_back(VK_OEM_6); + if ( GetAsyncKeyState(VK_OEM_1) & 0x8000 ) keys.push_back(VK_OEM_1); + if ( GetAsyncKeyState(VK_OEM_COMMA) & 0x8000 ) keys.push_back(VK_OEM_COMMA); + if ( GetAsyncKeyState(VK_OEM_PERIOD) & 0x8000 ) keys.push_back(VK_OEM_PERIOD); + if ( GetAsyncKeyState(VK_OEM_7) & 0x8000 ) keys.push_back(VK_OEM_7); + if ( GetAsyncKeyState(VK_OEM_2) & 0x8000 ) keys.push_back(VK_OEM_2); + if ( GetAsyncKeyState(VK_OEM_5) & 0x8000 ) keys.push_back(VK_OEM_5); + if ( GetAsyncKeyState(VK_OEM_3) & 0x8000 ) keys.push_back(VK_OEM_3); + if ( GetAsyncKeyState(VK_OEM_PLUS) & 0x8000 ) keys.push_back(VK_OEM_PLUS); + if ( GetAsyncKeyState(VK_OEM_MINUS) & 0x8000 ) keys.push_back(VK_OEM_MINUS); + if ( GetAsyncKeyState(VK_SPACE) & 0x8000 ) keys.push_back(VK_SPACE); + if ( GetAsyncKeyState(VK_RETURN) & 0x8000 ) keys.push_back(VK_RETURN); + if ( GetAsyncKeyState(VK_BACK) & 0x8000 ) keys.push_back(VK_BACK); + if ( GetAsyncKeyState(VK_TAB) & 0x8000 ) keys.push_back(VK_TAB); + if ( GetAsyncKeyState(VK_PRIOR) & 0x8000 ) keys.push_back(VK_PRIOR); + if ( GetAsyncKeyState(VK_NEXT) & 0x8000 ) keys.push_back(VK_NEXT); + if ( GetAsyncKeyState(VK_END) & 0x8000 ) keys.push_back(VK_END); + if ( GetAsyncKeyState(VK_HOME) & 0x8000 ) keys.push_back(VK_HOME); + if ( GetAsyncKeyState(VK_INSERT) & 0x8000 ) keys.push_back(VK_INSERT); + if ( GetAsyncKeyState(VK_DELETE) & 0x8000 ) keys.push_back(VK_DELETE); + if ( GetAsyncKeyState(VK_ADD) & 0x8000 ) keys.push_back(VK_ADD); + if ( GetAsyncKeyState(VK_SUBTRACT) & 0x8000 ) keys.push_back(VK_SUBTRACT); + if ( GetAsyncKeyState(VK_MULTIPLY) & 0x8000 ) keys.push_back(VK_MULTIPLY); + if ( GetAsyncKeyState(VK_DIVIDE) & 0x8000 ) keys.push_back(VK_DIVIDE); + if ( GetAsyncKeyState(VK_LEFT) & 0x8000 ) keys.push_back(VK_LEFT); + if ( GetAsyncKeyState(VK_RIGHT) & 0x8000 ) keys.push_back(VK_RIGHT); + if ( GetAsyncKeyState(VK_UP) & 0x8000 ) keys.push_back(VK_UP); + if ( GetAsyncKeyState(VK_DOWN) & 0x8000 ) keys.push_back(VK_DOWN); + if ( GetAsyncKeyState(VK_NUMPAD0) & 0x8000 ) keys.push_back(VK_NUMPAD0); + if ( GetAsyncKeyState(VK_NUMPAD1) & 0x8000 ) keys.push_back(VK_NUMPAD1); + if ( GetAsyncKeyState(VK_NUMPAD2) & 0x8000 ) keys.push_back(VK_NUMPAD2); + if ( GetAsyncKeyState(VK_NUMPAD3) & 0x8000 ) keys.push_back(VK_NUMPAD3); + if ( GetAsyncKeyState(VK_NUMPAD4) & 0x8000 ) keys.push_back(VK_NUMPAD4); + if ( GetAsyncKeyState(VK_NUMPAD5) & 0x8000 ) keys.push_back(VK_NUMPAD5); + if ( GetAsyncKeyState(VK_NUMPAD6) & 0x8000 ) keys.push_back(VK_NUMPAD6); + if ( GetAsyncKeyState(VK_NUMPAD7) & 0x8000 ) keys.push_back(VK_NUMPAD7); + if ( GetAsyncKeyState(VK_NUMPAD8) & 0x8000 ) keys.push_back(VK_NUMPAD8); + if ( GetAsyncKeyState(VK_NUMPAD9) & 0x8000 ) keys.push_back(VK_NUMPAD9); + if ( GetAsyncKeyState(VK_F1) & 0x8000 ) keys.push_back(VK_F1); + if ( GetAsyncKeyState(VK_F2) & 0x8000 ) keys.push_back(VK_F2); + if ( GetAsyncKeyState(VK_F3) & 0x8000 ) keys.push_back(VK_F3); + if ( GetAsyncKeyState(VK_F4) & 0x8000 ) keys.push_back(VK_F4); + if ( GetAsyncKeyState(VK_F5) & 0x8000 ) keys.push_back(VK_F5); + if ( GetAsyncKeyState(VK_F6) & 0x8000 ) keys.push_back(VK_F6); + if ( GetAsyncKeyState(VK_F7) & 0x8000 ) keys.push_back(VK_F7); + if ( GetAsyncKeyState(VK_F8) & 0x8000 ) keys.push_back(VK_F8); + if ( GetAsyncKeyState(VK_F9) & 0x8000 ) keys.push_back(VK_F9); + if ( GetAsyncKeyState(VK_F10) & 0x8000 ) keys.push_back(VK_F10); + if ( GetAsyncKeyState(VK_F11) & 0x8000 ) keys.push_back(VK_F11); + if ( GetAsyncKeyState(VK_F12) & 0x8000 ) keys.push_back(VK_F12); + if ( GetAsyncKeyState(VK_F13) & 0x8000 ) keys.push_back(VK_F13); + if ( GetAsyncKeyState(VK_F14) & 0x8000 ) keys.push_back(VK_F14); + if ( GetAsyncKeyState(VK_F15) & 0x8000 ) keys.push_back(VK_F15); + if ( GetAsyncKeyState(VK_PAUSE) & 0x8000 ) keys.push_back(VK_PAUSE); + + if ( GetAsyncKeyState(VK_LBUTTON) & 0x8000 ) keys.push_back(VK_LBUTTON); + if ( GetAsyncKeyState(VK_RBUTTON) & 0x8000 ) keys.push_back(VK_RBUTTON); + if ( GetAsyncKeyState(VK_MBUTTON) & 0x8000 ) keys.push_back(VK_MBUTTON); + if ( GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ) keys.push_back(VK_XBUTTON1); + if ( GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ) keys.push_back(VK_XBUTTON2); + return keys; + } + std::string _GetKeyName( WPARAM key, LPARAM flags = 0 ) { + #if 1 + switch ( key ) { + // Check the scancode to distinguish between left and right shift + case VK_SHIFT: { + static UINT lShift = MapVirtualKeyW(VK_LSHIFT, MAPVK_VK_TO_VSC); + UINT scancode = static_cast((flags & (0xFF << 16)) >> 16); + return scancode == lShift ? "LShift" : "RShift"; + } + // Check the "extended" flag to distinguish between left and right alt + case VK_MENU : return (HIWORD(flags) & KF_EXTENDED) ? "RAlt" : "LAlt"; + // Check the "extended" flag to distinguish between left and right control + case VK_CONTROL : return (HIWORD(flags) & KF_EXTENDED) ? "RControl" : "LControl"; + + // Other keys are reported properly + case VK_LWIN: return "LSystem"; + case VK_RWIN: return "RSystem"; + case VK_APPS: return "Menu"; + case VK_OEM_1: return "SemiColon"; + case VK_OEM_2: return "Slash"; + case VK_OEM_PLUS: return "Equal"; + case VK_OEM_MINUS: return "Dash"; + case VK_OEM_4: return "LBracket"; + case VK_OEM_6: return "RBracket"; + case VK_OEM_COMMA: return "Comma"; + case VK_OEM_PERIOD: return "Period"; + case VK_OEM_7: return "Quote"; + case VK_OEM_5: return "BackSlash"; + case VK_OEM_3: return "Tilde"; + + case VK_ESCAPE: return "Escape"; + case VK_SPACE: return "Space"; + case VK_RETURN: return "Enter"; + case VK_BACK: return "BackSpace"; + case VK_TAB: return "Tab"; + case VK_PRIOR: return "PageUp"; + case VK_NEXT: return "PageDown"; + case VK_END: return "End"; + case VK_HOME: return "Home"; + case VK_INSERT: return "Insert"; + case VK_DELETE: return "Delete"; + case VK_ADD: return "Add"; + case VK_SUBTRACT: return "Subtract"; + case VK_MULTIPLY: return "Multiply"; + case VK_DIVIDE: return "Divide"; + case VK_PAUSE: return "Pause"; + + case VK_F1: return "F1"; + case VK_F2: return "F2"; + case VK_F3: return "F3"; + case VK_F4: return "F4"; + case VK_F5: return "F5"; + case VK_F6: return "F6"; + case VK_F7: return "F7"; + case VK_F8: return "F8"; + case VK_F9: return "F9"; + case VK_F10: return "F10"; + case VK_F11: return "F11"; + case VK_F12: return "F12"; + case VK_F13: return "F13"; + case VK_F14: return "F14"; + case VK_F15: return "F15"; + + case VK_LEFT: return "Left"; + case VK_RIGHT: return "Right"; + case VK_UP: return "Up"; + case VK_DOWN: return "Down"; + + case VK_NUMPAD0: return "Numpad0"; + case VK_NUMPAD1: return "Numpad1"; + case VK_NUMPAD2: return "Numpad2"; + case VK_NUMPAD3: return "Numpad3"; + case VK_NUMPAD4: return "Numpad4"; + case VK_NUMPAD5: return "Numpad5"; + case VK_NUMPAD6: return "Numpad6"; + case VK_NUMPAD7: return "Numpad7"; + case VK_NUMPAD8: return "Numpad8"; + case VK_NUMPAD9: return "Numpad9"; + + case 'Q': return "Q"; + case 'W': return "W"; + case 'E': return "E"; + case 'R': return "R"; + case 'T': return "T"; + case 'Y': return "Y"; + case 'U': return "U"; + case 'I': return "I"; + case 'O': return "O"; + case 'P': return "P"; + + case 'A': return "A"; + case 'S': return "S"; + case 'D': return "D"; + case 'F': return "F"; + case 'G': return "G"; + case 'H': return "H"; + case 'J': return "J"; + case 'K': return "K"; + case 'L': return "L"; + + case 'Z': return "Z"; + case 'X': return "X"; + case 'C': return "C"; + case 'V': return "V"; + case 'B': return "B"; + case 'N': return "N"; + case 'M': return "M"; + + case '1': return "Num1"; + case '2': return "Num2"; + case '3': return "Num3"; + case '4': return "Num4"; + case '5': return "Num5"; + case '6': return "Num6"; + case '7': return "Num7"; + case '8': return "Num8"; + case '9': return "Num9"; + case '0': return "Num0"; + } + #else + switch ( key ) { + case 'A': return "A"; + case 'B': return "B"; + case 'C': return "C"; + case 'D': return "D"; + case 'E': return "E"; + case 'F': return "F"; + case 'G': return "G"; + case 'H': return "H"; + case 'I': return "I"; + case 'J': return "J"; + case 'K': return "K"; + case 'L': return "L"; + case 'M': return "M"; + case 'N': return "N"; + case 'O': return "O"; + case 'P': return "P"; + case 'Q': return "Q"; + case 'R': return "R"; + case 'S': return "S"; + case 'T': return "T"; + case 'U': return "U"; + case 'V': return "V"; + case 'W': return "W"; + case 'X': return "X"; + case 'Y': return "Y"; + case 'Z': return "Z"; + case '0': return "0"; + case '1': return "1"; + case '2': return "2"; + case '3': return "3"; + case '4': return "4"; + case '5': return "5"; + case '6': return "6"; + case '7': return "7"; + case '8': return "8"; + case '9': return "9"; + case VK_ESCAPE: return "Escape"; + case VK_LCONTROL: return "LControl"; + case VK_LSHIFT: return "LShift"; + case VK_LMENU: return "LAlt"; + case VK_LWIN: return "LSystem"; + case VK_RCONTROL: return "RControl"; + case VK_RSHIFT: return "RShift"; + case VK_RMENU: return "RAlt"; + case VK_RWIN: return "RSystem"; + case VK_APPS: return "Apps"; + case VK_OEM_4: return "OEM4"; + case VK_OEM_6: return "OEM6"; + case VK_OEM_1: return "OEM1"; + case VK_OEM_COMMA: return "OEMComma"; + case VK_OEM_PERIOD: return "OEMPeriod"; + case VK_OEM_7: return "OEM7"; + case VK_OEM_2: return "OEM2"; + case VK_OEM_5: return "OEM5"; + case VK_OEM_3: return "OEM3"; + case VK_OEM_PLUS: return "OEM+"; + case VK_OEM_MINUS: return "OEM-"; + case VK_SPACE: return " "; + case VK_RETURN: return "Enter"; + case VK_BACK: return "Back"; + case VK_TAB: return "Tab"; + case VK_PRIOR: return "Prior"; + case VK_NEXT: return "Next"; + case VK_END: return "End"; + case VK_HOME: return "Home"; + case VK_INSERT: return "Insert"; + case VK_DELETE: return "Delete"; + case VK_ADD: return "+"; + case VK_SUBTRACT: return "-"; + case VK_MULTIPLY: return "*"; + case VK_DIVIDE: return "/"; + case VK_LEFT: return "Left"; + case VK_RIGHT: return "Right"; + case VK_UP: return "Up"; + case VK_DOWN: return "Down"; + case VK_NUMPAD0: return "Num0"; + case VK_NUMPAD1: return "Num1"; + case VK_NUMPAD2: return "Num2"; + case VK_NUMPAD3: return "Num3"; + case VK_NUMPAD4: return "Num4"; + case VK_NUMPAD5: return "Num5"; + case VK_NUMPAD6: return "Num6"; + case VK_NUMPAD7: return "Num7"; + case VK_NUMPAD8: return "Num8"; + case VK_NUMPAD9: return "Num9"; + case VK_F1: return "F1"; + case VK_F2: return "F2"; + case VK_F3: return "F3"; + case VK_F4: return "F4"; + case VK_F5: return "F5"; + case VK_F6: return "F6"; + case VK_F7: return "F7"; + case VK_F8: return "F8"; + case VK_F9: return "F9"; + case VK_F10: return "F10"; + case VK_F11: return "F11"; + case VK_F12: return "F12"; + case VK_F13: return "F13"; + case VK_F14: return "F14"; + case VK_F15: return "F15"; + case VK_PAUSE: return "Pause"; + + case VK_LBUTTON: return "LeftMouse"; + case VK_RBUTTON: return "RightMouse"; + case VK_MBUTTON: return "MiddleMouse"; + case VK_XBUTTON1: return "XButton1"; + case VK_XBUTTON2: return "XButton2"; + } + #endif + return std::to_string((int) key); + } + std::string GetKeyName( WPARAM key, LPARAM flags = 0 ) { + return uf::string::uppercase( _GetKeyName( key, flags ) ); + } + + WPARAM GetKeyCode( const std::string& _name ) { + std::string name = uf::string::uppercase(_name); + if ( name == "A" ) return 'A'; + else if ( name == "B" ) return 'B'; + else if ( name == "C" ) return 'C'; + else if ( name == "D" ) return 'D'; + else if ( name == "E" ) return 'E'; + else if ( name == "F" ) return 'F'; + else if ( name == "G" ) return 'G'; + else if ( name == "H" ) return 'H'; + else if ( name == "I" ) return 'I'; + else if ( name == "J" ) return 'J'; + else if ( name == "K" ) return 'K'; + else if ( name == "L" ) return 'L'; + else if ( name == "M" ) return 'M'; + else if ( name == "N" ) return 'N'; + else if ( name == "O" ) return 'O'; + else if ( name == "P" ) return 'P'; + else if ( name == "Q" ) return 'Q'; + else if ( name == "R" ) return 'R'; + else if ( name == "S" ) return 'S'; + else if ( name == "T" ) return 'T'; + else if ( name == "U" ) return 'U'; + else if ( name == "V" ) return 'V'; + else if ( name == "W" ) return 'W'; + else if ( name == "X" ) return 'X'; + else if ( name == "Y" ) return 'Y'; + else if ( name == "Z" ) return 'Z'; + else if ( name == "0" ) return '0'; + else if ( name == "1" ) return '1'; + else if ( name == "2" ) return '2'; + else if ( name == "3" ) return '3'; + else if ( name == "4" ) return '4'; + else if ( name == "5" ) return '5'; + else if ( name == "6" ) return '6'; + else if ( name == "7" ) return '7'; + else if ( name == "8" ) return '8'; + else if ( name == "9" ) return '9'; + else if ( name == "ESCAPE" ) return VK_ESCAPE; + else if ( name == "LCONTROL" ) return VK_LCONTROL; + else if ( name == "LSHIFT" ) return VK_LSHIFT; + else if ( name == "LALT" ) return VK_LMENU; + else if ( name == "LSYSTEM" ) return VK_LWIN; + else if ( name == "RCONTROL" ) return VK_RCONTROL; + else if ( name == "RSHIFT" ) return VK_RSHIFT; + else if ( name == "RALT" ) return VK_RMENU; + else if ( name == "RSYSTEM" ) return VK_RWIN; + else if ( name == "APPS" ) return VK_APPS; + else if ( name == "OEM4" ) return VK_OEM_4; + else if ( name == "OEM6" ) return VK_OEM_6; + else if ( name == "OEM1" ) return VK_OEM_1; + else if ( name == "OEMCOMMA" ) return VK_OEM_COMMA; + else if ( name == "OEMPERIOD" ) return VK_OEM_PERIOD; + else if ( name == "OEM7" ) return VK_OEM_7; + else if ( name == "OEM2" ) return VK_OEM_2; + else if ( name == "OEM5" ) return VK_OEM_5; + else if ( name == "OEM3" ) return VK_OEM_3; + else if ( name == "OEM+" ) return VK_OEM_PLUS; + else if ( name == "OEM-" ) return VK_OEM_MINUS; + else if ( name == " " ) return VK_SPACE; + else if ( name == "ENTER" ) return VK_RETURN; + else if ( name == "BACK" ) return VK_BACK; + else if ( name == "TAB" ) return VK_TAB; + else if ( name == "PRIOR" ) return VK_PRIOR; + else if ( name == "NEXT" ) return VK_NEXT; + else if ( name == "END" ) return VK_END; + else if ( name == "HOME" ) return VK_HOME; + else if ( name == "INSERT" ) return VK_INSERT; + else if ( name == "DELETE" ) return VK_DELETE; + else if ( name == "+" ) return VK_ADD; + else if ( name == "-" ) return VK_SUBTRACT; + else if ( name == "*" ) return VK_MULTIPLY; + else if ( name == "/" ) return VK_DIVIDE; + else if ( name == "LEFT" ) return VK_LEFT; + else if ( name == "RIGHT" ) return VK_RIGHT; + else if ( name == "UP" ) return VK_UP; + else if ( name == "DOWN" ) return VK_DOWN; + else if ( name == "NUM0" ) return VK_NUMPAD0; + else if ( name == "NUM1" ) return VK_NUMPAD1; + else if ( name == "NUM2" ) return VK_NUMPAD2; + else if ( name == "NUM3" ) return VK_NUMPAD3; + else if ( name == "NUM4" ) return VK_NUMPAD4; + else if ( name == "NUM5" ) return VK_NUMPAD5; + else if ( name == "NUM6" ) return VK_NUMPAD6; + else if ( name == "NUM7" ) return VK_NUMPAD7; + else if ( name == "NUM8" ) return VK_NUMPAD8; + else if ( name == "NUM9" ) return VK_NUMPAD9; + else if ( name == "F1" ) return VK_F1; + else if ( name == "F2" ) return VK_F2; + else if ( name == "F3" ) return VK_F3; + else if ( name == "F4" ) return VK_F4; + else if ( name == "F5" ) return VK_F5; + else if ( name == "F6" ) return VK_F6; + else if ( name == "F7" ) return VK_F7; + else if ( name == "F8" ) return VK_F8; + else if ( name == "F9" ) return VK_F9; + else if ( name == "F10" ) return VK_F10; + else if ( name == "F11" ) return VK_F11; + else if ( name == "F12" ) return VK_F12; + else if ( name == "F13" ) return VK_F13; + else if ( name == "F14" ) return VK_F14; + else if ( name == "F15" ) return VK_F15; + else if ( name == "PAUSE" ) return VK_PAUSE; + + else if ( name == "LEFTMOUSE" ) return VK_LBUTTON; + else if ( name == "RIGHTMOUSE" ) return VK_RBUTTON; + else if ( name == "MIDDLEMOUSE" ) return VK_MBUTTON; + else if ( name == "XBUTTON1" ) return VK_XBUTTON1; + else if ( name == "XBUTTON2" ) return VK_XBUTTON2; + return 0; + } } UF_API_CALL spec::win32::Window::Window() : @@ -300,8 +762,6 @@ bool UF_API_CALL spec::win32::Window::hasFocus() const { return this->m_handle == GetForegroundWindow(); } - -#include void UF_API_CALL spec::win32::Window::processEvents() { if ( !this->m_callback ) { MSG message; @@ -311,114 +771,7 @@ void UF_API_CALL spec::win32::Window::processEvents() { } } /* Key inputs */ if ( this->m_asyncParse ) { - std::vector keys; - if ( GetAsyncKeyState('A') & 0x8000 ) keys.push_back('A'); // keys.push_back(this->getKey('A', 0)); - if ( GetAsyncKeyState('B') & 0x8000 ) keys.push_back('B'); // keys.push_back(this->getKey('B', 0)); - if ( GetAsyncKeyState('C') & 0x8000 ) keys.push_back('C'); // keys.push_back(this->getKey('C', 0)); - if ( GetAsyncKeyState('D') & 0x8000 ) keys.push_back('D'); // keys.push_back(this->getKey('D', 0)); - if ( GetAsyncKeyState('E') & 0x8000 ) keys.push_back('E'); // keys.push_back(this->getKey('E', 0)); - if ( GetAsyncKeyState('F') & 0x8000 ) keys.push_back('F'); // keys.push_back(this->getKey('F', 0)); - if ( GetAsyncKeyState('G') & 0x8000 ) keys.push_back('G'); // keys.push_back(this->getKey('G', 0)); - if ( GetAsyncKeyState('H') & 0x8000 ) keys.push_back('H'); // keys.push_back(this->getKey('H', 0)); - if ( GetAsyncKeyState('I') & 0x8000 ) keys.push_back('I'); // keys.push_back(this->getKey('I', 0)); - if ( GetAsyncKeyState('J') & 0x8000 ) keys.push_back('J'); // keys.push_back(this->getKey('J', 0)); - if ( GetAsyncKeyState('K') & 0x8000 ) keys.push_back('K'); // keys.push_back(this->getKey('K', 0)); - if ( GetAsyncKeyState('L') & 0x8000 ) keys.push_back('L'); // keys.push_back(this->getKey('L', 0)); - if ( GetAsyncKeyState('M') & 0x8000 ) keys.push_back('M'); // keys.push_back(this->getKey('M', 0)); - if ( GetAsyncKeyState('N') & 0x8000 ) keys.push_back('N'); // keys.push_back(this->getKey('N', 0)); - if ( GetAsyncKeyState('O') & 0x8000 ) keys.push_back('O'); // keys.push_back(this->getKey('O', 0)); - if ( GetAsyncKeyState('P') & 0x8000 ) keys.push_back('P'); // keys.push_back(this->getKey('P', 0)); - if ( GetAsyncKeyState('Q') & 0x8000 ) keys.push_back('Q'); // keys.push_back(this->getKey('Q', 0)); - if ( GetAsyncKeyState('R') & 0x8000 ) keys.push_back('R'); // keys.push_back(this->getKey('R', 0)); - if ( GetAsyncKeyState('S') & 0x8000 ) keys.push_back('S'); // keys.push_back(this->getKey('S', 0)); - if ( GetAsyncKeyState('T') & 0x8000 ) keys.push_back('T'); // keys.push_back(this->getKey('T', 0)); - if ( GetAsyncKeyState('U') & 0x8000 ) keys.push_back('U'); // keys.push_back(this->getKey('U', 0)); - if ( GetAsyncKeyState('V') & 0x8000 ) keys.push_back('V'); // keys.push_back(this->getKey('V', 0)); - if ( GetAsyncKeyState('W') & 0x8000 ) keys.push_back('W'); // keys.push_back(this->getKey('W', 0)); - if ( GetAsyncKeyState('X') & 0x8000 ) keys.push_back('X'); // keys.push_back(this->getKey('X', 0)); - if ( GetAsyncKeyState('Y') & 0x8000 ) keys.push_back('Y'); // keys.push_back(this->getKey('Y', 0)); - if ( GetAsyncKeyState('Z') & 0x8000 ) keys.push_back('Z'); // keys.push_back(this->getKey('Z', 0)); - if ( GetAsyncKeyState('0') & 0x8000 ) keys.push_back('0'); // keys.push_back(this->getKey('0', 0)); - if ( GetAsyncKeyState('1') & 0x8000 ) keys.push_back('1'); // keys.push_back(this->getKey('1', 0)); - if ( GetAsyncKeyState('2') & 0x8000 ) keys.push_back('2'); // keys.push_back(this->getKey('2', 0)); - if ( GetAsyncKeyState('3') & 0x8000 ) keys.push_back('3'); // keys.push_back(this->getKey('3', 0)); - if ( GetAsyncKeyState('4') & 0x8000 ) keys.push_back('4'); // keys.push_back(this->getKey('4', 0)); - if ( GetAsyncKeyState('5') & 0x8000 ) keys.push_back('5'); // keys.push_back(this->getKey('5', 0)); - if ( GetAsyncKeyState('6') & 0x8000 ) keys.push_back('6'); // keys.push_back(this->getKey('6', 0)); - if ( GetAsyncKeyState('7') & 0x8000 ) keys.push_back('7'); // keys.push_back(this->getKey('7', 0)); - if ( GetAsyncKeyState('8') & 0x8000 ) keys.push_back('8'); // keys.push_back(this->getKey('8', 0)); - if ( GetAsyncKeyState('9') & 0x8000 ) keys.push_back('9'); // keys.push_back(this->getKey('9', 0)); - if ( GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) keys.push_back(VK_ESCAPE); // keys.push_back(this->getKey(VK_ESCAPE, 0)); - if ( GetAsyncKeyState(VK_LCONTROL) & 0x8000 ) keys.push_back(VK_LCONTROL); // keys.push_back(this->getKey(VK_LCONTROL, 0)); - if ( GetAsyncKeyState(VK_LSHIFT) & 0x8000 ) keys.push_back(VK_LSHIFT); // keys.push_back(this->getKey(VK_LSHIFT, 0)); - if ( GetAsyncKeyState(VK_LMENU) & 0x8000 ) keys.push_back(VK_LMENU); // keys.push_back(this->getKey(VK_LMENU, 0)); - if ( GetAsyncKeyState(VK_LWIN) & 0x8000 ) keys.push_back(VK_LWIN); // keys.push_back(this->getKey(VK_LWIN, 0)); - if ( GetAsyncKeyState(VK_RCONTROL) & 0x8000 ) keys.push_back(VK_RCONTROL); // keys.push_back(this->getKey(VK_RCONTROL, 0)); - if ( GetAsyncKeyState(VK_RSHIFT) & 0x8000 ) keys.push_back(VK_RSHIFT); // keys.push_back(this->getKey(VK_RSHIFT, 0)); - if ( GetAsyncKeyState(VK_RMENU) & 0x8000 ) keys.push_back(VK_RMENU); // keys.push_back(this->getKey(VK_RMENU, 0)); - if ( GetAsyncKeyState(VK_RWIN) & 0x8000 ) keys.push_back(VK_RWIN); // keys.push_back(this->getKey(VK_RWIN, 0)); - if ( GetAsyncKeyState(VK_APPS) & 0x8000 ) keys.push_back(VK_APPS); // keys.push_back(this->getKey(VK_APPS, 0)); - if ( GetAsyncKeyState(VK_OEM_4) & 0x8000 ) keys.push_back(VK_OEM_4); // keys.push_back(this->getKey(VK_OEM_4, 0)); - if ( GetAsyncKeyState(VK_OEM_6) & 0x8000 ) keys.push_back(VK_OEM_6); // keys.push_back(this->getKey(VK_OEM_6, 0)); - if ( GetAsyncKeyState(VK_OEM_1) & 0x8000 ) keys.push_back(VK_OEM_1); // keys.push_back(this->getKey(VK_OEM_1, 0)); - if ( GetAsyncKeyState(VK_OEM_COMMA) & 0x8000 ) keys.push_back(VK_OEM_COMMA); // keys.push_back(this->getKey(VK_OEM_COMMA, 0)); - if ( GetAsyncKeyState(VK_OEM_PERIOD) & 0x8000 ) keys.push_back(VK_OEM_PERIOD); // keys.push_back(this->getKey(VK_OEM_PERIOD, 0)); - if ( GetAsyncKeyState(VK_OEM_7) & 0x8000 ) keys.push_back(VK_OEM_7); // keys.push_back(this->getKey(VK_OEM_7, 0)); - if ( GetAsyncKeyState(VK_OEM_2) & 0x8000 ) keys.push_back(VK_OEM_2); // keys.push_back(this->getKey(VK_OEM_2, 0)); - if ( GetAsyncKeyState(VK_OEM_5) & 0x8000 ) keys.push_back(VK_OEM_5); // keys.push_back(this->getKey(VK_OEM_5, 0)); - if ( GetAsyncKeyState(VK_OEM_3) & 0x8000 ) keys.push_back(VK_OEM_3); // keys.push_back(this->getKey(VK_OEM_3, 0)); - if ( GetAsyncKeyState(VK_OEM_PLUS) & 0x8000 ) keys.push_back(VK_OEM_PLUS); // keys.push_back(this->getKey(VK_OEM_PLUS, 0)); - if ( GetAsyncKeyState(VK_OEM_MINUS) & 0x8000 ) keys.push_back(VK_OEM_MINUS); // keys.push_back(this->getKey(VK_OEM_MINUS, 0)); - if ( GetAsyncKeyState(VK_SPACE) & 0x8000 ) keys.push_back(VK_SPACE); // keys.push_back(this->getKey(VK_SPACE, 0)); - if ( GetAsyncKeyState(VK_RETURN) & 0x8000 ) keys.push_back(VK_RETURN); // keys.push_back(this->getKey(VK_RETURN, 0)); - if ( GetAsyncKeyState(VK_BACK) & 0x8000 ) keys.push_back(VK_BACK); // keys.push_back(this->getKey(VK_BACK, 0)); - if ( GetAsyncKeyState(VK_TAB) & 0x8000 ) keys.push_back(VK_TAB); // keys.push_back(this->getKey(VK_TAB, 0)); - if ( GetAsyncKeyState(VK_PRIOR) & 0x8000 ) keys.push_back(VK_PRIOR); // keys.push_back(this->getKey(VK_PRIOR, 0)); - if ( GetAsyncKeyState(VK_NEXT) & 0x8000 ) keys.push_back(VK_NEXT); // keys.push_back(this->getKey(VK_NEXT, 0)); - if ( GetAsyncKeyState(VK_END) & 0x8000 ) keys.push_back(VK_END); // keys.push_back(this->getKey(VK_END, 0)); - if ( GetAsyncKeyState(VK_HOME) & 0x8000 ) keys.push_back(VK_HOME); // keys.push_back(this->getKey(VK_HOME, 0)); - if ( GetAsyncKeyState(VK_INSERT) & 0x8000 ) keys.push_back(VK_INSERT); // keys.push_back(this->getKey(VK_INSERT, 0)); - if ( GetAsyncKeyState(VK_DELETE) & 0x8000 ) keys.push_back(VK_DELETE); // keys.push_back(this->getKey(VK_DELETE, 0)); - if ( GetAsyncKeyState(VK_ADD) & 0x8000 ) keys.push_back(VK_ADD); // keys.push_back(this->getKey(VK_ADD, 0)); - if ( GetAsyncKeyState(VK_SUBTRACT) & 0x8000 ) keys.push_back(VK_SUBTRACT); // keys.push_back(this->getKey(VK_SUBTRACT, 0)); - if ( GetAsyncKeyState(VK_MULTIPLY) & 0x8000 ) keys.push_back(VK_MULTIPLY); // keys.push_back(this->getKey(VK_MULTIPLY, 0)); - if ( GetAsyncKeyState(VK_DIVIDE) & 0x8000 ) keys.push_back(VK_DIVIDE); // keys.push_back(this->getKey(VK_DIVIDE, 0)); - if ( GetAsyncKeyState(VK_LEFT) & 0x8000 ) keys.push_back(VK_LEFT); // keys.push_back(this->getKey(VK_LEFT, 0)); - if ( GetAsyncKeyState(VK_RIGHT) & 0x8000 ) keys.push_back(VK_RIGHT); // keys.push_back(this->getKey(VK_RIGHT, 0)); - if ( GetAsyncKeyState(VK_UP) & 0x8000 ) keys.push_back(VK_UP); // keys.push_back(this->getKey(VK_UP, 0)); - if ( GetAsyncKeyState(VK_DOWN) & 0x8000 ) keys.push_back(VK_DOWN); // keys.push_back(this->getKey(VK_DOWN, 0)); - if ( GetAsyncKeyState(VK_NUMPAD0) & 0x8000 ) keys.push_back(VK_NUMPAD0); // keys.push_back(this->getKey(VK_NUMPAD0, 0)); - if ( GetAsyncKeyState(VK_NUMPAD1) & 0x8000 ) keys.push_back(VK_NUMPAD1); // keys.push_back(this->getKey(VK_NUMPAD1, 0)); - if ( GetAsyncKeyState(VK_NUMPAD2) & 0x8000 ) keys.push_back(VK_NUMPAD2); // keys.push_back(this->getKey(VK_NUMPAD2, 0)); - if ( GetAsyncKeyState(VK_NUMPAD3) & 0x8000 ) keys.push_back(VK_NUMPAD3); // keys.push_back(this->getKey(VK_NUMPAD3, 0)); - if ( GetAsyncKeyState(VK_NUMPAD4) & 0x8000 ) keys.push_back(VK_NUMPAD4); // keys.push_back(this->getKey(VK_NUMPAD4, 0)); - if ( GetAsyncKeyState(VK_NUMPAD5) & 0x8000 ) keys.push_back(VK_NUMPAD5); // keys.push_back(this->getKey(VK_NUMPAD5, 0)); - if ( GetAsyncKeyState(VK_NUMPAD6) & 0x8000 ) keys.push_back(VK_NUMPAD6); // keys.push_back(this->getKey(VK_NUMPAD6, 0)); - if ( GetAsyncKeyState(VK_NUMPAD7) & 0x8000 ) keys.push_back(VK_NUMPAD7); // keys.push_back(this->getKey(VK_NUMPAD7, 0)); - if ( GetAsyncKeyState(VK_NUMPAD8) & 0x8000 ) keys.push_back(VK_NUMPAD8); // keys.push_back(this->getKey(VK_NUMPAD8, 0)); - if ( GetAsyncKeyState(VK_NUMPAD9) & 0x8000 ) keys.push_back(VK_NUMPAD9); // keys.push_back(this->getKey(VK_NUMPAD9, 0)); - if ( GetAsyncKeyState(VK_F1) & 0x8000 ) keys.push_back(VK_F1); // keys.push_back(this->getKey(VK_F1, 0)); - if ( GetAsyncKeyState(VK_F2) & 0x8000 ) keys.push_back(VK_F2); // keys.push_back(this->getKey(VK_F2, 0)); - if ( GetAsyncKeyState(VK_F3) & 0x8000 ) keys.push_back(VK_F3); // keys.push_back(this->getKey(VK_F3, 0)); - if ( GetAsyncKeyState(VK_F4) & 0x8000 ) keys.push_back(VK_F4); // keys.push_back(this->getKey(VK_F4, 0)); - if ( GetAsyncKeyState(VK_F5) & 0x8000 ) keys.push_back(VK_F5); // keys.push_back(this->getKey(VK_F5, 0)); - if ( GetAsyncKeyState(VK_F6) & 0x8000 ) keys.push_back(VK_F6); // keys.push_back(this->getKey(VK_F6, 0)); - if ( GetAsyncKeyState(VK_F7) & 0x8000 ) keys.push_back(VK_F7); // keys.push_back(this->getKey(VK_F7, 0)); - if ( GetAsyncKeyState(VK_F8) & 0x8000 ) keys.push_back(VK_F8); // keys.push_back(this->getKey(VK_F8, 0)); - if ( GetAsyncKeyState(VK_F9) & 0x8000 ) keys.push_back(VK_F9); // keys.push_back(this->getKey(VK_F9, 0)); - if ( GetAsyncKeyState(VK_F10) & 0x8000 ) keys.push_back(VK_F10); // keys.push_back(this->getKey(VK_F10, 0)); - if ( GetAsyncKeyState(VK_F11) & 0x8000 ) keys.push_back(VK_F11); // keys.push_back(this->getKey(VK_F11, 0)); - if ( GetAsyncKeyState(VK_F12) & 0x8000 ) keys.push_back(VK_F12); // keys.push_back(this->getKey(VK_F12, 0)); - if ( GetAsyncKeyState(VK_F13) & 0x8000 ) keys.push_back(VK_F13); // keys.push_back(this->getKey(VK_F13, 0)); - if ( GetAsyncKeyState(VK_F14) & 0x8000 ) keys.push_back(VK_F14); // keys.push_back(this->getKey(VK_F14, 0)); - if ( GetAsyncKeyState(VK_F15) & 0x8000 ) keys.push_back(VK_F15); // keys.push_back(this->getKey(VK_F15, 0)); - if ( GetAsyncKeyState(VK_PAUSE) & 0x8000 ) keys.push_back(VK_PAUSE); // keys.push_back(this->getKey(VK_PAUSE, 0)); - - if ( GetAsyncKeyState(VK_LBUTTON) & 0x8000 ) keys.push_back(VK_LBUTTON); // keys.push_back( this->getKey(VK_LBUTTON, 0) ); - if ( GetAsyncKeyState(VK_RBUTTON) & 0x8000 ) keys.push_back(VK_RBUTTON); // keys.push_back( this->getKey(VK_RBUTTON, 0) ); - if ( GetAsyncKeyState(VK_MBUTTON) & 0x8000 ) keys.push_back(VK_MBUTTON); // keys.push_back( this->getKey(VK_MBUTTON, 0) ); - if ( GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ) keys.push_back(VK_XBUTTON1); // keys.push_back( this->getKey(VK_XBUTTON1, 0) ); - if ( GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ) keys.push_back(VK_XBUTTON2); // keys.push_back( this->getKey(VK_XBUTTON2, 0) ); + std::vector keys = GetKeys(); struct Event { std::string type = "unknown"; @@ -466,11 +819,9 @@ void UF_API_CALL spec::win32::Window::processEvents() { } /* Loop through key inputs */ { for ( auto& key : keys ) { - auto code = this->getKey(key, 0); + auto code = GetKeyName(key); event.key.code = code; event.key.raw = key; - // if ( USE_OPTIMAL ) this->pushEvent(event.type + "." + code, uf::Userdata(uf::userdata::create(event))); - // if ( USE_OPTIMAL ) this->pushEvent(event.type, uf::Userdata(uf::userdata::create(event))); json["key"]["code"] = code; json["key"]["raw"] = key; @@ -1127,235 +1478,10 @@ void UF_API_CALL spec::win32::Window::switchToFullscreen( bool borderless ) { } bool UF_API_CALL spec::win32::Window::isKeyPressed(const std::string& key) { - if ( (key == "A") && (GetAsyncKeyState('A') & 0x8000) ) return true; - if ( (key == "B") && (GetAsyncKeyState('B') & 0x8000) ) return true; - if ( (key == "C") && (GetAsyncKeyState('C') & 0x8000) ) return true; - if ( (key == "D") && (GetAsyncKeyState('D') & 0x8000) ) return true; - if ( (key == "E") && (GetAsyncKeyState('E') & 0x8000) ) return true; - if ( (key == "F") && (GetAsyncKeyState('F') & 0x8000) ) return true; - if ( (key == "G") && (GetAsyncKeyState('G') & 0x8000) ) return true; - if ( (key == "H") && (GetAsyncKeyState('H') & 0x8000) ) return true; - if ( (key == "I") && (GetAsyncKeyState('I') & 0x8000) ) return true; - if ( (key == "J") && (GetAsyncKeyState('J') & 0x8000) ) return true; - if ( (key == "K") && (GetAsyncKeyState('K') & 0x8000) ) return true; - if ( (key == "L") && (GetAsyncKeyState('L') & 0x8000) ) return true; - if ( (key == "M") && (GetAsyncKeyState('M') & 0x8000) ) return true; - if ( (key == "N") && (GetAsyncKeyState('N') & 0x8000) ) return true; - if ( (key == "O") && (GetAsyncKeyState('O') & 0x8000) ) return true; - if ( (key == "P") && (GetAsyncKeyState('P') & 0x8000) ) return true; - if ( (key == "Q") && (GetAsyncKeyState('Q') & 0x8000) ) return true; - if ( (key == "R") && (GetAsyncKeyState('R') & 0x8000) ) return true; - if ( (key == "S") && (GetAsyncKeyState('S') & 0x8000) ) return true; - if ( (key == "T") && (GetAsyncKeyState('T') & 0x8000) ) return true; - if ( (key == "U") && (GetAsyncKeyState('U') & 0x8000) ) return true; - if ( (key == "V") && (GetAsyncKeyState('V') & 0x8000) ) return true; - if ( (key == "W") && (GetAsyncKeyState('W') & 0x8000) ) return true; - if ( (key == "X") && (GetAsyncKeyState('X') & 0x8000) ) return true; - if ( (key == "Y") && (GetAsyncKeyState('Y') & 0x8000) ) return true; - if ( (key == "Z") && (GetAsyncKeyState('Z') & 0x8000) ) return true; - if ( (key == "0") && (GetAsyncKeyState('0') & 0x8000) ) return true; - if ( (key == "1") && (GetAsyncKeyState('1') & 0x8000) ) return true; - if ( (key == "2") && (GetAsyncKeyState('2') & 0x8000) ) return true; - if ( (key == "3") && (GetAsyncKeyState('3') & 0x8000) ) return true; - if ( (key == "4") && (GetAsyncKeyState('4') & 0x8000) ) return true; - if ( (key == "5") && (GetAsyncKeyState('5') & 0x8000) ) return true; - if ( (key == "6") && (GetAsyncKeyState('6') & 0x8000) ) return true; - if ( (key == "7") && (GetAsyncKeyState('7') & 0x8000) ) return true; - if ( (key == "8") && (GetAsyncKeyState('8') & 0x8000) ) return true; - if ( (key == "9") && (GetAsyncKeyState('9') & 0x8000) ) return true; - if ( (key == "Escape") && (GetAsyncKeyState(VK_ESCAPE) & 0x8000) ) return true; - if ( (key == "LControl") && (GetAsyncKeyState(VK_LCONTROL) & 0x8000) ) return true; - if ( (key == "LShift") && (GetAsyncKeyState(VK_LSHIFT) & 0x8000) ) return true; - if ( (key == "LAlt") && (GetAsyncKeyState(VK_LMENU) & 0x8000) ) return true; - if ( (key == "LSystem") && (GetAsyncKeyState(VK_LWIN) & 0x8000) ) return true; - if ( (key == "RControl") && (GetAsyncKeyState(VK_RCONTROL) & 0x8000) ) return true; - if ( (key == "RShift") && (GetAsyncKeyState(VK_RSHIFT) & 0x8000) ) return true; - if ( (key == "RAlt") && (GetAsyncKeyState(VK_RMENU) & 0x8000) ) return true; - if ( (key == "RSystem") && (GetAsyncKeyState(VK_RWIN) & 0x8000) ) return true; - if ( (key == "Apps") && (GetAsyncKeyState(VK_APPS) & 0x8000) ) return true; - if ( (key == "OEM4") && (GetAsyncKeyState(VK_OEM_4) & 0x8000) ) return true; - if ( (key == "OEM6") && (GetAsyncKeyState(VK_OEM_6) & 0x8000) ) return true; - if ( (key == "OEM1") && (GetAsyncKeyState(VK_OEM_1) & 0x8000) ) return true; - if ( (key == "OEMComma") && (GetAsyncKeyState(VK_OEM_COMMA) & 0x8000) ) return true; - if ( (key == "OEMPeriod") && (GetAsyncKeyState(VK_OEM_PERIOD) & 0x8000) ) return true; - if ( (key == "OEM7") && (GetAsyncKeyState(VK_OEM_7) & 0x8000) ) return true; - if ( (key == "OEM2") && (GetAsyncKeyState(VK_OEM_2) & 0x8000) ) return true; - if ( (key == "OEM5") && (GetAsyncKeyState(VK_OEM_5) & 0x8000) ) return true; - if ( (key == "OEM3") && (GetAsyncKeyState(VK_OEM_3) & 0x8000) ) return true; - if ( (key == "OEM+") && (GetAsyncKeyState(VK_OEM_PLUS) & 0x8000) ) return true; - if ( (key == "OEM-") && (GetAsyncKeyState(VK_OEM_MINUS) & 0x8000) ) return true; - if ( (key == " ") && (GetAsyncKeyState(VK_SPACE) & 0x8000) ) return true; - if ( (key == "Enter") && (GetAsyncKeyState(VK_RETURN) & 0x8000) ) return true; - if ( (key == "Back") && (GetAsyncKeyState(VK_BACK) & 0x8000) ) return true; - if ( (key == "Tab") && (GetAsyncKeyState(VK_TAB) & 0x8000) ) return true; - if ( (key == "Prior") && (GetAsyncKeyState(VK_PRIOR) & 0x8000) ) return true; - if ( (key == "Next") && (GetAsyncKeyState(VK_NEXT) & 0x8000) ) return true; - if ( (key == "End") && (GetAsyncKeyState(VK_END) & 0x8000) ) return true; - if ( (key == "Home") && (GetAsyncKeyState(VK_HOME) & 0x8000) ) return true; - if ( (key == "Insert") && (GetAsyncKeyState(VK_INSERT) & 0x8000) ) return true; - if ( (key == "Delete") && (GetAsyncKeyState(VK_DELETE) & 0x8000) ) return true; - if ( (key == "+") && (GetAsyncKeyState(VK_ADD) & 0x8000) ) return true; - if ( (key == "-") && (GetAsyncKeyState(VK_SUBTRACT) & 0x8000) ) return true; - if ( (key == "*") && (GetAsyncKeyState(VK_MULTIPLY) & 0x8000) ) return true; - if ( (key == "/") && (GetAsyncKeyState(VK_DIVIDE) & 0x8000) ) return true; - if ( (key == "Left") && (GetAsyncKeyState(VK_LEFT) & 0x8000) ) return true; - if ( (key == "Right") && (GetAsyncKeyState(VK_RIGHT) & 0x8000) ) return true; - if ( (key == "Up") && (GetAsyncKeyState(VK_UP) & 0x8000) ) return true; - if ( (key == "Down") && (GetAsyncKeyState(VK_DOWN) & 0x8000) ) return true; - if ( (key == "Num0") && (GetAsyncKeyState(VK_NUMPAD0) & 0x8000) ) return true; - if ( (key == "Num1") && (GetAsyncKeyState(VK_NUMPAD1) & 0x8000) ) return true; - if ( (key == "Num2") && (GetAsyncKeyState(VK_NUMPAD2) & 0x8000) ) return true; - if ( (key == "Num3") && (GetAsyncKeyState(VK_NUMPAD3) & 0x8000) ) return true; - if ( (key == "Num4") && (GetAsyncKeyState(VK_NUMPAD4) & 0x8000) ) return true; - if ( (key == "Num5") && (GetAsyncKeyState(VK_NUMPAD5) & 0x8000) ) return true; - if ( (key == "Num6") && (GetAsyncKeyState(VK_NUMPAD6) & 0x8000) ) return true; - if ( (key == "Num7") && (GetAsyncKeyState(VK_NUMPAD7) & 0x8000) ) return true; - if ( (key == "Num8") && (GetAsyncKeyState(VK_NUMPAD8) & 0x8000) ) return true; - if ( (key == "Num9") && (GetAsyncKeyState(VK_NUMPAD9) & 0x8000) ) return true; - if ( (key == "F1") && (GetAsyncKeyState(VK_F1) & 0x8000) ) return true; - if ( (key == "F2") && (GetAsyncKeyState(VK_F2) & 0x8000) ) return true; - if ( (key == "F3") && (GetAsyncKeyState(VK_F3) & 0x8000) ) return true; - if ( (key == "F4") && (GetAsyncKeyState(VK_F4) & 0x8000) ) return true; - if ( (key == "F5") && (GetAsyncKeyState(VK_F5) & 0x8000) ) return true; - if ( (key == "F6") && (GetAsyncKeyState(VK_F6) & 0x8000) ) return true; - if ( (key == "F7") && (GetAsyncKeyState(VK_F7) & 0x8000) ) return true; - if ( (key == "F8") && (GetAsyncKeyState(VK_F8) & 0x8000) ) return true; - if ( (key == "F9") && (GetAsyncKeyState(VK_F9) & 0x8000) ) return true; - if ( (key == "F10") && (GetAsyncKeyState(VK_F10) & 0x8000) ) return true; - if ( (key == "F11") && (GetAsyncKeyState(VK_F11) & 0x8000) ) return true; - if ( (key == "F12") && (GetAsyncKeyState(VK_F12) & 0x8000) ) return true; - if ( (key == "F13") && (GetAsyncKeyState(VK_F13) & 0x8000) ) return true; - if ( (key == "F14") && (GetAsyncKeyState(VK_F14) & 0x8000) ) return true; - if ( (key == "F15") && (GetAsyncKeyState(VK_F15) & 0x8000) ) return true; - if ( (key == "Pause") && (GetAsyncKeyState(VK_PAUSE) & 0x8000) ) return true; - - if ( (key == "LeftMouse") && (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ) return true; - if ( (key == "RightMouse") && (GetAsyncKeyState(VK_RBUTTON) & 0x8000) ) return true; - if ( (key == "MiddleMouse") && (GetAsyncKeyState(VK_MBUTTON) & 0x8000) ) return true; - if ( (key == "XButton1") && (GetAsyncKeyState(VK_XBUTTON1) & 0x8000) ) return true; - if ( (key == "XButton2") && (GetAsyncKeyState(VK_XBUTTON2) & 0x8000) ) return true; - return false; + return GetAsyncKeyState( GetKeyCode( key ) ) & 0x8000; } std::string UF_API_CALL spec::win32::Window::getKey(WPARAM key, LPARAM flags) { - switch (key) { - // Check the scancode to distinguish between left and right shift - case VK_SHIFT: { - static UINT lShift = MapVirtualKeyW(VK_LSHIFT, MAPVK_VK_TO_VSC); - UINT scancode = static_cast((flags & (0xFF << 16)) >> 16); - return scancode == lShift ? "LShift" : "RShift"; - } - // Check the "extended" flag to distinguish between left and right alt - case VK_MENU : return (HIWORD(flags) & KF_EXTENDED) ? "RAlt" : "LAlt"; - // Check the "extended" flag to distinguish between left and right control - case VK_CONTROL : return (HIWORD(flags) & KF_EXTENDED) ? "RControl" : "LControl"; - - // Other keys are reported properly - case VK_LWIN: return "LSystem"; - case VK_RWIN: return "RSystem"; - case VK_APPS: return "Menu"; - case VK_OEM_1: return "SemiColon"; - case VK_OEM_2: return "Slash"; - case VK_OEM_PLUS: return "Equal"; - case VK_OEM_MINUS: return "Dash"; - case VK_OEM_4: return "LBracket"; - case VK_OEM_6: return "RBracket"; - case VK_OEM_COMMA: return "Comma"; - case VK_OEM_PERIOD: return "Period"; - case VK_OEM_7: return "Quote"; - case VK_OEM_5: return "BackSlash"; - case VK_OEM_3: return "Tilde"; - - case VK_ESCAPE: return "Escape"; - case VK_SPACE: return "Space"; - case VK_RETURN: return "Enter"; - case VK_BACK: return "BackSpace"; - case VK_TAB: return "Tab"; - case VK_PRIOR: return "PageUp"; - case VK_NEXT: return "PageDown"; - case VK_END: return "End"; - case VK_HOME: return "Home"; - case VK_INSERT: return "Insert"; - case VK_DELETE: return "Delete"; - case VK_ADD: return "Add"; - case VK_SUBTRACT: return "Subtract"; - case VK_MULTIPLY: return "Multiply"; - case VK_DIVIDE: return "Divide"; - case VK_PAUSE: return "Pause"; - - case VK_F1: return "F1"; - case VK_F2: return "F2"; - case VK_F3: return "F3"; - case VK_F4: return "F4"; - case VK_F5: return "F5"; - case VK_F6: return "F6"; - case VK_F7: return "F7"; - case VK_F8: return "F8"; - case VK_F9: return "F9"; - case VK_F10: return "F10"; - case VK_F11: return "F11"; - case VK_F12: return "F12"; - case VK_F13: return "F13"; - case VK_F14: return "F14"; - case VK_F15: return "F15"; - - case VK_LEFT: return "Left"; - case VK_RIGHT: return "Right"; - case VK_UP: return "Up"; - case VK_DOWN: return "Down"; - - case VK_NUMPAD0: return "Numpad0"; - case VK_NUMPAD1: return "Numpad1"; - case VK_NUMPAD2: return "Numpad2"; - case VK_NUMPAD3: return "Numpad3"; - case VK_NUMPAD4: return "Numpad4"; - case VK_NUMPAD5: return "Numpad5"; - case VK_NUMPAD6: return "Numpad6"; - case VK_NUMPAD7: return "Numpad7"; - case VK_NUMPAD8: return "Numpad8"; - case VK_NUMPAD9: return "Numpad9"; - - case 'Q': return "Q"; - case 'W': return "W"; - case 'E': return "E"; - case 'R': return "R"; - case 'T': return "T"; - case 'Y': return "Y"; - case 'U': return "U"; - case 'I': return "I"; - case 'O': return "O"; - case 'P': return "P"; - - case 'A': return "A"; - case 'S': return "S"; - case 'D': return "D"; - case 'F': return "F"; - case 'G': return "G"; - case 'H': return "H"; - case 'J': return "J"; - case 'K': return "K"; - case 'L': return "L"; - - case 'Z': return "Z"; - case 'X': return "X"; - case 'C': return "C"; - case 'V': return "V"; - case 'B': return "B"; - case 'N': return "N"; - case 'M': return "M"; - - case '1': return "Num1"; - case '2': return "Num2"; - case '3': return "Num3"; - case '4': return "Num4"; - case '5': return "Num5"; - case '6': return "Num6"; - case '7': return "Num7"; - case '8': return "Num8"; - case '9': return "Num9"; - case '0': return "Num0"; - } -// return "Unknown"; - return std::to_string((int) key); + return GetKeyName( key, flags ); } #if defined(UF_USE_VULKAN) && UF_USE_VULKAN == 1 std::vector UF_API_CALL spec::win32::Window::getExtensions( bool validationEnabled ) { diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 37a7d3a9..6a378285 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -10,19 +10,22 @@ #define STB_IMAGE_WRITE_IMPLEMENTATION #include #include +#include // C-tor // Default uf::Image::Image() : m_bpp(8), - m_channels(4) { + m_channels(4), + m_format(0) { } // Just Size uf::Image::Image( const Image::vec2_t& size ) : m_dimensions(size), m_bpp(8), - m_channels(4) + m_channels(4), + m_format(0) { this->m_pixels.reserve(size.x*size.y*this->m_channels); } @@ -32,7 +35,8 @@ uf::Image::Image( Image&& move ) : m_dimensions(std::move(move.m_dimensions)), m_bpp(move.m_bpp), m_channels(move.m_channels), - m_filename(move.m_filename) + m_filename(move.m_filename), + m_format(move.m_format) { } @@ -42,7 +46,8 @@ uf::Image::Image( const Image& copy ) : m_dimensions(copy.m_dimensions), m_bpp(copy.m_bpp), m_channels(copy.m_channels), - m_filename(copy.m_filename) + m_filename(copy.m_filename), + m_format(copy.m_format) { } @@ -51,7 +56,8 @@ uf::Image::Image( Image::container_t&& move, const Image::vec2_t& size ) : m_pixels(std::move(move)), m_dimensions(size), m_bpp(8), - m_channels(4) + m_channels(4), + m_format(0) { } @@ -60,7 +66,8 @@ uf::Image::Image( const Image::container_t& copy, const Image::vec2_t& size ) : m_pixels(copy), m_dimensions(size), m_bpp(8), - m_channels(4) + m_channels(4), + m_format(0) { } @@ -69,25 +76,81 @@ std::string uf::Image::getFilename() const { return this->m_filename; } +#define _PACK4(v) ((v * 0xF) / 0xFF) +#define PACK_ARGB4444(a,r,g,b) (_PACK4(a) << 12) | (_PACK4(r) << 8) | (_PACK4(g) << 4) | (_PACK4(b)) +#define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) ) +#define PACK_ARGB1555(a,r,g,b) \ + (((uint16_t)(a > 0) << 15) | (((uint16_t) r >> 3) << 10) | (((uint16_t)g >> 3) << 5) | ((uint16_t)b >> 3)) + +#define PACK_RGB565(r,g,b) \ + ((((uint16_t)r & 0xf8) << 8) | (((uint16_t) g & 0xfc) << 3) | ((uint16_t) b >> 3)) + // from file bool uf::Image::open( const std::string& filename, bool flip ) { if ( !uf::io::exists(filename) ) UF_EXCEPTION("does not exist: " + filename); std::string extension = uf::io::extension(filename); this->m_filename = filename; this->m_pixels.clear(); - int width, height, channels, bit_depth; - bit_depth = 8; - stbi_set_flip_vertically_on_load(flip); - uint8_t* buffer = stbi_load( filename.c_str(), &width, &height, &channels, STBI_rgb_alpha ); - - channels = 4; - uint len = width * height * channels; + int width = 0, height = 0, channelsDud = 0, bit_depth = 8, channels = 4; +#if UF_ENV_DREAMCAST + if ( extension == "dtex" ) { + struct { + char id[4]; // 'DTEX' + uint16_t width; + uint16_t height; + uint32_t type; + uint32_t size; + } header; + + FILE* file = NULL; + file = fopen(filename.c_str(), "rb"); + fread(&header, sizeof(header), 1, file); + this->m_pixels.resize(header.size); + fread(this->m_pixels.data(), header.size, 1, file); + fclose(file); + + bool twiddled = (header.type & (1 << 26)) < 1; + bool compressed = (header.type & (1 << 30)) > 0; + bool mipmapped = (header.type & (1 << 31)) > 0; + bool strided = (header.type & (1 << 25)) > 0; + uint32_t format = (header.type >> 27) & 0b111; + width = header.width; + height = header.height; + + uint32_t expected = 2 * header.width * header.height; + uint32_t ratio = (uint32_t) (((float) expected) / ((float) header.size)); + bit_depth = 4; + if ( compressed ) { + if ( twiddled ) { + switch ( format ) { + case 0: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; break; + case 1: this->m_format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_RGB_565_VQ_TWID_KOS; channels = 3; break; + case 2: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; break; + default: UF_EXCEPTION(filename << ": invalid texture format"); return false; + } + } else { + switch ( format ) { + case 0: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_1555_VQ_KOS; break; + case 1: this->m_format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS : GL_COMPRESSED_RGB_565_VQ_KOS; channels = 3; break; + case 2: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_4444_VQ_KOS; break; + default: UF_EXCEPTION(filename << ": invalid texture format"); return false; + } + } + } else { UF_EXCEPTION(filename << ": not a compressed texture"); return false; } + } else +#endif + { + stbi_set_flip_vertically_on_load(flip); + uint8_t* buffer = stbi_load( filename.c_str(), &width, &height, &channelsDud, STBI_rgb_alpha ); + size_t len = width * height * channels; + this->m_pixels.insert( this->m_pixels.end(), (uint8_t*) buffer, buffer + len ); + stbi_image_free(buffer); + } + this->m_dimensions.x = width; this->m_dimensions.y = height; this->m_bpp = bit_depth * channels; this->m_channels = channels; - this->m_pixels.insert( this->m_pixels.end(), (uint8_t*) buffer, buffer + len ); - stbi_image_free(buffer); return true; } void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) { @@ -232,6 +295,9 @@ std::size_t& uf::Image::getChannels() { std::size_t uf::Image::getChannels() const { return this->m_channels; } +std::size_t uf::Image::getFormat() const { + return this->m_format; +} std::string uf::Image::getHash() const { return uf::string::sha256( this->m_pixels ); } @@ -253,60 +319,6 @@ bool uf::Image::save( const std::string& filename, bool flip ) const { std::string extension = uf::io::extension(filename); stbi_flip_vertically_on_write(flip); if ( extension == "png" ) { - #if 0 - if ( flip ) - for (uint j = 0; j * 2 < h; ++j) { - uint x = j * w * this->m_bpp/8; - uint y = (h - 1 - j) * w * this->m_bpp/8; - for (uint i = w * this->m_bpp/8; i > 0; --i) { - std::swap( pixels[x], pixels[y] ); - ++x, ++y; - } - } - #endif - #if 0 - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png) - return false; - - png_infop info = png_create_info_struct(png); - if (!info) { - png_destroy_write_struct(&png, &info); - return false; - } - - FILE *fp = fopen(filename.c_str(), "wb"); - if (!fp) { - png_destroy_write_struct(&png, &info); - return false; - } - - png_init_io(png, fp); - png_set_IHDR(png, info, w, h, 8 /* depth */, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if ( this->m_channels == 4 ) png_set_IHDR(png, info, w, h, 8 /* depth */, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if ( this->m_channels == 3 ) png_set_IHDR(png, info, w, h, 8 /* depth */, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_colorp palette = (png_colorp)png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); - if (!palette) { - fclose(fp); - png_destroy_write_struct(&png, &info); - return false; - } - png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH); - png_write_info(png, info); - png_set_packing(png); - - png_bytepp rows = (png_bytepp)png_malloc(png, h * sizeof(png_bytep)); - for (uint i = 0; i < h; ++i) - rows[i] = (png_bytep)(pixels + (h - i - 1) * w * this->m_bpp/8); - - png_write_image(png, rows); - png_write_end(png, info); - png_free(png, palette); - png_destroy_write_struct(&png, &info); - - fclose(fp); - delete[] rows; - #endif stbi_write_png(filename.c_str(), w, h, this->m_channels, &pixels[0], w * this->m_channels); } else if ( extension == "jpg" || extension == "jpeg" ) { stbi_write_jpg(filename.c_str(), w, h, this->m_channels, &pixels[0], w * this->m_channels); diff --git a/engine/src/utils/thread/thread.cpp b/engine/src/utils/thread/thread.cpp index 8c4d1fc3..c7992bd6 100644 --- a/engine/src/utils/thread/thread.cpp +++ b/engine/src/utils/thread/thread.cpp @@ -53,20 +53,17 @@ pod::Thread& UF_API uf::thread::fetchWorker( const std::string& name ) { static int current = 0; static int limit = uf::thread::workers; static uint threads = std::thread::hardware_concurrency(); - if ( ++current >= limit ) current = 0; - std::string thread = name; - if ( current > 0 ) thread += " " + std::to_string(current); - bool exists = uf::thread::has(thread); - auto& pod = exists ? uf::thread::get(thread) : uf::thread::create( thread, true ); - if ( !exists ) { -/* - pod.affinity = (current + 1) % threads; - std::cout << "Create: " << thread << ": " << pod.affinity << std::endl; - BOOL res = SetThreadAffinityMask((HANDLE) pod.thread.native_handle(), 1u << pod.affinity ); - if ( res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Bound worker thread #" << current << " to ID " << pod.affinity << "\n"; - else if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to bind worker thread #" << current << " to ID " << pod.affinity << "\n"; -*/ + int tries = 8; + while ( --tries >= 0 ) { + if ( ++current >= limit ) current = 0; + std::string thread = name; + if ( current > 0 ) thread += " " + std::to_string(current); + bool exists = uf::thread::has(thread); + auto& pod = exists ? uf::thread::get(thread) : uf::thread::create( thread, true ); + if ( std::this_thread::get_id() != pod.thread.get_id() ) return pod; } + bool exists = uf::thread::has( "Main" ); + auto& pod = exists ? uf::thread::get( "Main" ) : uf::thread::create( "Main" , true ); return pod; } void UF_API uf::thread::batchWorkers( const std::vector& functions, bool wait, const std::string& name ) { diff --git a/ext/behaviors/craeture/behavior.cpp b/ext/behaviors/craeture/behavior.cpp index 6596ea3b..6dbf8d1e 100644 --- a/ext/behaviors/craeture/behavior.cpp +++ b/ext/behaviors/craeture/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -58,12 +59,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { } #endif // Hooks -/* - struct { - uf::Timer flash = uf::Timer(false); - uf::Timer sound = uf::Timer(false); - } timers; -*/ +#if 0 static uf::Timer timer(true); this->addHook( "world:Collision.%UID%", [&](ext::json::Value& json){ size_t uid = json["uid"].as(); @@ -88,6 +84,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { if ( normal.z == 1 || normal.z == -1 ) physics.linear.velocity.z = 0; #endif }); +#endif this->addHook( "asset:Cache.Sound.%UID%", [&](ext::json::Value& json){ uf::Scene& world = uf::scene::getCurrentScene(); uf::Serializer& masterdata = world.getComponent(); @@ -103,6 +100,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { sfx.setPosition( transform.position ); sfx.play(); }); +#if 0 this->addHook( "world:Craeture.OnHit.%UID%", [&](ext::json::Value& json){ uint64_t phase = json["phase"].as(); // start color @@ -142,14 +140,15 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { } } }); +#endif } void ext::CraetureBehavior::tick( uf::Object& self ) { +#if 0 uf::Serializer& metadata = this->getComponent(); uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& sMetadata = scene.getComponent(); uf::Serializer& pMetadata = scene.getController().getComponent(); -#if 0 if ( !pMetadata["system"]["control"].as() ) return; if ( !sMetadata["system"]["physics"]["optimizations"]["entity-local update"].as() ) return; @@ -173,4 +172,5 @@ void ext::CraetureBehavior::tick( uf::Object& self ) { void ext::CraetureBehavior::render( uf::Object& self ){} void ext::CraetureBehavior::destroy( uf::Object& self ){} -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/craeture/behavior.h b/ext/behaviors/craeture/behavior.h index b702b123..857038d9 100644 --- a/ext/behaviors/craeture/behavior.h +++ b/ext/behaviors/craeture/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API CraetureBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace CraetureBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/hands/behavior.cpp b/ext/behaviors/hands/behavior.cpp index 40577244..64816f40 100644 --- a/ext/behaviors/hands/behavior.cpp +++ b/ext/behaviors/hands/behavior.cpp @@ -1,3 +1,4 @@ +#if UF_USE_OPENVR #include "behavior.h" #include @@ -484,4 +485,5 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ void ext::PlayerHandBehavior::destroy( uf::Object& self ){ } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/hands/behavior.h b/ext/behaviors/hands/behavior.h index bb24d347..b97ab323 100644 --- a/ext/behaviors/hands/behavior.h +++ b/ext/behaviors/hands/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API PlayerHandBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace PlayerHandBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 96fc49d3..af800130 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -16,7 +16,7 @@ namespace { UF_BEHAVIOR_REGISTER_CPP(ext::LightBehavior) #define this (&self) void ext::LightBehavior::initialize( uf::Object& self ) { - auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); auto& transform = this->getComponent>(); auto& camera = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); @@ -30,31 +30,31 @@ void ext::LightBehavior::initialize( uf::Object& self ) { }); } - if ( !metadata["light"]["bias"]["constant"].is() ) { - metadata["light"]["bias"]["constant"] = 0.00005f; + if ( !metadataJson["light"]["bias"]["constant"].is() ) { + metadataJson["light"]["bias"]["constant"] = 0.00005f; } - if ( !ext::json::isArray( metadata["light"]["color"] ) ) { - metadata["light"]["color"][0] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; - metadata["light"]["color"][1] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; - metadata["light"]["color"][2] = 1; //metadata["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; + if ( !ext::json::isArray( metadataJson["light"]["color"] ) ) { + metadataJson["light"]["color"][0] = 1; //metadataJson["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; + metadataJson["light"]["color"][1] = 1; //metadataJson["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; + metadataJson["light"]["color"][2] = 1; //metadataJson["light"]["color"]["random"].as() ? (rand() % 100) / 100.0 : 1; } #if UF_USE_OPENGL - metadata["light"]["shadows"] = false; + metadataJson["light"]["shadows"] = false; #endif - if ( metadata["light"]["shadows"].as() ) { + if ( metadataJson["light"]["shadows"].as() ) { auto& cameraTransform = camera.getTransform(); cameraTransform.reference = &transform; camera.setStereoscopic(false); - if ( ext::json::isArray( metadata["light"]["radius"] ) ) { + if ( ext::json::isArray( metadataJson["light"]["radius"] ) ) { auto bounds = camera.getBounds(); - bounds.x = metadata["light"]["radius"][0].as(); - bounds.y = metadata["light"]["radius"][1].as(); + bounds.x = metadataJson["light"]["radius"][0].as(); + bounds.y = metadataJson["light"]["radius"][1].as(); camera.setBounds(bounds); } - if ( ext::json::isArray( metadata["light"]["resolution"] ) ) { - camera.setSize( uf::vector::decode( metadata["light"]["resolution"], pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height } ) ); - } else if ( metadata["light"]["resolution"].is() ) { - size_t size = metadata["light"]["resolution"].as(); + if ( ext::json::isArray( metadataJson["light"]["resolution"] ) ) { + camera.setSize( uf::vector::decode( metadataJson["light"]["resolution"], pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height } ) ); + } else if ( metadataJson["light"]["resolution"].is() ) { + size_t size = metadataJson["light"]["resolution"].as(); camera.setSize( {size, size} ); } else { camera.setSize( pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height } ); @@ -64,16 +64,16 @@ void ext::LightBehavior::initialize( uf::Object& self ) { auto& renderMode = this->getComponent(); renderMode.metadata["type"] = "depth"; - renderMode.metadata["depth bias"] = metadata["light"]["bias"]; - renderMode.metadata["renderMode"] = metadata["renderMode"]; + renderMode.metadata["depth bias"] = metadataJson["light"]["bias"]; + renderMode.metadata["renderMode"] = metadataJson["renderMode"]; // std::cout << this->getName() << ": " << renderMode.metadata["renderMode"] << std::endl; - if ( metadata["light"]["type"].as() == "point" ) { - metadata["light"]["fov"] = 90.0f; + if ( metadataJson["light"]["type"].as() == "point" ) { + metadataJson["light"]["fov"] = 90.0f; renderMode.metadata["subpasses"] = 6; } - if ( metadata["light"]["fov"].is() ) { - camera.setFov( metadata["light"]["fov"].as() ); + if ( metadataJson["light"]["fov"].is() ) { + camera.setFov( metadataJson["light"]["fov"].as() ); } camera.updateView(); camera.updateProjection(); @@ -87,149 +87,147 @@ void ext::LightBehavior::initialize( uf::Object& self ) { } + auto updateMetadata = [&](){ + auto& metadata = this->getComponent(); + metadata.color = uf::vector::decode( metadataJson["light"]["color"], pod::Vector3f{1,1,1} ); + metadata.power = metadataJson["light"]["power"].as(); + metadata.bias = metadataJson["light"]["bias"]["shader"].as(); + metadata.shadows = metadataJson["light"]["shadows"].as(); + metadata.renderer.mode = metadataJson["system"]["renderer"]["mode"].as(); + metadata.renderer.rendered = false; + metadata.renderer.external = metadataJson["light"]["external update"].as(); + metadata.renderer.limiter = metadataJson["system"]["renderer"]["timer"].as(); + if ( metadataJson["light"]["type"].is() ) { + metadata.type = metadataJson["light"]["type"].as(); + } else if ( metadataJson["light"]["type"].is() ) { + std::string lightType = metadataJson["light"]["type"].as(); + if ( lightType == "point" ) metadata.type = 1; + else if ( lightType == "spot" ) metadata.type = 2; + } + }; + + this->addHook( "object:UpdateMetadata.%UID%", updateMetadata); + updateMetadata(); } void ext::LightBehavior::tick( uf::Object& self ) { - auto& metadata = this->getComponent(); +#if !UF_ENV_DREAMCAST + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); if ( this->hasComponent() ) { auto& renderMode = this->getComponent(); renderMode.setTarget(""); } - - auto& transform = this->getComponent>(); - auto& parent = this->getParent(); - auto& parentMetadata = parent.getComponent(); - auto& parentTransform = parent.getComponent>(); - // copy from our parent -// if ( parentMetadata["system"]["name"] == "Light" ) { - if ( metadata["light"]["bound"].as() ) { - metadata["light"] = parentMetadata["light"]; - metadata["light"]["bound"] = true; - if ( metadata["light"]["static"].as() ) { - auto flatten = uf::transform::flatten( parentTransform ); - transform.position = flatten.position; +#if 0 + // light fade action + if ( ext::json::isObject( metadataJson["light"]["fade"] ) ) { + if ( ext::json::isNull( metadataJson["light"]["backup"]["power"] ) ) { + metadataJson["light"]["backup"]["power"] = metadataJson["light"]["power"]; } - } else { - // light fade action - if ( ext::json::isObject( metadata["light"]["fade"] ) ) { - if ( ext::json::isNull( metadata["light"]["backup"]["power"] ) ) { - metadata["light"]["backup"]["power"] = metadata["light"]["power"]; - } - if ( ext::json::isNull( metadata["light"]["backup"]["color"] ) ) { - metadata["light"]["backup"]["color"] = metadata["light"]["color"]; - } - // fade towards - int direction = metadata["light"]["fade"]["increment"].as() ? 1 : -1; - metadata["light"]["fade"]["timer"] = metadata["light"]["fade"]["timer"].as() + metadata["light"]["fade"]["rate"].as() * uf::physics::time::delta * direction; - - // 0 .. delta .. 1 .. (1 + timeout * 0.5) - if ( direction == 1 && metadata["light"]["fade"]["timer"].as() >= 0.5f * metadata["light"]["fade"]["timeout"].as() + 1.0f ) { - metadata["light"]["fade"]["increment"] = false; - } else if ( direction == -1 && metadata["light"]["fade"]["timer"].as() <= -0.5f * metadata["light"]["fade"]["timeout"].as() ) { - metadata["light"]["fade"]["increment"] = true; - } - { - float delta = metadata["light"]["fade"]["timer"].as(); - delta = std::clamp( delta, 0.f, 1.f ); - if ( metadata["light"]["fade"]["power"].is() ) { - metadata["light"]["power"] = uf::math::lerp( metadata["light"]["backup"]["power"].as(), metadata["light"]["fade"]["power"].as(), delta ); - } - if ( ext::json::isArray( metadata["light"]["fade"]["color"] ) ) { - pod::Vector3f fadeColor; { - fadeColor.x = metadata["light"]["fade"]["color"][0].as(); - fadeColor.y = metadata["light"]["fade"]["color"][1].as(); - fadeColor.z = metadata["light"]["fade"]["color"][2].as(); - } - pod::Vector3f origColor; { - origColor.x = metadata["light"]["backup"]["color"][0].as(); - origColor.y = metadata["light"]["backup"]["color"][1].as(); - origColor.z = metadata["light"]["backup"]["color"][2].as(); - } - pod::Vector3f color = uf::vector::lerp( origColor, fadeColor, delta ); - - metadata["light"]["color"][0] = color[0]; - metadata["light"]["color"][1] = color[1]; - metadata["light"]["color"][2] = color[2]; - } - } + if ( ext::json::isNull( metadataJson["light"]["backup"]["color"] ) ) { + metadataJson["light"]["backup"]["color"] = metadataJson["light"]["color"]; } - // light flicker action - if ( ext::json::isObject( metadata["light"]["flicker"] ) ) { - float r = (rand() % 100) / 100.0; - float rate = metadata["light"]["flicker"]["rate"].as(); - if ( ext::json::isNull( metadata["light"]["backup"]["power"] ) ) { - metadata["light"]["backup"]["power"] = metadata["light"]["power"]; + // fade towards + int direction = metadataJson["light"]["fade"]["increment"].as() ? 1 : -1; + metadataJson["light"]["fade"]["timer"] = metadataJson["light"]["fade"]["timer"].as() + metadataJson["light"]["fade"]["rate"].as() * uf::physics::time::delta * direction; + + // 0 .. delta .. 1 .. (1 + timeout * 0.5) + if ( direction == 1 && metadataJson["light"]["fade"]["timer"].as() >= 0.5f * metadataJson["light"]["fade"]["timeout"].as() + 1.0f ) { + metadataJson["light"]["fade"]["increment"] = false; + } else if ( direction == -1 && metadataJson["light"]["fade"]["timer"].as() <= -0.5f * metadataJson["light"]["fade"]["timeout"].as() ) { + metadataJson["light"]["fade"]["increment"] = true; + } + { + float delta = metadataJson["light"]["fade"]["timer"].as(); + delta = std::clamp( delta, 0.f, 1.f ); + if ( metadataJson["light"]["fade"]["power"].is() ) { + metadataJson["light"]["power"] = uf::math::lerp( metadataJson["light"]["backup"]["power"].as(), metadataJson["light"]["fade"]["power"].as(), delta ); } - metadata["light"]["flicker"]["timer"] = metadata["light"]["flicker"]["timer"].as() + uf::physics::time::delta; - if ( metadata["light"]["flicker"]["timer"].as() >= metadata["light"]["flicker"]["timeout"].as() ) { - metadata["light"]["flicker"]["timer"] = 0; - metadata["light"]["power"] = (r > rate) ? metadata["light"]["flicker"]["power"].as() : metadata["light"]["backup"]["power"].as(); + if ( ext::json::isArray( metadataJson["light"]["fade"]["color"] ) ) { + pod::Vector3f fadeColor; { + fadeColor.x = metadataJson["light"]["fade"]["color"][0].as(); + fadeColor.y = metadataJson["light"]["fade"]["color"][1].as(); + fadeColor.z = metadataJson["light"]["fade"]["color"][2].as(); + } + pod::Vector3f origColor; { + origColor.x = metadataJson["light"]["backup"]["color"][0].as(); + origColor.y = metadataJson["light"]["backup"]["color"][1].as(); + origColor.z = metadataJson["light"]["backup"]["color"][2].as(); + } + pod::Vector3f color = uf::vector::lerp( origColor, fadeColor, delta ); + + metadataJson["light"]["color"][0] = color[0]; + metadataJson["light"]["color"][1] = color[1]; + metadataJson["light"]["color"][2] = color[2]; } } } - - // skip if we're handling the camera view matrix position ourselves - if ( !metadata["light"]["external update"].as() ) { - auto& camera = this->getComponent(); - // omni light - if ( metadata["light"]["shadows"].as() && metadata["light"]["type"].as() == "point" ) { - auto transform = camera.getTransform(); - std::vector> rotations = { - /* - {0, 0, 0, 1}, - {0, 0.707107, 0, -0.707107}, - {0, 1, 0, 0}, - {0, 0.707107, 0, 0.707107}, - {-0.707107, 0, 0, -0.707107}, - {0.707107, 0, 0, -0.707107}, - */ - uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 1 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 2 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 3 * 1.57079633 ), - - uf::quaternion::axisAngle( { 1, 0, 0 }, 1 * 1.57079633 ), - uf::quaternion::axisAngle( { 1, 0, 0 }, 3 * 1.57079633 ), - }; - for ( size_t i = 0; i < rotations.size(); ++i ) { - auto transform = camera.getTransform(); - transform.orientation = rotations[i]; - camera.setView( uf::matrix::inverse( uf::transform::model( transform, false ) ), i ); - } - } else { - camera.updateView(); + // light flicker action + if ( ext::json::isObject( metadataJson["light"]["flicker"] ) ) { + float r = (rand() % 100) / 100.0; + float rate = metadataJson["light"]["flicker"]["rate"].as(); + if ( ext::json::isNull( metadataJson["light"]["backup"]["power"] ) ) { + metadataJson["light"]["backup"]["power"] = metadataJson["light"]["power"]; + } + metadataJson["light"]["flicker"]["timer"] = metadataJson["light"]["flicker"]["timer"].as() + uf::physics::time::delta; + if ( metadataJson["light"]["flicker"]["timer"].as() >= metadataJson["light"]["flicker"]["timeout"].as() ) { + metadataJson["light"]["flicker"]["timer"] = 0; + metadataJson["light"]["power"] = (r > rate) ? metadataJson["light"]["flicker"]["power"].as() : metadataJson["light"]["backup"]["power"].as(); } - // for ( std::size_t i = 0; i < 2; ++i ) camera.setView( uf::matrix::inverse( uf::transform::model( transform ) ), i ); } - +#endif // limit updating our shadow map if ( this->hasComponent() ) { + // skip if we're handling the camera view matrix position ourselves + if ( !metadata.renderer.external ) { + auto& camera = this->getComponent(); + // omni light + if ( metadata.shadows && metadata.type == 1 ) { + auto transform = camera.getTransform(); + std::vector> rotations = { + uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), + uf::quaternion::axisAngle( { 0, 1, 0 }, 1 * 1.57079633 ), + uf::quaternion::axisAngle( { 0, 1, 0 }, 2 * 1.57079633 ), + uf::quaternion::axisAngle( { 0, 1, 0 }, 3 * 1.57079633 ), + + uf::quaternion::axisAngle( { 1, 0, 0 }, 1 * 1.57079633 ), + uf::quaternion::axisAngle( { 1, 0, 0 }, 3 * 1.57079633 ), + }; + for ( size_t i = 0; i < rotations.size(); ++i ) { + auto transform = camera.getTransform(); + transform.orientation = rotations[i]; + camera.setView( uf::matrix::inverse( uf::transform::model( transform, false ) ), i ); + } + } else { + camera.updateView(); + } + } bool execute = true; // enable renderer every X seconds - if ( metadata["system"]["renderer"]["limiter"].is() ) { - if ( metadata["system"]["renderer"]["timer"].as() > metadata["system"]["renderer"]["limiter"].as() ) { - metadata["system"]["renderer"]["timer"] = 0; + if ( metadata.renderer.limiter > 0 ) { + if ( metadata.renderer.timer > metadata.renderer.limiter ) { + metadata.renderer.timer = 0; execute = true; } else { - metadata["system"]["renderer"]["timer"] = metadata["system"]["renderer"]["timer"].as() + uf::physics::time::delta; + metadata.renderer.timer = metadata.renderer.timer + uf::physics::time::delta; execute = false; } - } else if ( metadata["system"]["renderer"]["mode"].is() ) { - std::string mode = metadata["system"]["renderer"]["mode"].as(); + } else { // round robin, enable if it's the light's current turn - if ( mode == "round robin" ) { + if ( metadata.renderer.mode == "round robin" ) { if ( ::roundRobin.current < ::roundRobin.lights.size() ) execute = ::roundRobin.lights[::roundRobin.current] == this; // render only if the light is used - } else if ( mode == "occlusion" ) { - execute = metadata["system"]["renderer"]["rendered"].as(); + } else if ( metadata.renderer.mode == "occlusion" ) { + execute = metadata.renderer.rendered; // light baking, but sadly re-bakes every time the command buffer is recorded - } else if ( mode == "once" ) { - execute = !metadata["system"]["renderer"]["rendered"].as(); - metadata["system"]["renderer"]["rendered"] = true; + } else if ( metadata.renderer.mode == "once" ) { + execute = !metadata.renderer.rendered; + metadata.renderer.rendered = true; } } auto& renderMode = this->getComponent(); renderMode.execute = execute; } +#endif } void ext::LightBehavior::render( uf::Object& self ){ diff --git a/ext/behaviors/light/behavior.h b/ext/behaviors/light/behavior.h index def94038..ce45629b 100644 --- a/ext/behaviors/light/behavior.h +++ b/ext/behaviors/light/behavior.h @@ -4,14 +4,29 @@ #include #include #include +#include namespace ext { - class EXT_API LightBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace LightBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + struct Metadata { + pod::Vector3f color = {1,1,1}; + float power = 0.0f; + float bias = 0.0f; + bool shadows = false; + size_t type = 0; + struct { + std::string mode = "in-range"; + float limiter = 0.0f; + float timer = 0.0f; + bool rendered = false; + bool external = false; + } renderer; + }; + } } \ No newline at end of file diff --git a/ext/behaviors/noise/behavior.cpp b/ext/behaviors/noise/behavior.cpp index 3481bb3a..d946b915 100644 --- a/ext/behaviors/noise/behavior.cpp +++ b/ext/behaviors/noise/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -120,4 +121,5 @@ void ext::NoiseBehavior::tick( uf::Object& self ) { } void ext::NoiseBehavior::render( uf::Object& self ) {} void ext::NoiseBehavior::destroy( uf::Object& self ) {} -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/noise/behavior.h b/ext/behaviors/noise/behavior.h index f6c9a3d7..d5d39b5b 100644 --- a/ext/behaviors/noise/behavior.h +++ b/ext/behaviors/noise/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API NoiseBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace NoiseBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index 91ad9590..8cac678b 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -11,29 +11,18 @@ #include #include #include +#include #include - +#if 0 namespace { - uf::Serializer masterTableGet( const std::string& table ) { - uf::Scene& scene = uf::scene::getCurrentScene(); - uf::Serializer& mastertable = scene.getComponent(); - return mastertable["system"]["mastertable"][table]; - } uf::Serializer masterDataGet( const std::string& table, const std::string& key ) { uf::Scene& scene = uf::scene::getCurrentScene(); uf::Serializer& mastertable = scene.getComponent(); return mastertable["system"]["mastertable"][table][key]; } - inline int64_t parseInt( const std::string& str ) { - return atoi(str.c_str()); - } - - inline std::string colorString( const std::string& hex ) { - return "%#" + hex + "%"; - } } - +#endif UF_BEHAVIOR_REGISTER_CPP(ext::PlayerBehavior) #define this (&self) void ext::PlayerBehavior::initialize( uf::Object& self ) { @@ -114,13 +103,10 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { } ); } } - metadata["system"]["control"] = true; - this->addHook( "window:Mouse.CursorVisibility", [&](ext::json::Value& json){ metadata["system"]["control"] = !json["state"].as(); }); - // Rotate Camera this->addHook( "window:Mouse.Moved", [&](ext::json::Value& json){ // discard events sent by os, only trust client now @@ -181,7 +167,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { camera.updateView(); } }); - +#if 0 this->addHook( ":Update.%UID%", [&](ext::json::Value& json){ // for ( auto& member : json[""]["transients"] ) { ext::json::forEach(metadata[""]["transients"], [&](ext::json::Value& member){ @@ -257,7 +243,9 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { metadata["system"]["menu"] = ""; metadata["system"]["cooldown"] = uf::physics::time::current + 1; }); - +#endif +#if 0 +#if UF_USE_DISCORD // Discord Integration this->addHook( "discord.Activity.Update.%UID%", [&](ext::json::Value& json){ std::string leaderId = metadata[""]["party"][0].as(); @@ -270,13 +258,38 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { uf::hooks.call( "discord:Activity.Update", payload ); }); this->queueHook("discord.Activity.Update.%UID%", ext::json::null(), 1.0); +#endif +#endif +#if !UF_ENTITY_METADATA_USE_JSON + { + auto& metadataBehavior = this->getComponent(); + auto& metadataSystem = metadata["system"]; + metadataBehavior.system.menu = metadataSystem["menu"].as(); + metadataBehavior.system.control = metadataSystem["control"].as(); + metadataBehavior.system.crouching = metadataSystem["crouching"].as(); + metadataBehavior.system.noclipped = metadataSystem["noclipped"].as(); + auto& metadataSystemPhysics = metadataSystem["physics"]; + metadataBehavior.system.physics.impulse = metadataSystemPhysics["impulse"].as(); + metadataBehavior.system.physics.rotate = metadataSystemPhysics["rotate"].as(); + metadataBehavior.system.physics.move = metadataSystemPhysics["move"].as(); + metadataBehavior.system.physics.run = metadataSystemPhysics["run"].as(); + metadataBehavior.system.physics.walk = metadataSystemPhysics["walk"].as(); + metadataBehavior.system.physics.collision = metadataSystemPhysics["collision"].as(); + metadataBehavior.system.physics.jump = uf::vector::decode(metadataSystemPhysics["jump"], pod::Vector3f{}); + metadataBehavior.system.physics.crouch = metadataSystemPhysics["crouch"].as(); + auto& metadataAudioFootstep = metadata["audio"]["footstep"]; + ext::json::forEach( metadataAudioFootstep["list"], [&]( const ext::json::Value& value ){ + metadataBehavior.audio.footstep.list.emplace_back(value); + }); + metadataBehavior.audio.footstep.volume = metadataAudioFootstep["volume"].as(); + } +#endif } void ext::PlayerBehavior::tick( uf::Object& self ) { - uf::Camera& camera = this->getComponent(); - pod::Transform<>& transform = this->getComponent>(); - pod::Physics& physics = this->getComponent(); - uf::Serializer& metadata = this->getComponent(); - uf::Scene& scene = uf::scene::getCurrentScene(); + auto& camera = this->getComponent(); + auto& transform = this->getComponent>(); + auto& physics = this->getComponent(); + auto& scene = uf::scene::getCurrentScene(); struct { bool forward; @@ -293,20 +306,6 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { bool paused; bool vee; } keys = { - #if UF_ENV_DREAMCAST - .forward = uf::Window::isKeyPressed("Up"), - .backwards = uf::Window::isKeyPressed("Down"), - .left = uf::Window::isKeyPressed("Left"), - .right = uf::Window::isKeyPressed("Right"), - .lookLeft = uf::Window::isKeyPressed("C"), - .lookRight = uf::Window::isKeyPressed("X"), - .running = uf::Window::isKeyPressed("Y"), - .walk = uf::Window::isKeyPressed("_"), - .jump = uf::Window::isKeyPressed("A"), - .crouch = uf::Window::isKeyPressed("X"), - .paused = uf::Window::isKeyPressed("Start"), - .vee = uf::Window::isKeyPressed("B"), - #else .forward = uf::Window::isKeyPressed("W"), .backwards = uf::Window::isKeyPressed("S"), .left = uf::Window::isKeyPressed("A"), @@ -319,26 +318,38 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { .crouch = uf::Window::isKeyPressed("LControl"), .paused = uf::Window::isKeyPressed("Escape"), .vee = uf::Window::isKeyPressed("V"), - #endif }; -#if UF_USE_OPENVR - if ( ext::openvr::context ) { - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadUp" )["state"].as() ) keys.forward = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadDown" )["state"].as() ) keys.backwards = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadLeft" )["state"].as() ) keys.lookLeft = true; // keys.left = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "dpadRight" )["state"].as() ) keys.lookRight = true; // keys.right = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "thumbclick" )["state"].as() ) keys.running = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Right, "a" )["state"].as() ) keys.jump = true; + if ( spec::controller::connected() ) { + #if UF_USE_OPENVR + if ( spec::controller::pressed( "R_DPAD_UP" ) ) keys.forward = true; + if ( spec::controller::pressed( "R_DPAD_DOWN" ) ) keys.backwards = true; + if ( spec::controller::pressed( "R_DPAD_LEFT" ) ) keys.lookLeft = true; // keys.left = true; + if ( spec::controller::pressed( "R_DPAD_RIGHT" ) ) keys.lookRight = true; // keys.right = true; + if ( spec::controller::pressed( "R_JOYSTICK" ) ) keys.running = true; + if ( spec::controller::pressed( "R_A" ) ) keys.jump = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadUp" )["state"].as() ) keys.forward = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadDown" )["state"].as() ) keys.backwards = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadLeft" )["state"].as() ) keys.lookLeft = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "dpadRight" )["state"].as() ) keys.lookRight = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "thumbclick" )["state"].as() ) keys.crouch = true, keys.walk = true; - if ( ext::openvr::controllerState( vr::Controller_Hand::Hand_Left, "a" )["state"].as() ) keys.paused = true; + if ( spec::controller::pressed( "L_DPAD_UP" ) ) keys.forward = true; + if ( spec::controller::pressed( "L_DPAD_DOWN" ) ) keys.backwards = true; + if ( spec::controller::pressed( "L_DPAD_LEFT" ) ) keys.lookLeft = true; + if ( spec::controller::pressed( "L_DPAD_RIGHT" ) ) keys.lookRight = true; + if ( spec::controller::pressed( "L_JOYSTICK" ) ) keys.crouch = true, keys.walk = true; + if ( spec::controller::pressed( "L_A" ) ) keys.paused = true; + #else + if ( spec::controller::pressed( "DPAD_UP" ) ) keys.forward = true; + if ( spec::controller::pressed( "DPAD_DOWN" ) ) keys.backwards = true; + if ( spec::controller::pressed( "DPAD_LEFT" ) ) keys.lookLeft = true; + if ( spec::controller::pressed( "DPAD_RIGHT" ) ) keys.lookRight = true; + if ( spec::controller::pressed( "A" ) ) keys.jump = true; + if ( spec::controller::pressed( "B" ) ) keys.running = true; + if ( spec::controller::pressed( "X" ) ) keys.crouch = true, keys.walk = true; + if ( spec::controller::pressed( "Y" ) ) keys.vee = true; + if ( spec::controller::pressed( "L_TRIGGER" ) ) keys.left = true; + if ( spec::controller::pressed( "R_TRIGGER" ) ) keys.right = true; + if ( spec::controller::pressed( "START" ) ) keys.paused = true; + #endif } -#endif + struct { bool updateCamera = true; bool deltaCrouch = false; @@ -350,10 +361,33 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { std::string targetAnimation = ""; } stats; + auto& metadata = this->getComponent(); +#if UF_ENTITY_METADATA_USE_JSON + auto& metadataJson = this->getComponent(); + auto& metadataSystem = metadataJson["system"]; + metadata.system.menu = metadataSystem["menu"].as(); + metadata.system.control = metadataSystem["control"].as(); + metadata.system.crouching = metadataSystem["crouching"].as(); + metadata.system.noclipped = metadataSystem["noclipped"].as(); + auto& metadataSystemPhysics = metadataSystem["physics"]; + metadata.system.physics.impulse = metadataSystemPhysics["impulse"].as(); + metadata.system.physics.rotate = metadataSystemPhysics["rotate"].as(); + metadata.system.physics.move = metadataSystemPhysics["move"].as(); + metadata.system.physics.run = metadataSystemPhysics["run"].as(); + metadata.system.physics.walk = metadataSystemPhysics["walk"].as(); + metadata.system.physics.collision = metadataSystemPhysics["collision"].as(); + metadata.system.physics.jump = uf::vector::decode(metadataSystemPhysics["jump"], pod::Vector3f{}); + metadata.system.physics.crouch = metadataSystemPhysics["crouch"].as(); + auto& metadataAudioFootstep = metadataJson["audio"]["footstep"]; + ext::json::forEach( metadataAudioFootstep["list"], [&]( const ext::json::Value& value ){ + metadata.audio.footstep.list.emplace_back(value); + }); + metadata.audio.footstep.volume = metadataAudioFootstep["volume"].as(); +#endif stats.floored = fabs(physics.linear.velocity.y) < 0.01f; - stats.menu = metadata["system"]["menu"].as(); - stats.impulse = metadata["system"]["physics"]["impulse"].as(); - stats.noclipped = metadata["system"]["noclipped"].as(); + stats.menu = metadata.system.menu; + stats.impulse = metadata.system.physics.impulse; + stats.noclipped = metadata.system.noclipped; struct { float move = 4; float walk = 1; @@ -361,12 +395,12 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { float rotate = uf::physics::time::delta; float limitSquared = 4*4; } speed; { - speed.rotate *= metadata["system"]["physics"]["rotate"].as(); - speed.move = metadata["system"]["physics"]["move"].as(); - speed.run = metadata["system"]["physics"]["run"].as() / metadata["system"]["physics"]["move"].as(); - speed.walk = metadata["system"]["physics"]["walk"].as() / metadata["system"]["physics"]["move"].as(); + speed.rotate *= metadata.system.physics.rotate; + speed.move = metadata.system.physics.move; + speed.run = metadata.system.physics.run / speed.move; + speed.walk = metadata.system.physics.walk / speed.move; } - if ( !metadata["system"]["physics"]["collision"].as() ) { + if ( !metadata.system.physics.collision ) { stats.impulse = true; } if ( keys.running ) speed.move *= speed.run; @@ -378,27 +412,26 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { // make assumptions if ( stats.menu == "" && keys.paused ) { stats.menu = "paused"; - metadata["system"]["control"] = false; + metadata.system.control = false; uf::hooks.call("menu:Pause"); } - else if ( !metadata["system"]["control"].as() ) { + else if ( !metadata.system.control ) { stats.menu = "menu"; } else if ( stats.menu == "" ) { - metadata["system"]["control"] = true; + metadata.system.control = true; } else { - metadata["system"]["control"] = false; + metadata.system.control = false; } - metadata["system"]["menu"] = stats.menu; + metadata.system.menu = stats.menu; auto& collider = this->getComponent(); - if ( metadata["system"]["control"].as() ) { + if ( metadata.system.control ) { { TIMER(0.25, keys.vee && ) { - bool state = !metadata["system"]["noclipped"].as(); - metadata["system"]["noclipped"] = state; + bool state = !stats.noclipped; + metadata.system.noclipped = state; - std::cout << "Toggling noclip: " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; + UF_DEBUG_MSG( (state ? "En" : "Dis") << "abled noclip: " << uf::vector::toString(transform.position)); if ( state ) { - std::cout << "Enabled noclip" << std::endl; #if UF_USE_BULLET if ( collider.body ) { collider.body->setGravity(btVector3(0,0.0,0)); @@ -407,7 +440,6 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } #endif } else { - std::cout << "Disabled noclip" << std::endl; #if UF_USE_BULLET if ( collider.body ) { collider.body->setGravity(btVector3(0,-9.81,0)); @@ -440,16 +472,11 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { int polarity = keys.forward ? 1 : -1; float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); if ( mag < speed.limitSquared ) { - // physics.linear.velocity += translator.forward * speed.move * polarity; - // mag = uf::vector::magnitude(physics.linear.velocity); mag = uf::vector::magnitude(physics.linear.velocity + translator.forward * speed.move * polarity); } else mag = speed.limitSquared; - pod::Vector3 correction = translator.forward * sqrt(mag) * polarity; + pod::Vector3 correction = translator.forward * ::sqrt(mag) * polarity; if ( collider.body && !collider.shared ) { - // physics.linear.velocity.x += correction.x; - // physics.linear.velocity.z += correction.z; - // ext::bullet::move( collider, physics.linear.velocity ); queued += correction; } else { if ( stats.impulse && stats.noclipped ) { @@ -467,16 +494,11 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { int polarity = keys.right ? 1 : -1; float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); if ( mag < speed.limitSquared ) { - // physics.linear.velocity += translator.right * speed.move * polarity; - // mag = uf::vector::magnitude(physics.linear.velocity); mag = uf::vector::magnitude(physics.linear.velocity + translator.right * speed.move * polarity); } else mag = speed.limitSquared; - pod::Vector3 correction = translator.right * sqrt(mag) * polarity; + pod::Vector3 correction = translator.right * ::sqrt(mag) * polarity; if ( collider.body && !collider.shared ) { - // physics.linear.velocity.x += correction.x; - // physics.linear.velocity.z += correction.z; - // ext::bullet::move( collider, physics.linear.velocity ); queued += correction; } else { if ( stats.impulse && stats.noclipped ) { @@ -509,8 +531,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } } if ( keys.jump ) { + pod::Vector3f yump = metadata.system.physics.jump; if ( collider.body && !collider.shared ) { - pod::Vector3f yump = uf::vector::decode(metadata["system"]["physics"]["jump"], pod::Vector3f{}); if ( fabs(yump.x) > 0.001f ) physics.linear.velocity.x = yump.x; if ( fabs(yump.y) > 0.001f ) physics.linear.velocity.y = yump.y; if ( fabs(yump.z) > 0.001f ) physics.linear.velocity.z = yump.z; @@ -518,9 +540,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { ext::bullet::move( collider, physics.linear.velocity ); #endif } else { - if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x += metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y += metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z += metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; + transform.position += yump * uf::physics::time::delta; } } } @@ -531,7 +551,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { ext::bullet::applyRotation( collider, transform.up, -speed.rotate ); #endif } else { - uf::transform::rotate( transform, transform.up, -speed.rotate ), stats.updateCamera = true; + uf::transform::rotate( transform, transform.up, -speed.rotate ); } stats.updateCamera = true; } @@ -541,14 +561,14 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { ext::bullet::applyRotation( collider, transform.up, speed.rotate ); #endif } else { - uf::transform::rotate( transform, transform.up, speed.rotate ), stats.updateCamera = true; + uf::transform::rotate( transform, transform.up, speed.rotate ); } stats.updateCamera = true; } if ( keys.crouch ) { + pod::Vector3f yump = metadata.system.physics.jump; if ( stats.noclipped ) { if ( collider.body && !collider.shared ) { - pod::Vector3f yump = uf::vector::decode(metadata["system"]["physics"]["jump"], pod::Vector3f{}); if ( fabs(yump.x) > 0.001f ) physics.linear.velocity.x = -yump.x; if ( fabs(yump.y) > 0.001f ) physics.linear.velocity.y = -yump.y; if ( fabs(yump.z) > 0.001f ) physics.linear.velocity.z = -yump.z; @@ -557,18 +577,16 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { #endif } } else { - if ( !metadata["system"]["physics"]["collision"].as() ) { - if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x -= metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y -= metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z -= metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; + if ( !metadata.system.physics.collision ) { + transform.position -= yump * uf::physics::time::delta; } else { - if ( !metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; - metadata["system"]["crouching"] = true; + if ( !metadata.system.crouching ) stats.deltaCrouch = true; + metadata.system.crouching = true; } } } else { - if ( metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; - metadata["system"]["crouching"] = false; + if ( metadata.system.crouching ) stats.deltaCrouch = true; + metadata.system.crouching = false; } } if ( stats.noclipped && !keys.forward && !keys.backwards && !keys.left && !keys.right && !keys.jump && !keys.crouch ) { @@ -580,27 +598,27 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } } if ( stats.deltaCrouch ) { - float delta = metadata["system"]["physics"]["crouch"].as(); - if ( metadata["system"]["crouching"].as() ) camera.getTransform().position.y -= delta; + float delta = metadata.system.physics.crouch; + if ( metadata.system.crouching ) camera.getTransform().position.y -= delta; else camera.getTransform().position.y += delta; stats.updateCamera = true; } - +#if UF_USE_OPENAL if ( stats.floored ) { if ( stats.walking ) { auto& emitter = this->getComponent(); - int cycle = rand() % metadata["audio"]["footstep"]["list"].size(); - std::string filename = metadata["audio"]["footstep"]["list"][cycle].as(); + int cycle = rand() % metadata.audio.footstep.list.size(); + std::string filename = metadata.audio.footstep.list[cycle]; uf::Audio& footstep = emitter.add(filename); bool playing = false; - for ( uint i = 0; i < metadata["audio"]["footstep"]["list"].size(); ++i ) { - uf::Audio& audio = emitter.add(metadata["audio"]["footstep"]["list"][i].as()); + for ( uint i = 0; i < metadata.audio.footstep.list.size(); ++i ) { + uf::Audio& audio = emitter.add(metadata.audio.footstep.list[i]); if ( audio.playing() ) playing = true; } if ( !playing ) { footstep.play(); - footstep.setVolume(metadata["audio"]["footstep"]["volume"].as()); + footstep.setVolume(metadata.audio.footstep.volume); footstep.setPosition( transform.position ); // [0, 1] @@ -618,171 +636,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { stats.targetAnimation = "idle_wank"; } } -#if 0 - { - TIMER(0.25, keys.vee && ) { - if ( ext::json::isNull( metadata["system"]["physics"]["backup"]["collision"] ) ) - metadata["system"]["physics"]["backup"]["collision"] = metadata["system"]["physics"]["collision"]; - if ( !metadata["system"]["physics"]["collision"].as() ) { - metadata["system"]["physics"]["collision"] = metadata["system"]["physics"]["backup"]["collision"]; - } else { - metadata["system"]["physics"]["collision"] = 0; - } - - std::cout << "Toggling noclip: " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; - std::cout << metadata.dump(1, '\t') << std::endl; - - // metadata["system"]["physics"]["collision"] = !metadata["system"]["physics"]["collision"].as(); - physics.linear.velocity = {0,0,0}; - } - } - - - if ( ext::json::isObject( metadata["system"]["physics"]["clamp"] ) ) { - if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["x"] ) ) { - transform.position.x = std::clamp( transform.position.x, metadata["system"]["physics"]["clamp"]["x"][0].as(), metadata["system"]["physics"]["clamp"]["x"][1].as() ); - } - if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["y"] ) ) { - auto previous = transform.position.y; - transform.position.y = std::clamp( transform.position.y, metadata["system"]["physics"]["clamp"]["y"][0].as(), metadata["system"]["physics"]["clamp"]["y"][1].as() ); - if ( transform.position.y > previous ) { - physics.linear.velocity.y = 0; - stats.floored = true; - } - } - if ( ext::json::isArray( metadata["system"]["physics"]["clamp"]["z"] ) ) { - transform.position.z = std::clamp( transform.position.z, metadata["system"]["physics"]["clamp"]["z"][0].as(), metadata["system"]["physics"]["clamp"]["z"][1].as() ); - } - } - - if ( metadata["system"]["control"].as() ) { - if ( stats.floored ) { - pod::Transform<> translator = transform; - if ( ext::openvr::context ) { - bool useController = true; - translator.orientation = uf::quaternion::multiply( transform.orientation * pod::Vector4f{1,1,1,1}, useController ? (ext::openvr::controllerQuaternion( vr::Controller_Hand::Hand_Right ) * pod::Vector4f{1,1,1,1}) : ext::openvr::hmdQuaternion() ); - translator = uf::transform::reorient( translator ); - - translator.forward *= { 1, 0, 1 }; - translator.right *= { 1, 0, 1 }; - - translator.forward = uf::vector::normalize( translator.forward ); - translator.right = uf::vector::normalize( translator.right ); - } - if ( keys.forward || keys.backwards ) { - int polarity = keys.forward ? 1 : -1; - float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); - if ( mag < speed.limitSquared ) { - physics.linear.velocity += translator.forward * speed.move * polarity; - mag = uf::vector::magnitude(physics.linear.velocity); - } else mag = speed.limitSquared; - pod::Vector3 correction = translator.forward * sqrt(mag) * polarity; - if ( stats.impulse ) { - physics.linear.velocity.x = correction.x; - physics.linear.velocity.z = correction.z; - } else { - correction *= uf::physics::time::delta; - transform.position.x += correction.x; - transform.position.z += correction.z; - } - stats.updateCamera = (stats.walking = true); - } - if ( keys.left || keys.right ) { - int polarity = keys.right ? 1 : -1; - float mag = uf::vector::magnitude(physics.linear.velocity * pod::Vector3{1, 0, 1}); - if ( mag < speed.limitSquared ) { - physics.linear.velocity += translator.right * speed.move * polarity; - mag = uf::vector::magnitude(physics.linear.velocity); - } else mag = speed.limitSquared; - pod::Vector3 correction = translator.right * sqrt(mag) * polarity; - if ( stats.impulse ) { - physics.linear.velocity.x = correction.x; - physics.linear.velocity.z = correction.z; - } else { - correction *= uf::physics::time::delta; - transform.position.x += correction.x; - transform.position.z += correction.z; - } - stats.updateCamera = (stats.walking = true); - } - if ( keys.jump ) { - if ( !metadata["system"]["physics"]["collision"].as() ) { - if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x += metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y += metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z += metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; - } else { - if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) physics.linear.velocity.x = metadata["system"]["physics"]["jump"][0].as(); - if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) physics.linear.velocity.y = metadata["system"]["physics"]["jump"][1].as(); - if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) physics.linear.velocity.z = metadata["system"]["physics"]["jump"][2].as(); - } - } - } - - if ( keys.lookLeft ) { - uf::transform::rotate( transform, transform.up, -speed.rotate ), stats.updateCamera = true; - } - if ( keys.lookRight ) { - uf::transform::rotate( transform, transform.up, speed.rotate ), stats.updateCamera = true; - } - - if ( keys.crouch ) { - if ( !metadata["system"]["physics"]["collision"].as() ) { - if ( metadata["system"]["physics"]["jump"][0].as() != 0 ) transform.position.x -= metadata["system"]["physics"]["jump"][0].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][1].as() != 0 ) transform.position.y -= metadata["system"]["physics"]["jump"][1].as() * uf::physics::time::delta; - if ( metadata["system"]["physics"]["jump"][2].as() != 0 ) transform.position.z -= metadata["system"]["physics"]["jump"][2].as() * uf::physics::time::delta; - } else { - if ( !metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; - metadata["system"]["crouching"] = true; - } - } else { - if ( metadata["system"]["crouching"].as() ) stats.deltaCrouch = true; - metadata["system"]["crouching"] = false; - } - } - if ( stats.deltaCrouch ) { - float delta = metadata["system"]["physics"]["crouch"].as(); - if ( metadata["system"]["crouching"].as() ) camera.getTransform().position.y -= delta; - else camera.getTransform().position.y += delta; - stats.updateCamera = true; - } - - if ( stats.floored ) { - if ( stats.walking ) { - uf::SoundEmitter& emitter = this->getComponent(); - int cycle = rand() % metadata["audio"]["footstep"]["list"].size(); - std::string filename = metadata["audio"]["footstep"]["list"][cycle].as(); - uf::Audio& footstep = emitter.add(filename); - - bool playing = false; - for ( uint i = 0; i < metadata["audio"]["footstep"]["list"].size(); ++i ) { - uf::Audio& audio = emitter.add(metadata["audio"]["footstep"]["list"][i].as()); - if ( audio.playing() ) playing = true; - } - if ( !playing ) { - footstep.play(); - footstep.setVolume(metadata["audio"]["footstep"]["volume"].as()); - footstep.setPosition( transform.position ); - - // [0, 1] - float modulation = (rand() % 100) / 100.0; - // [0, 0.1] - modulation *= 0.1f; - // [-0.05, 0.05] - modulation -= 0.05f; - if ( keys.running ) modulation += 0.5f; - footstep.setPitch(1 + modulation); - } - // set animation to walk - stats.targetAnimation = "walk"; - } else if ( !keys.jump ) { - physics.linear.velocity.x = 0; - physics.linear.velocity.y = 0; - physics.linear.velocity.z = 0; - stats.targetAnimation = "idle_wank"; - } - } #endif - +#if !UF_ENV_DREAMCAST // set animation to idle if ( stats.targetAnimation != "" ) { auto* playerModel = this->findByName("Player: Model"); @@ -796,54 +651,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } } } -/* - { - auto flatten = uf::transform::flatten( transform ); - static pod::Quaternion<> storedCameraOrientation = transform.orientation; - - const pod::Quaternion<> prevCameraOrientation = storedCameraOrientation; - const pod::Quaternion<> curCameraOrientation = transform.orientation; - const pod::Quaternion<> deltaOrientation = uf::quaternion::multiply( curCameraOrientation, uf::quaternion::inverse( prevCameraOrientation ) ) ; - const pod::Vector3f deltaAngles = uf::quaternion::eulerAngles( deltaOrientation ); - float magnitude = uf::vector::magnitude( deltaOrientation ); - if ( magnitude > 0.0001f ) { - uf::Serializer payload; - payload["previous"] = uf::vector::encode( prevCameraOrientation ); - payload["current"] = uf::vector::encode( curCameraOrientation ); - payload["delta"] = uf::vector::encode( deltaOrientation ); - payload["euler"] = uf::vector::encode( deltaAngles ); - payload["angle"]["pitch"] = deltaAngles.x; - payload["angle"]["yaw"] = deltaAngles.y; - payload["angle"]["roll"] = deltaAngles.z; - payload["magnitude"] = magnitude; - this->callHook("controller:Camera.Rotated", payload); - } - storedCameraOrientation = transform.orientation; - } -*/ -/* - // translate movement in HMD to give HUD feedback - if ( ext::openvr::context ) { - static pod::Quaternion<> prevCameraOrientation = ext::openvr::hmdQuaternion(); - const pod::Quaternion<> curCameraOrientation = ext::openvr::hmdQuaternion(); - const pod::Vector3f prevEulerAngle = uf::quaternion::eulerAngles( prevCameraOrientation ); - const pod::Vector3f curEulerAngle = uf::quaternion::eulerAngles( curCameraOrientation ); - const pod::Vector3f deltaAngles = uf::vector::subtract( curEulerAngle, prevEulerAngle ); - float magnitude = uf::vector::magnitude( deltaAngles ); - if ( magnitude > 0.0001f ) { - uf::Serializer payload; - payload["previous"] = uf::vector::encode( prevCameraOrientation ); - payload["current"] = uf::vector::encode( curCameraOrientation ); - payload["euler"] = uf::vector::encode( deltaAngles ); - payload["angle"]["pitch"] = deltaAngles.x; - payload["angle"]["yaw"] = deltaAngles.y; - payload["angle"]["roll"] = deltaAngles.z; - payload["magnitude"] = magnitude; - this->callHook("controller:Camera.Rotated", payload); - } - prevCameraOrientation = curCameraOrientation; - } -*/ +#endif +#if UF_USE_LUA #define TRACK_ORIENTATION(ORIENTATION) {\ static pod::Quaternion<> storedCameraOrientation = ORIENTATION;\ const pod::Quaternion<> prevCameraOrientation = storedCameraOrientation;\ @@ -854,7 +663,6 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { combinedDeltaOrientation = uf::quaternion::multiply( deltaOrientation, combinedDeltaOrientation );\ storedCameraOrientation = ORIENTATION;\ } - { pod::Quaternion<> combinedDeltaOrientation = {0,0,0,1}; pod::Vector3f combinedDeltaAngles = {}; @@ -871,10 +679,29 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { this->callHook("controller:Camera.Rotated", payload); } } +#endif + if ( stats.updateCamera ) camera.updateView(); - - if ( stats.updateCamera ) - camera.updateView(); +#if UF_ENTITY_METADATA_USE_JSON + auto& metadataJson = this->getComponent(); + auto& metadataSystem = metadataJson["system"] + metadataSystem["menu"] = metadata.system.menu; + metadataSystem["control"] = metadata.system.control; + metadataSystem["crouching"] = metadata.system.crouching; + metadataSystem["noclipped"] = metadata.system.noclipped; + auto& metadataSystemPhysics = metadataSystem["physics"] + metadataSystemPhysics["impulse"] = metadata.system.physics.impulse; + metadataSystemPhysics["rotate"] = metadata.system.physics.rotate; + metadataSystemPhysics["move"] = metadata.system.physics.move; + metadataSystemPhysics["run"] = metadata.system.physics.run; + metadataSystemPhysics["walk"] = metadata.system.physics.walk; + metadataSystemPhysics["collision"] = metadata.system.physics.collision; + metadataSystemPhysics["jump"] = uf::vector::encode(metadata.system.physics.jump); + metadataSystemPhysics["crouch"] = metadata.system.physics.crouch; + auto& metadataAudioFootstep = metadata["audio"]["footstep"]; + metadataAudioFootstep["list"] = metadata.audio.footstep.list; + metadataAudioFootstep["volume"] = metadata.audio.footstep.volume +#endif } void ext::PlayerBehavior::render( uf::Object& self ){} diff --git a/ext/behaviors/player/behavior.h b/ext/behaviors/player/behavior.h index a6b843b3..de850c87 100644 --- a/ext/behaviors/player/behavior.h +++ b/ext/behaviors/player/behavior.h @@ -4,14 +4,39 @@ #include #include #include +#include namespace ext { - class EXT_API PlayerBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace PlayerBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + struct Metadata { + struct { + struct { + bool collision = true; + bool impulse = true; + float crouch = -1.0f; + float rotate = 1.0f; + float move = 1.0f; + float run = 1.0f; + float walk = 1.0f; + pod::Vector3f jump = {0,8,0}; + } physics; + bool control = true; + std::string menu = ""; + bool crouching = false; + bool noclipped = false; + } system; + struct { + struct { + std::vector list; + float volume; + } footstep; + } audio; + }; + } } \ No newline at end of file diff --git a/ext/behaviors/player/model/behavior.h b/ext/behaviors/player/model/behavior.h index 9ef6b002..de6ce387 100644 --- a/ext/behaviors/player/model/behavior.h +++ b/ext/behaviors/player/model/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API PlayerModelBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace PlayerModelBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/portal/behavior.cpp b/ext/behaviors/portal/behavior.cpp index 789405d4..cb9050de 100644 --- a/ext/behaviors/portal/behavior.cpp +++ b/ext/behaviors/portal/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -162,4 +163,5 @@ void ext::PortalBehavior::destroy( uf::Object& self ){ uf::renderer::removeRenderMode( &renderMode, false ); this->deleteComponent(); } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/portal/behavior.h b/ext/behaviors/portal/behavior.h index 293b42a1..27ef921d 100644 --- a/ext/behaviors/portal/behavior.h +++ b/ext/behaviors/portal/behavior.h @@ -6,20 +6,20 @@ #include namespace ext { - class EXT_API PortalsBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; - class EXT_API PortalBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace PortalsBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } + namespace PortalBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index f4e900de..afbbf457 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -22,6 +22,7 @@ #include +#include "../light/behavior.h" #include "../../ext.h" #include "../../gui/gui.h" @@ -29,7 +30,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::ExtSceneBehavior) #define this ((uf::Scene*) &self) void ext::ExtSceneBehavior::initialize( uf::Object& self ) { uf::Asset& assetLoader = this->getComponent(); - uf::Serializer& metadata = this->getComponent(); + uf::Serializer& metadataJson = this->getComponent(); this->addHook( "system:Quit.%UID%", [&](ext::json::Value& json){ std::cout << json << std::endl; @@ -38,21 +39,19 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { this->addHook( "world:Music.LoadPrevious.%UID%", [&](ext::json::Value& json){ - if ( metadata["previous bgm"]["filename"] == "" ) return; + if ( metadataJson["previous bgm"]["filename"] == "" ) return; - std::string filename = metadata["previous bgm"]["filename"].as(); - float timestamp = metadata["previous bgm"]["timestamp"].as(); - -// std::cout << metadata["previous bgm"] << std::endl; + std::string filename = metadataJson["previous bgm"]["filename"].as(); + float timestamp = metadataJson["previous bgm"]["timestamp"].as(); uf::Audio& audio = this->getComponent(); if ( audio.playing() ) { - metadata["previous bgm"]["filename"] = audio.getFilename(); - metadata["previous bgm"]["timestamp"] = audio.getTime(); + metadataJson["previous bgm"]["filename"] = audio.getFilename(); + metadataJson["previous bgm"]["timestamp"] = audio.getTime(); audio.stop(); } audio.load(filename); - audio.setVolume(metadata["volumes"]["bgm"].as()); + audio.setVolume(metadataJson["volumes"]["bgm"].as()); audio.setTime(timestamp); audio.play(); }); @@ -70,7 +69,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { if ( audio.playing() ) audio.stop(); audio.load(filename); - audio.setVolume(metadata["volumes"]["bgm"].as()); + audio.setVolume(metadataJson["volumes"]["bgm"].as()); audio.play(); }); @@ -83,12 +82,12 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { uf::Object* manager = (uf::Object*) this->globalFindByName("Gui Manager"); if ( !manager ) return; uf::Serializer payload; - std::string config = metadata["menus"]["pause"].is() ? metadata["menus"]["pause"].as() : "/scenes/worldscape/gui/pause/menu.json"; + std::string config = metadataJson["menus"]["pause"].is() ? metadataJson["menus"]["pause"].as() : "/scenes/worldscape/gui/pause/menu.json"; uf::Object& gui = manager->loadChild(config, false); payload["uid"] = gui.getUid(); - uf::Serializer& metadata = gui.getComponent(); - metadata["menu"] = json["menu"]; + uf::Serializer& metadataJson = gui.getComponent(); + metadataJson["menu"] = json["menu"]; gui.initialize(); // return payload; @@ -101,27 +100,20 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }); this->addHook( "shader:Update.%UID%", [&](ext::json::Value& _json){ uf::Serializer json = _json; - json["mode"] = json["mode"].as() | metadata["system"]["renderer"]["shader"]["mode"].as(); - metadata["system"]["renderer"]["shader"]["mode"] = json["mode"]; - metadata["system"]["renderer"]["shader"]["parameters"] = json["parameters"]; + json["mode"] = json["mode"].as() | metadataJson["system"]["renderer"]["shader"]["mode"].as(); + metadataJson["system"]["renderer"]["shader"]["mode"] = json["mode"]; + metadataJson["system"]["renderer"]["shader"]["parameters"] = json["parameters"]; }); - /* store viewport size */ { -// metadata["system"]["window"]["size"]["x"] = uf::renderer::settings::width; -// metadata["system"]["window"]["size"]["y"] = uf::renderer::settings::height; -// ext::gui::size.current.x = uf::renderer::settings::width; -// ext::gui::size.current.y = uf::renderer::settings::height; - - this->addHook( "window:Resized", [&](ext::json::Value& json){ - pod::Vector2ui size; { - size.x = json["window"]["size"]["x"].as(); - size.y = json["window"]["size"]["y"].as(); - } - - metadata["system"]["window"] = json["system"]["window"]; - ext::gui::size.current = size; - }); - } + /* store viewport size */ + this->addHook( "window:Resized", [&](ext::json::Value& json){ + pod::Vector2ui size; { + size.x = json["window"]["size"]["x"].as(); + size.y = json["window"]["size"]["y"].as(); + } + metadataJson["system"]["window"] = json["system"]["window"]; + ext::gui::size.current = size; + }); // lock control { uf::Serializer payload; @@ -141,14 +133,13 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { }; auto& noiseGenerator = this->getComponent(); - auto& metadata = this->getComponent(); noiseGenerator.seed(rand()); float high = std::numeric_limits::min(); float low = std::numeric_limits::max(); - float amplitude = metadata["noise"]["amplitude"].is() ? metadata["noise"]["amplitude"].as() : 1.5; - pod::Vector3ui size = uf::vector::decode(metadata["noise"]["size"], pod::Vector3ui{256, 256, 256}); - pod::Vector3d coefficients = uf::vector::decode(metadata["noise"]["coefficients"], pod::Vector3d{3.0, 3.0, 3.0}); + float amplitude = metadataJson["noise"]["amplitude"].is() ? metadataJson["noise"]["amplitude"].as() : 1.5; + pod::Vector3ui size = uf::vector::decode(metadataJson["noise"]["size"], pod::Vector3ui{256, 256, 256}); + pod::Vector3d coefficients = uf::vector::decode(metadataJson["noise"]["coefficients"], pod::Vector3d{3.0, 3.0, 3.0}); std::vector pixels(size.x * size.y * size.z); std::vector perlins(size.x * size.y * size.z); @@ -211,36 +202,31 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { texture.fromBuffers( (void*) pixels.data(), pixels.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, size.x, size.y, 1, filenames.size() ); } #endif + + auto& metadata = this->getComponent(); + metadata.max.textures = metadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); + metadata.max.lights = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); + metadata.light.enabled = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); + metadata.light.shadowSamples = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as(); + metadata.light.shadowThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as(); + metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); + metadata.light.ambient = uf::vector::decode( metadataJson["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } ); + metadata.light.specular = uf::vector::decode( metadataJson["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } ); + metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } ); + metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as(); + metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as(); + metadata.fog.range = uf::vector::decode( metadataJson["light"]["fog"]["range"], pod::Vector2f{ 0, 0 } ); + metadata.fog.density.offset = uf::vector::decode( metadataJson["light"]["fog"]["density"]["offset"], pod::Vector4f{ 0, 0, 0, 0 } ); + metadata.fog.density.timescale = metadataJson["light"]["fog"]["density"]["timescale"].as(); + metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as(); + metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as(); + metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as(); } void ext::ExtSceneBehavior::tick( uf::Object& self ) { - uf::Serializer& metadata = this->getComponent(); - uf::Asset& assetLoader = this->getComponent(); - - /* check if audio needs to loop */ { - auto& bgm = this->getComponent(); - float current = bgm.getTime(); - float end = bgm.getDuration(); - float epsilon = 0.005f; - if ( current + epsilon >= end || !bgm.playing() ) { - // intro to main transition - std::string filename = bgm.getFilename(); - filename = assetLoader.getOriginal(filename); - if ( filename.find("_intro") != std::string::npos ) { - assetLoader.load(uf::string::replace( filename, "_intro", "" ), this->formatHookName("asset:Load.%UID%")); - // loop - } else { - bgm.setTime(0); - if ( !bgm.playing() ) bgm.play(); - } - } - } - { - uf::hooks.call("game:Frame.Start"); - } - + auto& metadata = this->getComponent(); + auto& metadataJson = this->getComponent(); /* Regain control if nothing requests it */ { - uf::Object* menu = (uf::Object*) this->globalFindByName("Gui: Menu"); - if ( !menu ) { + if ( !this->globalFindByName("Gui: Menu") ) { uf::Serializer payload; payload["state"] = false; uf::hooks.call("window:Mouse.CursorVisibility", payload); @@ -251,7 +237,11 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uf::hooks.call("window:Mouse.CursorVisibility", payload); } } +#if 0 + uf::hooks.call("game:Frame.Start"); + uf::Serializer& metadata = this->getComponent(); + uf::Asset& assetLoader = this->getComponent(); /* Print World Tree */ { TIMER(1, uf::Window::isKeyPressed("U") && ) { std::function filter = []( uf::Entity* entity, int indent ) { @@ -301,7 +291,27 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uf::iostream << instantiator << "\n"; } } - +#endif +#if UF_USE_OPENAL + auto& assetLoader = this->getComponent(); + /* check if audio needs to loop */ { + auto& bgm = this->getComponent(); + float current = bgm.getTime(); + float end = bgm.getDuration(); + float epsilon = 0.005f; + if ( current + epsilon >= end || !bgm.playing() ) { + // intro to main transition + std::string filename = bgm.getFilename(); + filename = assetLoader.getOriginal(filename); + if ( filename.find("_intro") != std::string::npos ) { + assetLoader.load(uf::string::replace( filename, "_intro", "" ), this->formatHookName("asset:Load.%UID%")); + // loop + } else { + bgm.setTime(0); + if ( !bgm.playing() ) bgm.play(); + } + } + } /* Updates Sound Listener */ { auto& controller = this->getController(); // copy @@ -312,15 +322,40 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { transform = uf::transform::reorient( transform ); } transform.forward *= -1; - #if UF_USE_OPENAL ext::oal.listener( "POSITION", { transform.position.x, transform.position.y, transform.position.z } ); ext::oal.listener( "VELOCITY", { 0, 0, 0 } ); ext::oal.listener( "ORIENTATION", { transform.forward.x, transform.forward.y, transform.forward.z, transform.up.x, transform.up.y, transform.up.z } ); - #endif } +#endif -#if UF_USE_VULKAN - /* Update lights */ if ( metadata["light"]["should"].as() ) { +#if UF_ENTITY_METADATA_USE_JSON + metadata.max.textures = metadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); + metadata.max.lights = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); + metadata.light.enabled = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); + metadata.light.shadowSamples = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as(); + metadata.light.shadowThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as(); + metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); + metadata.light.ambient = uf::vector::decode( metadataJson["light"]["ambient"], pod::Vector4f{ 1, 1, 1, 1 } ); + metadata.light.specular = uf::vector::decode( metadataJson["light"]["specular"], pod::Vector4f{ 1, 1, 1, 1 } ); + metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } ); + metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as(); + metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as(); + metadata.fog.range = uf::vector::decode( metadataJson["light"]["fog"]["range"], pod::Vector2f{ 0, 0 } ); + metadata.fog.density.offset = uf::vector::decode( metadataJson["light"]["fog"]["density"]["offset"], pod::Vector4f{ 0, 0, 0, 0 } ); + metadata.fog.density.timescale = metadataJson["light"]["fog"]["density"]["timescale"].as(); + metadata.fog.density.threshold = metadataJson["light"]["fog"]["density"]["threshold"].as(); + metadata.fog.density.multiplier = metadataJson["light"]["fog"]["density"]["multiplier"].as(); + metadata.fog.density.scale = metadataJson["light"]["fog"]["density"]["scale"].as(); +#else + if ( !metadata.max.textures ) metadata.max.textures = metadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); + if ( !metadata.max.lights ) metadata.max.lights = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); + if ( !metadata.light.enabled ) metadata.light.enabled = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); + if ( !metadata.light.shadowSamples ) metadata.light.shadowSamples = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as(); + if ( !metadata.light.shadowThreshold ) metadata.light.shadowThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as(); + if ( !metadata.light.updateThreshold ) metadata.light.updateThreshold = metadataJson["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); +#endif + + /* Update lights */ if ( metadata.light.enabled ) { auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); auto& camera = controller.getComponent(); @@ -329,8 +364,79 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { auto& controllerTransform = controller.getComponent>(); std::vector blitters = renderMode.getBlitters(); - size_t maxTextures = metadata["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(); + #if UF_USE_OPENGL + struct LightInfo { + uf::Entity* entity = NULL; + pod::Vector4f position = {0,0,0,1}; + pod::Vector4f color = {0,0,0,1}; + float distance = 0; + float power = 0; + }; + std::vector entities; + if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( entity == &controller || entity == this ) continue; + if ( entity->getName() != "Light" && !entity->hasComponent() ) continue; + auto& metadata = entity->getComponent(); + if ( metadata.power <= 0 ) continue; + LightInfo& info = entities.emplace_back(); + auto& transform = entity->getComponent>(); + auto flatten = uf::transform::flatten( transform ); + info.entity = entity; + info.position = flatten.position; + info.position.w = 1; + info.color = metadata.color; + info.color.w = 1; + info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ); + info.power = metadata.power; + } + } else { + this->process([&]( uf::Entity* entity ) { if ( !entity ) return; + if ( entity == &controller || entity == this ) return; + if ( entity->getName() != "Light" && !entity->hasComponent() ) return; + auto& metadata = entity->getComponent(); + if ( metadata.power <= 0 ) return; + LightInfo& info = entities.emplace_back(); + auto& transform = entity->getComponent>(); + auto flatten = uf::transform::flatten( transform ); + info.entity = entity; + info.position = flatten.position; + info.position.w = 1; + info.color = metadata.color; + info.color.w = 1; + info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ); + info.power = metadata.power; + }); + } + std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){ + return l.distance < r.distance; + }); + + static GLint glMaxLights = 0; + if ( !glMaxLights ) glGetIntegerv(GL_MAX_LIGHTS, &glMaxLights); + metadata.max.lights = std::min( (size_t) glMaxLights, metadata.max.lights ); + // add lighting + { + size_t i = 0; + for ( ; i < entities.size() && i < metadata.max.lights; ++i ) { + auto& info = entities[i]; + uf::Entity* entity = info.entity; + GLenum target = GL_LIGHT0+i; + GL_ERROR_CHECK(glEnable(target)); + GL_ERROR_CHECK(glLightfv(target, GL_AMBIENT, &metadata.light.ambient[0])); + GL_ERROR_CHECK(glLightfv(target, GL_SPECULAR, &metadata.light.specular[0])); + GL_ERROR_CHECK(glLightfv(target, GL_DIFFUSE, &info.color[0])); + GL_ERROR_CHECK(glLightfv(target, GL_POSITION, &info.position[0])); + GL_ERROR_CHECK(glLightf(target, GL_CONSTANT_ATTENUATION, 0.0f)); + GL_ERROR_CHECK(glLightf(target, GL_LINEAR_ATTENUATION, 0)); + GL_ERROR_CHECK(glLightf(target, GL_QUADRATIC_ATTENUATION, 1.0f / info.power)); + } + for ( ; i < metadata.max.lights; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i)); + } + #elif UF_USE_VULKAN + size_t maxTextures = metadata.max.textures; struct UniformDescriptor { struct Matrices { alignas(16) pod::Matrix4f view[2]; @@ -378,73 +484,82 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { struct LightInfo { uf::Entity* entity = NULL; + pod::Vector4f color = {0,0,0,0}; pod::Vector3f position = {0,0,0}; + float power = 0; float distance = 0; + float bias = 0; bool shadows = false; + size_t type = 0; }; std::vector entities; std::vector graphs; - - this->process([&]( uf::Entity* entity ) { if ( !entity ) return; - auto& metadata = entity->getComponent(); - if ( entity == &controller ) return; - if ( entity == this ) return; + if ( uf::scene::useGraph ) { + auto graph = uf::scene::generateGraph(); + for ( auto entity : graph ) { + if ( entity == &controller || entity == this ) continue; if ( entity->hasComponent() ) graphs.emplace_back(&entity->getComponent()); - // if ( entity->hasComponent() && entity->hasComponent() ) graphs.emplace_back(entity); - // - if ( entity->getName() != "Light" && !ext::json::isObject( metadata["light"] ) ) return; - // + if ( entity->getName() != "Light" && !entity->hasComponent() ) continue; + auto& metadata = entity->getComponent(); if ( entity->hasComponent() ) { auto& renderMode = entity->getComponent(); - metadata["system"]["renderer"]["rendered"] = false; - if ( metadata["system"]["renderer"]["mode"].as() == "in-range" ) { - renderMode.execute = false; - } + if ( metadata.renderer.mode == "in-range" ) renderMode.execute; } - // is a component of an shadowing point light - if ( metadata["light"]["bound"].as() ) return; + if ( metadata.power <= 0 ) continue; LightInfo& info = entities.emplace_back(); auto& transform = entity->getComponent>(); auto flatten = uf::transform::flatten( transform ); info.entity = entity; info.position = flatten.position; + info.color = metadata.color; + info.color.w = metadata.power; info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ); - info.shadows = metadata["light"]["shadows"].as(); + info.shadows = metadata.shadows; + info.bias = metadata.bias; + info.type = metadata.type; + } + } else { + this->process([&]( uf::Entity* entity ) { if ( !entity ) return; + if ( entity == &controller || entity == this ) return; + if ( entity->hasComponent() ) graphs.emplace_back(&entity->getComponent()); + if ( entity->getName() != "Light" && !entity->hasComponent() ) return; + auto& metadata = entity->getComponent(); + if ( entity->hasComponent() ) { + auto& renderMode = entity->getComponent(); + if ( metadata.renderer.mode == "in-range" ) renderMode.execute; + } + if ( metadata.power <= 0 ) return; + LightInfo& info = entities.emplace_back(); + auto& transform = entity->getComponent>(); + auto flatten = uf::transform::flatten( transform ); + info.entity = entity; + info.position = flatten.position; + info.color = metadata.color; + info.color.w = metadata.power; + info.distance = uf::vector::magnitude( uf::vector::subtract( flatten.position, controllerTransform.position ) ); + info.shadows = metadata.shadows; + info.bias = metadata.bias; + info.type = metadata.type; }); + } std::sort( entities.begin(), entities.end(), [&]( LightInfo& l, LightInfo& r ){ return l.distance < r.distance; }); - int shadowSamples = metadata["system"]["config"]["engine"]["scenes"]["lights"]["shadow samples"].as(); + int& shadowSamples = metadata.light.shadowSamples; + int& shadowThreshold = metadata.light.shadowThreshold; if ( shadowSamples <= 0 ) shadowSamples = 16; - - int shadowThreshold = metadata["system"]["config"]["engine"]["scenes"]["lights"]["shadow threshold"].as(); if ( shadowThreshold <= 0 ) shadowThreshold = std::numeric_limits::max(); { std::vector scratch; scratch.reserve(entities.size()); for ( size_t i = 0; i < entities.size(); ++i ) { auto& info = entities[i]; - auto& metadata = info.entity->getComponent(); if ( info.shadows && --shadowThreshold <= 0 ) info.shadows = false; scratch.emplace_back(info); } entities = scratch; } - - if ( controllerMetadata["light"]["should"].as() ) { - auto& info = entities.emplace_back(); - info.entity = &controller; - info.position = controllerTransform.position; - info.distance = 0; - info.shadows = false; - } - - if ( !metadata["light"]["fog"]["step scale"].is() ) metadata["light"]["fog"]["step scale"] = 16.0f; - if ( !metadata["light"]["fog"]["absorbtion"].is() ) metadata["light"]["fog"]["absorbtion"] = 0.85f; - if ( !metadata["light"]["fog"]["density"]["threshold"].is() ) metadata["light"]["fog"]["density"]["threshold"] = 0.5f; - if ( !metadata["light"]["fog"]["density"]["multiplier"].is() ) metadata["light"]["fog"]["density"]["multiplier"] = 5.0f; - if ( !metadata["light"]["fog"]["density"]["scale"].is() ) metadata["light"]["fog"]["density"]["scale"] = 50.0f; for ( auto* blitter : blitters ) { auto& graphic = *blitter; @@ -462,38 +577,27 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { uniforms->matrices.iProjectionView[i] = uf::matrix::inverse( uniforms->matrices.projection[i] * uniforms->matrices.view[i] ); } - uniforms->ambient = uf::vector::decode( metadata["light"]["ambient"], uniforms->ambient ); + uniforms->ambient = metadata.light.ambient; uniforms->msaa = ext::vulkan::settings::msaa; - // uniforms->msaa = metadata["system"]["config"]["engine"]["ext"]["vulkan"]["framebuffer"]["msaa"].as(); uniforms->poissonSamples = shadowSamples; - /* - pod::Transform<> transform = controller.getComponent>(); - if ( controller.hasComponent() ) { - auto& camera = controller.getComponent(); - transform.position += camera.getTransform().position; - transform = uf::transform::reorient( transform ); - } - uniforms->position = transform.position; - */ - uniforms->fog.color = uf::vector::decode( metadata["light"]["fog"]["color"], uniforms->fog.color ); - uniforms->fog.color.w = metadata["light"]["fog"]["step scale"].as(); + uniforms->fog.color = metadata.fog.color; + uniforms->fog.color.w = metadata.fog.stepScale; - float timescale = metadata["light"]["fog"]["density"]["timescale"].as(); - uniforms->fog.offset = uf::vector::decode( metadata["light"]["fog"]["density"]["offset"], uniforms->fog.offset ) * uf::physics::time::current * timescale; - uniforms->fog.offset.w = metadata["light"]["fog"]["density"]["scale"].as(); + float timescale = metadata.fog.density.timescale; + uniforms->fog.offset = metadata.fog.density.offset * uf::physics::time::current * timescale; + uniforms->fog.offset.w = metadata.fog.density.scale; - uniforms->fog.densityThreshold = metadata["light"]["fog"]["density"]["threshold"].as(); - uniforms->fog.densityMultiplier = metadata["light"]["fog"]["density"]["multiplier"].as(); - uniforms->fog.absorbtion = metadata["light"]["fog"]["absorbtion"].as(); + uniforms->fog.densityThreshold = metadata.fog.density.threshold; + uniforms->fog.densityMultiplier = metadata.fog.density.multiplier; + uniforms->fog.absorbtion = metadata.fog.absorbtion; - uniforms->fog.range = uf::vector::decode( metadata["light"]["fog"]["range"], uniforms->fog.range ); + uniforms->fog.range = metadata.fog.range; - uniforms->mode.type.x = metadata["system"]["renderer"]["shader"]["mode"].as(); - uniforms->mode.type.y = metadata["system"]["renderer"]["shader"]["scalar"].as(); - - uniforms->mode.parameters = uf::vector::decode( metadata["system"]["renderer"]["shader"]["parameters"], uniforms->mode.parameters ); - if ( metadata["system"]["renderer"]["shader"]["parameters"][3].as() == "time" ) { + uniforms->mode.type.x = metadataJson["system"]["renderer"]["shader"]["mode"].as(); + uniforms->mode.type.y = metadataJson["system"]["renderer"]["shader"]["scalar"].as(); + uniforms->mode.parameters = uf::vector::decode( metadataJson["system"]["renderer"]["shader"]["parameters"], uniforms->mode.parameters ); + if ( metadataJson["system"]["renderer"]["shader"]["parameters"][3].as() == "time" ) { uniforms->mode.parameters.w = uf::physics::time::current; } @@ -501,16 +605,14 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image); graphic.material.textures.clear(); - // add noise texture graphic.material.textures.emplace_back().aliasTexture(this->getComponent()); graphic.material.textures.emplace_back().aliasTexture(this->getComponent()); - size_t updateThreshold = metadata["system"]["config"]["engine"]["scenes"]["lights"]["update threshold"].as(); - size_t maxLights = metadata["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(); + size_t& updateThreshold = metadata.light.updateThreshold; size_t textureSlot = 0; std::vector lights; - lights.reserve( maxLights ); + lights.reserve( metadata.max.lights ); std::vector materials; materials.reserve(maxTextures); @@ -523,64 +625,53 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { drawCalls.reserve(maxTextures); // add materials - { - for ( auto* entity : graphs ) { - auto& graph = *entity; + for ( auto* entity : graphs ) { + auto& graph = *entity; - drawCalls.emplace_back(pod::DrawCall::Storage{ - materials.size(), - graph.materials.size(), - textures.size(), - graph.textures.size() - }); - - for ( auto& material : graph.materials ) materials.emplace_back( material.storage ); - for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage ); + drawCalls.emplace_back(pod::DrawCall::Storage{ + materials.size(), + graph.materials.size(), + textures.size(), + graph.textures.size() + }); + + for ( auto& material : graph.materials ) materials.emplace_back( material.storage ); + for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage ); - for ( auto& texture : graph.textures ) { - if ( !texture.texture.device ) continue; + for ( auto& texture : graph.textures ) { + if ( !texture.texture.device ) continue; - graphic.material.textures.emplace_back().aliasTexture(texture.texture); - ++textureSlot; + graphic.material.textures.emplace_back().aliasTexture(texture.texture); + ++textureSlot; - if ( graph.atlas ) break; - } + if ( graph.atlas ) break; } - - uniforms->lengths.materials = std::min( materials.size(), maxTextures ); - uniforms->lengths.textures = std::min( textures.size(), maxTextures ); - uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures ); } + + uniforms->lengths.materials = std::min( materials.size(), maxTextures ); + uniforms->lengths.textures = std::min( textures.size(), maxTextures ); + uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures ); // add lighting - for ( size_t i = 0; i < entities.size() && lights.size() < maxLights; ++i ) { + for ( size_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) { auto& info = entities[i]; uf::Entity* entity = info.entity; auto& transform = entity->getComponent>(); - auto& metadata = entity->getComponent(); + auto& metadata = entity->getComponent(); auto& camera = entity->getComponent(); - metadata["system"]["renderer"]["rendered"] = true; + metadata.renderer.rendered = true; pod::Light::Storage light; light.position = info.position; - light.color = uf::vector::decode( metadata["light"]["color"], light.color ); - light.color.w = metadata["light"]["power"].as(); - - if ( metadata["light"]["type"].is() ) { - light.type = metadata["light"]["type"].as(); - } else if ( metadata["light"]["type"].is() ) { - std::string lightType = metadata["light"]["type"].as(); - if ( lightType == "point" ) light.type = 1; - else if ( lightType == "spot" ) light.type = 2; - } - + light.color = info.color; + light.type = info.type; light.mapIndex = -1; - light.depthBias = metadata["light"]["bias"]["shader"].as(); + light.depthBias = info.bias; if ( info.shadows && entity->hasComponent() ) { auto& renderMode = entity->getComponent(); - if ( metadata["system"]["renderer"]["mode"].as() == "in-range" && --updateThreshold > 0 ) { + if ( metadata.renderer.mode == "in-range" && --updateThreshold > 0 ) { renderMode.execute = true; } size_t view = 0; @@ -601,14 +692,9 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { } else { lights.emplace_back(light); } - uniforms->lengths.lights = std::min( lights.size(), maxLights ); } - /* - while ( textureSlot++ < maxTextures + 3 ) { - graphic.material.textures.emplace_back().aliasTexture(uf::renderer::Texture2D::empty); - } - */ { + uniforms->lengths.lights = std::min( lights.size(), metadata.max.lights ); bool shouldUpdate = graphic.material.textures.size() != previousTextures.size(); for ( size_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) { if ( previousTextures[i] != graphic.material.textures[i].image ) @@ -633,8 +719,8 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { shader.updateUniform( "UBO", uniform ); } } + #endif } -#endif } void ext::ExtSceneBehavior::render( uf::Object& self ) {} void ext::ExtSceneBehavior::destroy( uf::Object& self ) {} diff --git a/ext/behaviors/scene/behavior.h b/ext/behaviors/scene/behavior.h index 4197df0e..425e512b 100644 --- a/ext/behaviors/scene/behavior.h +++ b/ext/behaviors/scene/behavior.h @@ -4,14 +4,42 @@ #include #include #include +#include namespace ext { - class EXT_API ExtSceneBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace ExtSceneBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + struct Metadata { + struct { + size_t textures = 256; + size_t lights = 256; + } max; + struct { + bool enabled = true; + int shadowSamples = 4; + int shadowThreshold = 8; + size_t updateThreshold = 4; + pod::Vector4f ambient = {0,0,0,1}; + pod::Vector4f specular = {1,1,1,1}; + } light; + struct { + pod::Vector3f color = {1,1,1}; + float stepScale = 16.0f; + float absorbtion = 0.85f; + pod::Vector2f range = {}; + struct { + pod::Vector4f offset = {}; + float timescale = 0.5f; + float threshold = 0.5f; + float multiplier = 5.0f; + float scale = 50.0f; + } density; + } fog; + }; + } } \ No newline at end of file diff --git a/ext/behaviors/scene/collision/behavior.cpp b/ext/behaviors/scene/collision/behavior.cpp index 5716d63b..c02035f1 100644 --- a/ext/behaviors/scene/collision/behavior.cpp +++ b/ext/behaviors/scene/collision/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -319,4 +320,5 @@ void ext::SceneCollisionBehavior::destroy( uf::Object& self ){ } #endif } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/scene/collision/behavior.h b/ext/behaviors/scene/collision/behavior.h index 6de63e13..2dc2e406 100644 --- a/ext/behaviors/scene/collision/behavior.h +++ b/ext/behaviors/scene/collision/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API SceneCollisionBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace SceneCollisionBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/soundemitter/behavior.h b/ext/behaviors/soundemitter/behavior.h index f504ee82..7a65b411 100644 --- a/ext/behaviors/soundemitter/behavior.h +++ b/ext/behaviors/soundemitter/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API SoundEmitterBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace SoundEmitterBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/behaviors/sprite/behavior.cpp b/ext/behaviors/sprite/behavior.cpp index cc559cd6..2343ffc0 100644 --- a/ext/behaviors/sprite/behavior.cpp +++ b/ext/behaviors/sprite/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -110,4 +111,5 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { void ext::HousamoSpriteBehavior::tick( uf::Object& self ) {} void ext::HousamoSpriteBehavior::render( uf::Object& self ){} void ext::HousamoSpriteBehavior::destroy( uf::Object& self ){} -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/behaviors/sprite/behavior.h b/ext/behaviors/sprite/behavior.h index 8d8be2b1..3af8a796 100644 --- a/ext/behaviors/sprite/behavior.h +++ b/ext/behaviors/sprite/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API HousamoSpriteBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace HousamoSpriteBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index c778a802..6e489de4 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -46,11 +46,11 @@ namespace { #endif uf::Serializer defaultSettings; } - +/* ext::Gui::Gui(){ this->addBehavior(); } - +*/ std::vector ext::Gui::generateGlyphs( const std::string& _string ) { std::vector gs; #if UF_USE_FREETYPE @@ -844,6 +844,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } void ext::GuiBehavior::tick( uf::Object& self ) { uf::Serializer& metadata = this->getComponent(); +#if 0 if ( metadata["text settings"]["fade in speed"].is() && !metadata["system"]["faded in"].as() ) { float speed = metadata["text settings"]["fade in speed"].as(); float alpha = metadata["text settings"]["color"][3].as(); @@ -858,21 +859,7 @@ void ext::GuiBehavior::tick( uf::Object& self ) { metadata["text settings"]["color"][3] = alpha + speed; } } -/* - if ( this->hasComponent() && metadata["experimental"].as() ) { - auto& image = this->getComponent(); - auto& pixels = image.getPixels(); - size_t channels = image.getChannels(); - size_t len = pixels.size(); - uint8_t red = fmod( uf::physics::time::current * 64.0f, 255.0f ); - for ( size_t i = 0; i < len; i += channels ) { - pixels[i] = red; - } - auto& graphic = this->getComponent(); - auto& texture = graphic.material.textures.front(); - texture.update( image ); - } -*/ +#endif } template struct UniformDescriptor { diff --git a/ext/gui/behavior.h b/ext/gui/behavior.h index 1b186c32..f50efc23 100644 --- a/ext/gui/behavior.h +++ b/ext/gui/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API GuiBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace GuiBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/gui/gui.h b/ext/gui/gui.h index 425564af..5d700de0 100644 --- a/ext/gui/gui.h +++ b/ext/gui/gui.h @@ -23,8 +23,7 @@ namespace ext { class EXT_API Gui : public uf::Object { public: typedef uf::BaseMesh glyph_mesh_t; - - Gui(); + // Gui(); std::vector generateGlyphs( const std::string& = "" ); void load( const uf::Image& ); }; diff --git a/ext/gui/html/behavior.cpp b/ext/gui/html/behavior.cpp index 6f324c43..d7aca942 100644 --- a/ext/gui/html/behavior.cpp +++ b/ext/gui/html/behavior.cpp @@ -1,3 +1,4 @@ +#if UF_USE_ULTRALIGHT #include "behavior.h" #include "../gui.h" @@ -118,4 +119,5 @@ void ext::GuiHtmlBehavior::render( uf::Object& self ){ } void ext::GuiHtmlBehavior::destroy( uf::Object& self ){ } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/gui/html/behavior.h b/ext/gui/html/behavior.h index f8a79cef..a34d8644 100644 --- a/ext/gui/html/behavior.h +++ b/ext/gui/html/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API GuiHtmlBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace GuiHtmlBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index aa054ccb..fc956794 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -101,7 +101,6 @@ void ext::GuiManagerBehavior::initialize( uf::Object& self ) { }); } void ext::GuiManagerBehavior::tick( uf::Object& self ) { - } void ext::GuiManagerBehavior::render( uf::Object& self ){ auto& scene = uf::scene::getCurrentScene(); diff --git a/ext/gui/manager/behavior.h b/ext/gui/manager/behavior.h index 7e6b8a9f..63347044 100644 --- a/ext/gui/manager/behavior.h +++ b/ext/gui/manager/behavior.h @@ -6,12 +6,12 @@ #include namespace ext { - class EXT_API GuiManagerBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace GuiManagerBehavior { + UF_BEHAVIOR_DEFINE_TYPE; + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/main.cpp b/ext/main.cpp index 6d40a5ae..5353a620 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -137,17 +138,11 @@ namespace { } } -#if UF_ENV_DREAMCAST - #define UF_DEBUG_TRACE_MSG() UF_DEBUG_PRINT_MARKER(); malloc_stats(); -#else - #define UF_DEBUG_TRACE_MSG() -#endif - void EXT_API ext::load() { ext::config = getConfig(); } void EXT_API ext::initialize() { - UF_DEBUG_TRACE_MSG(); + /* Arguments */ { bool modified = false; auto& arguments = ::config["arguments"]; @@ -189,20 +184,9 @@ void EXT_API ext::initialize() { // #include "./inits/persistence.inl" } /* Testing scope */ { + + } - } - UF_DEBUG_TRACE_MSG(); -#if UF_USE_LUA - /* Lua */ { - ext::lua::main = ::config["engine"]["ext"]["lua"]["main"].as(); - for ( auto it = ::config["engine"]["ext"]["lua"]["modules"].begin(); it != ::config["engine"]["ext"]["lua"]["modules"].end(); ++it ) { - std::string key = it.key(); - ext::lua::modules[key] = ::config["engine"]["ext"]["lua"]["modules"][key].as(); - } - ext::lua::initialize(); - } -#endif - UF_DEBUG_TRACE_MSG(); /* Parse config */ { /* Set memory pool sizes */ { auto deduceSize = []( const ext::json::Value& value )->size_t{ @@ -249,7 +233,7 @@ void EXT_API ext::initialize() { } } } - UF_DEBUG_TRACE_MSG(); + if ( ::config["engine"]["limiters"]["framerate"].as() == "auto" && ::config["window"]["refresh rate"].is() ) { double scale = 1.0; size_t refreshRate = ::config["window"]["refresh rate"].as(); @@ -291,7 +275,10 @@ void EXT_API ext::initialize() { ::config["engine"]["threads"]["workers"] = threads; uf::iostream << "Using " << threads << " worker threads" << "\n"; } - UF_DEBUG_TRACE_MSG(); + if ( ::config["engine"]["scenes"]["use graph"].is() ) { + uf::scene::useGraph = ::config["engine"]["scenes"]["use graph"].as(); + } + #if UF_USE_BULLET // set bullet parameters ext::bullet::debugDrawEnabled = ::config["engine"]["ext"]["bullet"]["debug draw"]["enabled"].as(); @@ -383,7 +370,6 @@ void EXT_API ext::initialize() { uf::renderer::settings::experimental::deferredAliasOutputToSwapchain = ::config["engine"]["ext"][RENDERER]["experimental"]["deferred alias output to swapchain"].as(); uf::renderer::settings::experimental::vsync = ::config["engine"]["ext"][RENDERER]["experimental"]["vsync"].as(); uf::renderer::settings::experimental::hdr = ::config["engine"]["ext"][RENDERER]["experimental"]["hdr"].as(); - #endif #define JSON_TO_VKFORMAT( key ) if ( ::config["engine"]["ext"][RENDERER]["formats"][#key].is() ) {\ std::string format = ::config["engine"]["ext"][RENDERER]["formats"][#key].as();\ @@ -396,13 +382,28 @@ void EXT_API ext::initialize() { JSON_TO_VKFORMAT(normal); JSON_TO_VKFORMAT(position); } - UF_DEBUG_TRACE_MSG(); + + /* Init controllers */ { + spec::controller::initialize(); + } + +#if UF_USE_LUA + /* Lua */ { + ext::lua::main = ::config["engine"]["ext"]["lua"]["main"].as(); + for ( auto it = ::config["engine"]["ext"]["lua"]["modules"].begin(); it != ::config["engine"]["ext"]["lua"]["modules"].end(); ++it ) { + std::string key = it.key(); + ext::lua::modules[key] = ::config["engine"]["ext"]["lua"]["modules"][key].as(); + } + ext::lua::initialize(); + } +#endif + #if UF_USE_BULLET /* Bullet */ { ext::bullet::initialize(); } #endif - UF_DEBUG_TRACE_MSG(); + #if UF_USE_OPENVR ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].as(); ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].as(); @@ -421,17 +422,15 @@ void EXT_API ext::initialize() { } #endif } - UF_DEBUG_TRACE_MSG(); + /* Create initial scene (kludge) */ { uf::Scene& scene = uf::instantiator::instantiate(); //new uf::Scene; uf::scene::scenes.push_back(&scene); auto& metadata = scene.getComponent(); metadata["system"]["config"] = ::config; } - UF_DEBUG_TRACE_MSG(); + /* Initialize Vulkan */ { - // uf::renderer::width = ::config["window"]["size"]["x"].as(); - // uf::renderer::height = ::config["window"]["size"]["y"].as(); #if UF_USE_VULKAN // setup render mode if ( ::config["engine"]["render modes"]["gui"].as() ) { @@ -447,7 +446,7 @@ void EXT_API ext::initialize() { } } #endif - UF_DEBUG_TRACE_MSG(); + #if UF_USE_OPENVR if ( ext::openvr::enabled ) { ext::openvr::initialize(); @@ -507,10 +506,10 @@ void EXT_API ext::initialize() { }); } #endif - UF_DEBUG_TRACE_MSG(); + uf::renderer::initialize(); } - UF_DEBUG_TRACE_MSG(); + /* */ { pod::Thread& threadMain = uf::thread::has("Main") ? uf::thread::get("Main") : uf::thread::create( "Main", false ); pod::Thread& threadPhysics = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true ); @@ -521,17 +520,20 @@ void EXT_API ext::initialize() { } #endif #if UF_USE_ULTRALIGHT - /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { - if ( ::config["engine"]["ext"]["ultralight"]["scale"].is() ) { - ext::ultralight::scale = ::config["engine"]["ext"]["ultralight"]["scale"].as(); + { + auto& ultralight = ::config["engine"]["ext"]["ultralight"]; + /* Ultralight-UX */ if ( ultralight["enabled"].as() ) { + if ( ultralight["scale"].is() ) { + ext::ultralight::scale = ultralight["scale"].as(); + } + if ( ultralight["log"].is() ) { + ext::ultralight::log = ultralight["log"].as(); + } + ext::ultralight::initialize(); } - if ( ::config["engine"]["ext"]["ultralight"]["log"].is() ) { - ext::ultralight::log = ::config["engine"]["ext"]["ultralight"]["log"].as(); - } - ext::ultralight::initialize(); } #endif - UF_DEBUG_TRACE_MSG(); + // #define DEBUG_PRINT() std::cout << __FILE__ << ":" __FUNCTION__ << "@" << __LINE__ << std::endl; /* Add hooks */ { uf::hooks.addHook( "game:Scene.Load", [&](ext::json::Value& json){ @@ -564,7 +566,7 @@ void EXT_API ext::initialize() { ext::ready = false; }); } - UF_DEBUG_TRACE_MSG(); + /* Initialize root scene*/ { uf::Serializer payload; payload["scene"] = ::config["engine"]["scenes"]["start"]; @@ -582,8 +584,8 @@ void EXT_API ext::initialize() { assetLoader.processQueue(); return 0;}, false ); } - UF_DEBUG_TRACE_MSG(); } + void EXT_API ext::tick() { /* Timer */ { times.prevTime = times.curTime; @@ -591,11 +593,15 @@ void EXT_API ext::tick() { times.deltaTime = times.curTime - times.prevTime; } + /* Tick controllers */ { + spec::controller::tick(); + } #if UF_USE_OPENVR /* OpenVR */ if ( ext::openvr::context ) { ext::openvr::tick(); } #endif +#if 0 /* Print Entity Information */ { TIMER(1, uf::Window::isKeyPressed("P") && ) { // uf::iostream << uf::renderer::allocatorStats() << "\n"; @@ -637,38 +643,44 @@ void EXT_API ext::tick() { } } } - - auto& bulletThread = uf::thread::get("Physics"); +#endif /* Update physics timer */ { uf::physics::tick(); } - #if UF_USE_BULLET + auto& bulletThread = uf::thread::get("Physics"); /* Update bullet */ { + #if 1 + //UF_TIMER_TRACE_INIT(); + ext::bullet::tick(); + //UF_TIMER_TRACE("[TICK] BULLET"); + #else if ( ::config["engine"]["ext"]["bullet"]["multithreaded"].as() ) { uf::thread::add( bulletThread, [&]() -> int { ext::bullet::tick(); return 0;}, true ); } else { ext::bullet::tick(); } + #endif } #endif + //UF_TIMER_TRACE("ticking physics"); /* Update entities */ { uf::scene::tick(); } - + //UF_TIMER_TRACE("ticking scene"); /* Tick Main Thread Queue */ { pod::Thread& thread = uf::thread::get("Main"); uf::thread::process( thread ); } - - /* Garbage collection */ if ( ::config["engine"]["debug"]["garbage collection"]["enabled"].as() ) { - double every = ::config["engine"]["debug"]["garbage collection"]["every"].as(); - uint8_t mode = ::config["engine"]["debug"]["garbage collection"]["mode"].as(); - bool announce = ::config["engine"]["debug"]["garbage collection"]["announce"].as(); - TIMER( every ) { - size_t collected = uf::instantiator::collect( mode ); - if ( announce && collected > 0 ) { - uf::iostream << "GC collected " << (int) collected << " unused entities" << "\n"; + { + auto& gc = ::config["engine"]["debug"]["garbage collection"]; + /* Garbage collection */ if ( gc["enabled"].as() ) { + double every = gc["every"].as(); + uint8_t mode = gc["mode"].as(); + bool announce = gc["announce"].as(); + TIMER( every ) { + size_t collected = uf::instantiator::collect( mode ); + if ( announce && collected > 0 ) UF_DEBUG_MSG("GC collected " << (int) collected << " unused entities"); } } } @@ -678,23 +690,29 @@ void EXT_API ext::tick() { } #endif /* Update vulkan */ { + //UF_TIMER_TRACE_INIT(); uf::renderer::tick(); + //UF_TIMER_TRACE("[TICK] RENDERER"); } + //UF_TIMER_TRACE("ticking renderer"); #if UF_USE_DISCORD /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enable"].as() ) { ext::discord::tick(); } #endif - /* FPS Print */ if ( ::config["engine"]["debug"]["framerate"]["print"].as() ) { - ++::times.frames; - double every = ::config["engine"]["debug"]["framerate"]["every"].as(); - TIMER( every ) { -// uf::iostream << "Framerate: " << (1.0/times.deltaTime) << " FPS | Frametime: " << (times.deltaTime * 1000) << "ms" << "\n"; - uf::iostream << "System: " << (every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time << "\n"; - ::times.frames = 0; + { + auto& fps = ::config["engine"]["debug"]["framerate"]; + /* FPS Print */ if ( fps["print"].as() ) { + ++::times.frames; + double every = fps["every"].as(); + TIMER( every ) { + // UF_DEBUG_MSG("Framerate: " << (1.0/times.deltaTime) << " FPS | Frametime: " << (times.deltaTime * 1000) << "ms"); + UF_DEBUG_MSG("System: " << (every * 1000.0/::times.frames) << " ms/frame | Time: " << time << " | Frames: " << ::times.frames << " | FPS: " << ::times.frames / time); + ::times.frames = 0; + } } } - +#if 0 /* Frame limiter of sorts I guess */ if ( false ) if ( ::times.limiter > 0 ) { static uf::Timer timer(false); if ( !timer.running() ) timer.start(); @@ -708,13 +726,16 @@ void EXT_API ext::tick() { } timer.reset(); } - +#endif +#if 0 if ( ::config["engine"]["ext"]["bullet"]["multithreaded"].as() ) { uf::thread::wait( bulletThread ); } +#endif + //UF_TIMER_TRACE("ticking"); } void EXT_API ext::render() { - + //UF_TIMER_TRACE_INIT(); #if UF_USE_ULTRALIGHT /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { ext::ultralight::render(); @@ -734,11 +755,15 @@ void EXT_API ext::render() { ext::openvr::submit(); } #endif + //UF_TIMER_TRACE("[RENDER]"); } void EXT_API ext::terminate() { /* Kill threads */ { uf::thread::terminate(); } + /* Terminate controllers */ { + spec::controller::terminate(); + } #if UF_USE_BULLET /* Kill bullet */ { ext::bullet::terminate(); diff --git a/ext/scenes/raytrace/behavior.cpp b/ext/scenes/raytrace/behavior.cpp index 6994b39d..2b78667f 100644 --- a/ext/scenes/raytrace/behavior.cpp +++ b/ext/scenes/raytrace/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -208,4 +209,5 @@ void ext::RayTracingSceneBehavior::destroy( uf::Object& self ) { uf::renderer::removeRenderMode( &renderMode, false ); } } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/scenes/raytrace/behavior.h b/ext/scenes/raytrace/behavior.h index d020acb0..a7ad6bba 100644 --- a/ext/scenes/raytrace/behavior.h +++ b/ext/scenes/raytrace/behavior.h @@ -6,12 +6,11 @@ #include namespace ext { - class EXT_API RayTracingSceneBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace RayTracingSceneBehavior { + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/scenes/worldscape/behavior.cpp b/ext/scenes/worldscape/behavior.cpp index 7093321e..70eed296 100644 --- a/ext/scenes/worldscape/behavior.cpp +++ b/ext/scenes/worldscape/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include @@ -119,4 +120,5 @@ void ext::WorldScapeSceneBehavior::tick( uf::Object& self ) { } void ext::WorldScapeSceneBehavior::render( uf::Object& self ){} void ext::WorldScapeSceneBehavior::destroy( uf::Object& self ){} -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/behavior.h b/ext/scenes/worldscape/behavior.h index 5fbbbf23..5380ac7a 100644 --- a/ext/scenes/worldscape/behavior.h +++ b/ext/scenes/worldscape/behavior.h @@ -6,12 +6,11 @@ #include namespace ext { - class EXT_API WorldScapeSceneBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace WorldScapeSceneBehavior { + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/scenes/worldscape/gui/battle.cpp b/ext/scenes/worldscape/gui/battle.cpp index 963bb666..851ad7a5 100644 --- a/ext/scenes/worldscape/gui/battle.cpp +++ b/ext/scenes/worldscape/gui/battle.cpp @@ -1,3 +1,4 @@ +#if 0 #include "battle.h" #include @@ -1520,4 +1521,5 @@ void ext::GuiBattle::render() { void ext::GuiBattle::destroy() { ext::Gui::destroy(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/gui/dialogue.cpp b/ext/scenes/worldscape/gui/dialogue.cpp index 0f335c17..3431b242 100644 --- a/ext/scenes/worldscape/gui/dialogue.cpp +++ b/ext/scenes/worldscape/gui/dialogue.cpp @@ -1,3 +1,4 @@ +#if 0 #include "dialogue.h" #include @@ -390,4 +391,5 @@ void ext::GuiDialogue::render() { void ext::GuiDialogue::destroy() { ext::Gui::destroy(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/housamo/battle.cpp b/ext/scenes/worldscape/housamo/battle.cpp index 0e185f0c..b124249d 100644 --- a/ext/scenes/worldscape/housamo/battle.cpp +++ b/ext/scenes/worldscape/housamo/battle.cpp @@ -1,3 +1,4 @@ +#if 0 #include "battle.h" #include ".h" @@ -1552,4 +1553,5 @@ void ext::HousamoBattle::destroy() { } void ext::HousamoBattle::render() { uf::Object::render(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/housamo/dialogue.cpp b/ext/scenes/worldscape/housamo/dialogue.cpp index 8da01c43..36b985b5 100644 --- a/ext/scenes/worldscape/housamo/dialogue.cpp +++ b/ext/scenes/worldscape/housamo/dialogue.cpp @@ -1,3 +1,4 @@ +#if 0 #include "dialogue.h" #include ".h" @@ -269,4 +270,5 @@ void ext::DialogueManager::destroy() { } void ext::DialogueManager::render() { uf::Object::render(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/housamo/housamo.cpp b/ext/scenes/worldscape/housamo/housamo.cpp index bf1487f0..ec7daf7b 100644 --- a/ext/scenes/worldscape/housamo/housamo.cpp +++ b/ext/scenes/worldscape/housamo/housamo.cpp @@ -1,3 +1,4 @@ +#if 0 #include ".h" #include @@ -155,4 +156,5 @@ void ext::Housamo::render() { } void ext::Housamo::destroy() { uf::Object::destroy(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/behavior.cpp b/ext/scenes/worldscape/terrain/behavior.cpp index a14a3228..0d32f6af 100644 --- a/ext/scenes/worldscape/terrain/behavior.cpp +++ b/ext/scenes/worldscape/terrain/behavior.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include "terrain.h" #include "generator.h" @@ -276,4 +277,5 @@ void ext::TerrainBehavior::render( uf::Object& self ){ } void ext::TerrainBehavior::destroy( uf::Object& self ){} #undef this -UF_BEHAVIOR_ENTITY_CPP_END(Terrain) \ No newline at end of file +UF_BEHAVIOR_ENTITY_CPP_END(Terrain) +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/behavior.h b/ext/scenes/worldscape/terrain/behavior.h index 7cc76cab..59009bee 100644 --- a/ext/scenes/worldscape/terrain/behavior.h +++ b/ext/scenes/worldscape/terrain/behavior.h @@ -6,12 +6,11 @@ #include namespace ext { - class EXT_API TerrainBehavior { - public: - static void attach( uf::Entity& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace TerrainBehavior { + void attach( uf::Entity& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/generator.cpp b/ext/scenes/worldscape/terrain/generator.cpp index eaaa2ba4..016e79a4 100644 --- a/ext/scenes/worldscape/terrain/generator.cpp +++ b/ext/scenes/worldscape/terrain/generator.cpp @@ -1,3 +1,4 @@ +#if 0 #include "generator.h" #include "../../../ext.h" @@ -1436,4 +1437,5 @@ void ext::TerrainGenerator::rasterize( std::vector #include "Maze.h" @@ -435,4 +436,5 @@ void ext::Maze::print(){ } std::cout << std::endl; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/region.cpp b/ext/scenes/worldscape/terrain/region.cpp index 427d011b..3b99aa09 100644 --- a/ext/scenes/worldscape/terrain/region.cpp +++ b/ext/scenes/worldscape/terrain/region.cpp @@ -1,3 +1,4 @@ +#if 0 #include "region.h" #include "../../../ext.h" @@ -656,4 +657,5 @@ void ext::RegionBehavior::destroy( uf::Object& self ){ mutexPointer = NULL; } } -#undef this \ No newline at end of file +#undef this +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/region.h b/ext/scenes/worldscape/terrain/region.h index f0167975..77cf7123 100644 --- a/ext/scenes/worldscape/terrain/region.h +++ b/ext/scenes/worldscape/terrain/region.h @@ -6,12 +6,11 @@ #include namespace ext { - class EXT_API RegionBehavior { - public: - static void attach( uf::Object& ); - static void initialize( uf::Object& ); - static void tick( uf::Object& ); - static void render( uf::Object& ); - static void destroy( uf::Object& ); - }; + namespace RegionBehavior { + void attach( uf::Object& ); + void initialize( uf::Object& ); + void tick( uf::Object& ); + void render( uf::Object& ); + void destroy( uf::Object& ); + } } \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/terrain.cpp b/ext/scenes/worldscape/terrain/terrain.cpp index 9c5c7827..fe27d085 100644 --- a/ext/scenes/worldscape/terrain/terrain.cpp +++ b/ext/scenes/worldscape/terrain/terrain.cpp @@ -1,3 +1,4 @@ +#if 0 #include "behavior.h" #include "terrain.h" #include "generator.h" @@ -224,4 +225,5 @@ void ext::Terrain::degenerate( const pod::Vector3i& position ) { region->destroy(); delete region; ::region_table.erase( position ); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/ext/scenes/worldscape/terrain/voxel.cpp b/ext/scenes/worldscape/terrain/voxel.cpp index 16f42423..e98649bb 100644 --- a/ext/scenes/worldscape/terrain/voxel.cpp +++ b/ext/scenes/worldscape/terrain/voxel.cpp @@ -1,3 +1,4 @@ +#if 0 #include "voxel.h" #include "../../../ext.h" @@ -499,4 +500,5 @@ ext::TerrainVoxel ext::TerrainVoxel::atlas( ext::TerrainVoxel::uid_t uid ) { if ( it->uid() == uid ) return *it; } return base; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/makefiles/dreamcast.gcc.make b/makefiles/dreamcast.gcc.make index d54560c5..a896808e 100644 --- a/makefiles/dreamcast.gcc.make +++ b/makefiles/dreamcast.gcc.make @@ -1,5 +1,7 @@ -ARCH = dreamcast -PREFIX = gcc -CC = $(KOS_CCPLUS) -FLAGS = -Wno-attributes -Wno-conversion-null -fdiagnostics-color=always -DUF_DISABLE_ALIGNAS -std=gnu++17 -TARGET_EXTENSION = elf \ No newline at end of file +ARCH = dreamcast +PREFIX = gcc +CC = $(KOS_CCPLUS) +TARGET_EXTENSION = elf +FLAGS += $(KOS_CPPFLAGS) -Wno-attributes -Wno-conversion-null -fdiagnostics-color=always -std=c++17 -O3 -ffast-math -frtti -DUF_NO_EXCEPTIONS +INCS += $(KOS_INC_PATHS) -I/opt/dreamcast/sh-elf/sh-elf/include +LIBS += $(KOS_LIB_PATHS) -L/opt/dreamcast/sh-elf/sh-elf/lib \ No newline at end of file diff --git a/makefiles/win64.clang.make b/makefiles/win64.clang.make index 193cfe3c..ea31acc3 100644 --- a/makefiles/win64.clang.make +++ b/makefiles/win64.clang.make @@ -1,4 +1,4 @@ ARCH = win64 PREFIX = clang CC = clang++ -FLAGS = -Wno-unknown-pragmas -std=c++17 -g -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder-ctor -Wno-ignored-attributes -Wno-c++11-narrowing -fcolor-diagnostics \ No newline at end of file +FLAGS += -Wno-unknown-pragmas -std=c++17 -g -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder-ctor -Wno-ignored-attributes -Wno-c++11-narrowing -fcolor-diagnostics \ No newline at end of file diff --git a/makefiles/win64.gcc.make b/makefiles/win64.gcc.make index d21a51b1..10e8f2f8 100644 --- a/makefiles/win64.gcc.make +++ b/makefiles/win64.gcc.make @@ -1,4 +1,4 @@ ARCH = win64 PREFIX = gcc CC = /opt/mingw-w64/x86_64-7.2.0-posix-seh-rt_v5-rev1/mingw64/bin/g++ -FLAGS = -Wno-unknown-pragmas -std=c++17 -g -Og -fdiagnostics-color=always -Wall -Wno-conversion-null -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file +FLAGS += -Wno-unknown-pragmas -std=c++17 -g -Og -fdiagnostics-color=always -Wall -Wno-conversion-null -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation \ No newline at end of file diff --git a/makefiles/win64.gcc10.make b/makefiles/win64.gcc10.make index 5a75b72d..d6c27b1e 100644 --- a/makefiles/win64.gcc10.make +++ b/makefiles/win64.gcc10.make @@ -1,5 +1,5 @@ ARCH = win64 PREFIX = gcc10 CC = g++ -FLAGS = -Wno-unknown-pragmas -std=c++17 -g -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation +FLAGS += -Wno-unknown-pragmas -std=c++17 -g -fdiagnostics-color=always -Wall -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation #-DUF_DISABLE_ALIGNAS -O2 \ No newline at end of file