diff --git a/Makefile b/Makefile index 4cdfc8d2..517279b7 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,13 @@ +ARCH = win64 PREFIX = gcc -include makefiles/win64.$(PREFIX).make +TARGET_NAME = program +TARGET_EXTENSION = exe +TARGET_LIB_EXTENSION = dll + +include makefiles/$(ARCH).$(PREFIX).make .PHONY: $(ARCH)-$(PREFIX) -TARGET_NAME += program BIN_DIR += ./bin ENGINE_SRC_DIR += ./engine/src @@ -25,11 +29,16 @@ GLSL_VALIDATOR += $(VULKAN_SDK_PATH)/Bin32/glslangValidator # Base Engine's DLL INC_DIR += $(ENGINE_INC_DIR)/$(ARCH)/$(PREFIX) DEPS += -REQ_DEPS += win32 opengl json:nlohmann png openal ogg freetype ncurses curl openvr luajit ultralight-ux bullet meshoptimizer # discord -ifneq (,$(findstring win32,$(REQ_DEPS))) +ifneq (,$(findstring win64,$(ARCH))) + REQ_DEPS += vulkan json:nlohmann png openal ogg freetype ncurses curl openvr luajit ultralight-ux bullet meshoptimizer # discord FLAGS += DEPS += -lgdi32 +else ifneq (,$(findstring dreamcast,$(ARCH))) + REQ_DEPS += opengl json:nlohmann #freetype ogg openal meshoptimizer # 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 endif ifneq (,$(findstring vulkan,$(REQ_DEPS))) FLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DUF_USE_VULKAN @@ -37,14 +46,18 @@ ifneq (,$(findstring vulkan,$(REQ_DEPS))) endif ifneq (,$(findstring opengl,$(REQ_DEPS))) FLAGS += -DUF_USE_OPENGL -DUF_USE_GLEW - DEPS += -lglew32 -lopengl32 -lglu32 + ifneq (,$(findstring dreamcast,$(ARCH))) + DEPS += -lGLdc + else + DEPS += -lglew32 -lopengl32 -lglu32 + endif endif ifneq (,$(findstring json,$(REQ_DEPS))) FLAGS += -DUF_USE_JSON DEPS += -ifneq (,$(findstring nlohmann,$(REQ_DEPS))) - FLAGS += -DUF_JSON_USE_NLOHMANN -endif + ifneq (,$(findstring nlohmann,$(REQ_DEPS))) + FLAGS += -DUF_JSON_USE_NLOHMANN + endif endif ifneq (,$(findstring png,$(REQ_DEPS))) FLAGS += -DUF_USE_PNG @@ -52,7 +65,12 @@ ifneq (,$(findstring png,$(REQ_DEPS))) endif ifneq (,$(findstring openal,$(REQ_DEPS))) FLAGS += -DUF_USE_OPENAL - DEPS += -lopenal -lalut + ifneq (,$(findstring dreamcast,$(ARCH))) + DEPS += -lAL + else + FLAGS += -DUF_USE_ALUT + DEPS += -lopenal -lalut + endif endif ifneq (,$(findstring ogg,$(REQ_DEPS))) FLAGS += -DUF_USE_VORBIS @@ -78,9 +96,15 @@ ifneq (,$(findstring openvr,$(REQ_DEPS))) FLAGS += -DUF_USE_OPENVR -DUSE_OPENVR_MINGW DEPS += -lopenvr_api endif -ifneq (,$(findstring luajit,$(REQ_DEPS))) - FLAGS += -DUF_USE_LUA -DUF_USE_LUAJIT - DEPS += -lluajit-5.1 +ifneq (,$(findstring lua,$(REQ_DEPS))) + FLAGS += -DUF_USE_LUA + ifneq (,$(findstring luajit,$(REQ_DEPS))) + FLAGS += -DUF_USE_LUAJIT + DEPS += -lluajit-5.1 + INCS += -I/mingw64/include/luajit-2.1 + else + DEPS += -llua-5.1 + endif endif ifneq (,$(findstring ultralight-ux,$(REQ_DEPS))) FLAGS += -DUF_USE_ULTRALIGHT_UX @@ -88,8 +112,12 @@ ifneq (,$(findstring ultralight-ux,$(REQ_DEPS))) endif ifneq (,$(findstring bullet,$(REQ_DEPS))) FLAGS += -DUF_USE_BULLET - DEPS += -lBulletDynamics -lBulletCollision -lLinearMath - # -lBullet3Collision -lLinearMath -lBullet3Common -lBullet3Dynamics -lGIMPACTUtils + ifneq (,$(findstring dreamcast,$(ARCH))) + DEPS += -lbulletdynamics -lbulletcollision -lbulletmath + else + DEPS += -lBulletDynamics -lBulletCollision -lLinearMath + INCS += -I$(ENGINE_INC_DIR)/bullet/ + endif endif ifneq (,$(findstring simd,$(REQ_DEPS))) FLAGS += -DUF_USE_SIMD #-march=native @@ -105,14 +133,14 @@ LINKS += $(UF_LIBS) $(EXT_LIBS) $(DEPS) #-Wl,-subsystem,windows LIB_DIR += $(ENGINE_LIB_DIR)/$(ARCH) -INCS += -I$(ENGINE_INC_DIR) -I$(INC_DIR) -I$(VULKAN_SDK_PATH)/include -I/mingw64/include -I/mingw64/include/luajit-2.1 -I$(ENGINE_INC_DIR)/bullet/ +INCS += -I$(ENGINE_INC_DIR) -I$(INC_DIR) -I$(VULKAN_SDK_PATH)/include -I/mingw64/include LIBS += -L$(ENGINE_LIB_DIR) -L$(LIB_DIR) -L$(LIB_DIR)/$(PREFIX) -L$(VULKAN_SDK_PATH)/Lib SRCS_DLL += $(wildcard $(ENGINE_SRC_DIR)/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(ENGINE_SRC_DIR)/*/*/*/*/*.cpp) OBJS_DLL += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_DLL)) BASE_DLL += lib$(LIB_NAME) -IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll.a -EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll +IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a +EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_DLL).$(TARGET_LIB_EXTENSION) # External Engine's DLL EXT_INC_DIR += $(INC_DIR) EXT_LB_FLAGS += $(LIB_DIR) @@ -127,16 +155,51 @@ EXT_LIBS += -L$(ENGINE_LIB_DIR) -L$(EXT_LIB_DIR) -L$(EXT_LIB_DIR)/$(PREFIX) SRCS_EXT_DLL += $(wildcard $(EXT_SRC_DIR)/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*.cpp) $(wildcard $(EXT_SRC_DIR)/*/*/*/*/*.cpp) OBJS_EXT_DLL += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_EXT_DLL)) BASE_EXT_DLL += lib$(EXT_LIB_NAME) -EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll.a -EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll +EXT_IM_DLL += $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a +EXT_EX_DLL += $(BIN_DIR)/exe/lib/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION) # Client EXE SRCS += $(wildcard $(CLIENT_SRC_DIR)/*.cpp) $(wildcard $(CLIENT_SRC_DIR)/*/*.cpp) OBJS += $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS)) -TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX).exe +TARGET += $(BIN_DIR)/exe/$(TARGET_NAME).$(PREFIX).$(TARGET_EXTENSION) # Shaders SRCS_SHADERS += $(wildcard bin/data/shaders/*.glsl) 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 +#OBJS = $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_DLL)) $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_EXT_DLL)) $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS)) +OBJS = $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS_DLL)) $(patsubst %.cpp,%.$(ARCH).$(PREFIX).o,$(SRCS)) +DEPS += -lkallisti -lc -lm -lgcc -lstdc++ -lGLdc -lAL # -l$(LIB_NAME) -l$(EXT_LIB_NAME) + +%.$(ARCH).$(PREFIX).o: %.cpp + $(CC) $(FLAGS) $(INCS) -c $< -o $@ + +$(EX_DLL): FLAGS += -DUF_EXPORTS -DJSON_DLL_BUILD +$(EX_DLL): $(OBJS_DLL) + $(KOS_AR) cru $@ $^ + $(KOS_RANLIB) $@ + cp $@ $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).a + +$(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS -DJSON_DLL_BUILD +$(EXT_EX_DLL): $(OBJS_EXT_DLL) + $(KOS_AR) cru $@ $^ + $(KOS_RANLIB) $@ + cp $@ $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).a + +./bin/dreamcast/romdisk.img: + $(KOS_GENROMFS) -f ./bin/dreamcast/romdisk.img -d ./bin/dreamcast/romdisk/ -v + +./bin/dreamcast/romdisk.o: ./bin/dreamcast/romdisk.img + $(KOS_BASE)/utils/bin2o/bin2o ./bin/dreamcast/romdisk.img romdisk ./bin/dreamcast/romdisk.o + +$(TARGET): $(OBJS) ./bin/dreamcast/romdisk.o + $(CC) -O2 -fomit-frame-pointer -ml -m4-single-only -ffunction-sections -fdata-sections $(KOS_INC_PATHS) $(INCS) -D_arch_dreamcast -D_arch_sub_pristine -Wall -g -fno-builtin -ml -m4-single-only -Wl,-Ttext=0x8c010000 -Wl,--gc-sections -T/opt/dreamcast/kos/utils/ldscripts/shlelf.xc -nodefaultlibs $(KOS_LIB_PATHS) $(LIBS) -o $(TARGET) $(OBJS) ./bin/dreamcast/romdisk.o -Wl,--start-group $(DEPS) -Wl,--end-group + +./bin/dreamcast/$(TARGET_NAME).cdi: $(TARGET) + cd ./bin/dreamcast/; ./elf2cdi.sh $(TARGET_NAME) + +else $(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) $(TARGET_SHADERS) %.$(ARCH).$(PREFIX).o: %.cpp @@ -145,15 +208,16 @@ $(ARCH): $(EX_DLL) $(EXT_EX_DLL) $(TARGET) $(TARGET_SHADERS) $(EX_DLL): FLAGS += -DUF_EXPORTS -DJSON_DLL_BUILD $(EX_DLL): $(OBJS_DLL) $(CC) -shared -o $(EX_DLL) -g -Wl,--out-implib=$(IM_DLL) $(OBJS_DLL) $(LIBS) $(INCS) $(LINKS) - cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).dll.a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).a + cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_DLL).a $(EXT_EX_DLL): FLAGS += -DEXT_EXPORTS -DJSON_DLL_BUILD $(EXT_EX_DLL): $(OBJS_EXT_DLL) $(CC) -shared -o $(EXT_EX_DLL) -g -Wl,--out-implib=$(EXT_IM_DLL) $(OBJS_EXT_DLL) $(EXT_LIBS) $(EXT_INCS) $(EXT_LINKS) - cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).dll.a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).a + cp $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).$(TARGET_LIB_EXTENSION).a $(ENGINE_LIB_DIR)/$(ARCH)/$(PREFIX)/$(BASE_EXT_DLL).a $(TARGET): $(OBJS) $(CC) $(FLAGS) $(OBJS) $(LIBS) $(INCS) $(LINKS) -l$(LIB_NAME) -l$(EXT_LIB_NAME) -o $(TARGET) +endif %.spv: %.glsl $(GLSL_VALIDATOR) -V $< -o $@ diff --git a/bin/data/shaders/old/dither/base.dither16.frag.glsl b/bin/data/shaders/old/dither/base.dither16.frag.glsl deleted file mode 100644 index ec3c7970..00000000 --- a/bin/data/shaders/old/dither/base.dither16.frag.glsl +++ /dev/null @@ -1,294 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in vec3 inPositionEye; -layout (location = 2) in vec3 inNormalEye; -layout (location = 3) in vec4 inColor; -layout (location = 0) out vec4 outFragColor; - -void fog( inout vec3 i ) { - vec3 color = vec3( 0, 0, 0 ); - float inner = 8, outer = 64; - float distance = length(-inPositionEye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); - - i = mix(i.rgb, color, factor); -} - -void phong( inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = vec3(0.4, 0.4, 1.0); // light color - vec3 La = vec3(0.1, 0.1, 0.1); - - vec3 Ks = vec3(0.6, 0.6, 0.9); // material specular - vec3 Kd = i; // material diffuse - vec3 Ka = vec3(0.7, 0.7, 0.7); - - float Kexp = 1000.0; - - vec3 dist_light_eye = vec3(0, 0, 0) - inPositionEye; - vec3 dir_light_eye = normalize(dist_light_eye); - float d_dot = max(dot( dir_light_eye, inNormalEye ), 0.0); - - vec3 reflection_eye = reflect( -dir_light_eye, inNormalEye ); - vec3 surface_eye = normalize(-inPositionEye); - float s_dot = max(dot( reflection_eye, surface_eye ), 0.0); - float s_factor = pow( s_dot, Kexp ); - - vec3 Ia = La * Ka; - vec3 Id = Ld * Kd * d_dot; - vec3 Is = Ls * Ks * s_factor; - i = Is + Id + Ia; -} - -const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255, - 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127, - 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223, - 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95, - 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247, - 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119, - 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215, - 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87, - 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253, - 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125, - 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221, - 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93, - 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245, - 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117, - 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213, - 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85); - -float indexValue16x16() { - int x = int(mod(gl_FragCoord.x, 16)); - int y = int(mod(gl_FragCoord.y, 16)); - return indexMatrix16x16[(x + y * 16)] / 256.0; -} -/* -const int paletteSize = 16; -const vec3 palette[paletteSize] = vec3[]( - vec3( 0x00/255.0, 0x00/255.0, 0x18/255.0), - vec3( 0x60/255.0, 0x60/255.0, 0x78/255.0), - vec3( 0x00/255.0, 0x18/255.0, 0x30/255.0), - vec3( 0x18/255.0, 0x18/255.0, 0x30/255.0), - vec3( 0x30/255.0, 0x30/255.0, 0x48/255.0), - vec3( 0x30/255.0, 0x30/255.0, 0x30/255.0), - vec3( 0x18/255.0, 0x18/255.0, 0x48/255.0), - vec3( 0x00/255.0, 0x00/255.0, 0x00/255.0), - vec3( 0x18/255.0, 0x00/255.0, 0x00/255.0), - vec3( 0x48/255.0, 0x48/255.0, 0x60/255.0), - vec3( 0x30/255.0, 0x00/255.0, 0x18/255.0), - vec3( 0x00/255.0, 0x18/255.0, 0x48/255.0), - vec3( 0x90/255.0, 0x90/255.0, 0xa8/255.0), - vec3( 0x48/255.0, 0x18/255.0, 0x30/255.0), - vec3( 0x18/255.0, 0x30/255.0, 0x48/255.0), - vec3( 0x18/255.0, 0x00/255.0, 0x18/255.0) -); -*/ - -const int paletteSize = 40; -const vec3 palette[paletteSize] = vec3[]( - vec3( 0, 0, 0), - vec3( 0, 0, 0.502), - vec3( 0, 0, 0.753), - vec3( 0, 0, 1), - vec3( 0, 1, 0.251), - vec3( 0, 1, 0.50), - vec3( 24.0/360.0, 1, 0.251), - vec3( 24.0/360.0, 1, 0.5), - vec3( 24.0/360.0, 1, 0.625), - vec3( 24.0/360.0, 1, 0.751), - vec3( 30.0/360.0, 1, 0.251), - vec3( 60.0/360.0, 0.333, 0.376), - vec3( 60.0/360.0, 1, 0.251), - vec3( 60.0/360.0, 1, 0.5), - vec3( 60.0/360.0, 1, 0.751), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.751), - vec3(150.0/360.0, 1, 0.251), - vec3(150.0/360.0, 1, 0.5), - vec3(150.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(210.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.751), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.251), - vec3(270.0/360.0, 1, 0.5), - vec3(270.0/360.0, 1, 0.751), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.751), - vec3(330.0/360.0, 1, 0.251), - vec3(330.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.751) -); - -/* -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} -*/ - -float hueToRgb(float f1, float f2, float hue) { - if (hue < 0.0) - hue += 1.0; - else if (hue > 1.0) - hue -= 1.0; - float res; - if ((6.0 * hue) < 1.0) - res = f1 + (f2 - f1) * 6.0 * hue; - else if ((2.0 * hue) < 1.0) - res = f2; - else if ((3.0 * hue) < 2.0) - res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0; - else - res = f1; - return res; -} - -vec3 hslToRgb(vec3 hsl) { - vec3 rgb; - - if (hsl.y == 0.0) { - rgb = vec3(hsl.z); // Luminance - } else { - float f2; - - if (hsl.z < 0.5) - f2 = hsl.z * (1.0 + hsl.y); - else - f2 = hsl.z + hsl.y - hsl.y * hsl.z; - - float f1 = 2.0 * hsl.z - f2; - - rgb.r = hueToRgb(f1, f2, hsl.x + (1.0/3.0)); - rgb.g = hueToRgb(f1, f2, hsl.x); - rgb.b = hueToRgb(f1, f2, hsl.x - (1.0/3.0)); - } - return rgb; -} - -vec3 rgbToHcv(vec3 rgb) { - float epsilon = 1e-10; - // Based on work by Sam Hocevar and Emil Persson - vec4 p = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0); - vec4 q = (rgb.r < p.x) ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx); - float c = q.x - min(q.w, q.y); - float h = abs((q.w - q.y) / (6.0 * c + epsilon) + q.z); - return vec3(h, c, q.x); -} - -vec3 rgbToHsl(vec3 rgb) { - float epsilon = 1e-10; - vec3 hcv = rgbToHcv(rgb); - float l = hcv.z - hcv.y * 0.5; - float s = hcv.y / (1.0 - abs(l * 2.0 - 1.0) + epsilon); - return vec3(hcv.x, s, l); -} - - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = rgbToHsl(palette[i]); - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 8.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue16x16(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue16x16(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - outFragColor = texture(samplerColor, inUv); - phong(outFragColor.rgb); - fog(outFragColor.rgb); - outFragColor.rgb = mix( outFragColor.rgb, inColor.rgb, inColor.a ); - if ( outFragColor.a < 0.001 ) discard; - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/base.dither4.frag.glsl b/bin/data/shaders/old/dither/base.dither4.frag.glsl deleted file mode 100644 index 638f30a1..00000000 --- a/bin/data/shaders/old/dither/base.dither4.frag.glsl +++ /dev/null @@ -1,189 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in vec3 inPositionEye; -layout (location = 2) in vec3 inNormalEye; -layout (location = 3) in vec4 inColor; -layout (location = 0) out vec4 outFragColor; - -void fog( inout vec3 i ) { - vec3 color = vec3( 0, 0, 0 ); - float inner = 8, outer = 64; - float distance = length(-inPositionEye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); - - i = mix(i.rgb, color, factor); -} - -void phong( inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = vec3(0.4, 0.4, 1.0); // light color - vec3 La = vec3(0.1, 0.1, 0.1); - - vec3 Ks = vec3(0.6, 0.6, 0.9); // material specular - vec3 Kd = i; // material diffuse - vec3 Ka = vec3(0.7, 0.7, 0.7); - - float Kexp = 1000.0; - - vec3 dist_light_eye = vec3(0, 0, 0) - inPositionEye; - vec3 dir_light_eye = normalize(dist_light_eye); - float d_dot = max(dot( dir_light_eye, inNormalEye ), 0.0); - - vec3 reflection_eye = reflect( -dir_light_eye, inNormalEye ); - vec3 surface_eye = normalize(-inPositionEye); - float s_dot = max(dot( reflection_eye, surface_eye ), 0.0); - float s_factor = pow( s_dot, Kexp ); - - vec3 Ia = La * Ka; - vec3 Id = Ld * Kd * d_dot; - vec3 Is = Ls * Ks * s_factor; - i = Is + Id + Ia; -} - -const int indexMatrix4x4[16] = int[](0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5); - -float indexValue4x4() { - int x = int(mod(gl_FragCoord.x, 4)); - int y = int(mod(gl_FragCoord.y, 4)); - return indexMatrix4x4[(x + y * 4)] / 16.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue4x4(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue4x4(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - outFragColor = texture(samplerColor, inUv); - phong(outFragColor.rgb); - fog(outFragColor.rgb); - outFragColor.rgb = mix( outFragColor.rgb, inColor.rgb, inColor.a ); - if ( outFragColor.a < 0.001 ) discard; - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/base.dither8.frag.glsl b/bin/data/shaders/old/dither/base.dither8.frag.glsl deleted file mode 100644 index 2fa1d0a3..00000000 --- a/bin/data/shaders/old/dither/base.dither8.frag.glsl +++ /dev/null @@ -1,194 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in vec3 inPositionEye; -layout (location = 2) in vec3 inNormalEye; -layout (location = 3) in vec4 inColor; -layout (location = 0) out vec4 outFragColor; - -void fog( inout vec3 i ) { - vec3 color = vec3( 0, 0, 0 ); - float inner = 8, outer = 64; - float distance = length(-inPositionEye); - float factor = (distance - inner) / (outer - inner); - factor = clamp( factor, 0.0, 1.0 ); - - i = mix(i.rgb, color, factor); -} - -void phong( inout vec3 i ) { - vec3 Ls = vec3(1.0, 1.0, 1.0); // light specular - vec3 Ld = vec3(0.4, 0.4, 1.0); // light color - vec3 La = vec3(0.1, 0.1, 0.1); - - vec3 Ks = vec3(0.6, 0.6, 0.9); // material specular - vec3 Kd = i; // material diffuse - vec3 Ka = vec3(0.7, 0.7, 0.7); - - float Kexp = 1000.0; - - vec3 dist_light_eye = vec3(0, 0, 0) - inPositionEye; - vec3 dir_light_eye = normalize(dist_light_eye); - float d_dot = max(dot( dir_light_eye, inNormalEye ), 0.0); - - vec3 reflection_eye = reflect( -dir_light_eye, inNormalEye ); - vec3 surface_eye = normalize(-inPositionEye); - float s_dot = max(dot( reflection_eye, surface_eye ), 0.0); - float s_factor = pow( s_dot, Kexp ); - - vec3 Ia = La * Ka; - vec3 Id = Ld * Kd * d_dot; - vec3 Is = Ls * Ks * s_factor; - i = Is + Id + Ia; -} - -const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21); - -float indexValue8x8() { - int x = int(mod(gl_FragCoord.x, 8)); - int y = int(mod(gl_FragCoord.y, 8)); - return indexMatrix8x8[(x + y * 8)] / 64.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue8x8(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue8x8(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - - -void main() { - outFragColor = texture(samplerColor, inUv); - phong(outFragColor.rgb); - fog(outFragColor.rgb); - outFragColor.rgb = mix( outFragColor.rgb, inColor.rgb, inColor.a ); - if ( outFragColor.a < 0.001 ) discard; - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.dither16.frag.glsl b/bin/data/shaders/old/dither/gui.dither16.frag.glsl deleted file mode 100644 index fe3936df..00000000 --- a/bin/data/shaders/old/dither/gui.dither16.frag.glsl +++ /dev/null @@ -1,178 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255, - 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127, - 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223, - 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95, - 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247, - 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119, - 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215, - 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87, - 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253, - 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125, - 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221, - 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93, - 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245, - 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117, - 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213, - 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85); - -float indexValue16x16() { - int x = int(mod(gl_FragCoord.x, 16)); - int y = int(mod(gl_FragCoord.y, 16)); - return indexMatrix16x16[(x + y * 16)] / 256.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue16x16(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue16x16(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - outFragColor = texture(samplerColor, inUv);// vec4(inUv.s, inUv.t, 1.0, 1.0); - if ( outFragColor.a < 0.001 ) discard; - if ( inGui.mode == 1 ) { - outFragColor = inGui.color; - } else { - outFragColor *= inGui.color; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.dither4.frag.glsl b/bin/data/shaders/old/dither/gui.dither4.frag.glsl deleted file mode 100644 index 59283116..00000000 --- a/bin/data/shaders/old/dither/gui.dither4.frag.glsl +++ /dev/null @@ -1,166 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -const int indexMatrix4x4[16] = int[](0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5); - -float indexValue4x4() { - int x = int(mod(gl_FragCoord.x, 4)); - int y = int(mod(gl_FragCoord.y, 4)); - return indexMatrix4x4[(x + y * 4)] / 16.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue4x4(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue4x4(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - outFragColor = texture(samplerColor, inUv);// vec4(inUv.s, inUv.t, 1.0, 1.0); - if ( outFragColor.a < 0.001 ) discard; - if ( inGui.mode == 1 ) { - outFragColor = inGui.color; - } else { - outFragColor *= inGui.color; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.dither8.frag.glsl b/bin/data/shaders/old/dither/gui.dither8.frag.glsl deleted file mode 100644 index c91f823e..00000000 --- a/bin/data/shaders/old/dither/gui.dither8.frag.glsl +++ /dev/null @@ -1,170 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21); - -float indexValue8x8() { - int x = int(mod(gl_FragCoord.x, 8)); - int y = int(mod(gl_FragCoord.y, 8)); - return indexMatrix8x8[(x + y * 8)] / 64.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue8x8(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue8x8(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - outFragColor = texture(samplerColor, inUv);// vec4(inUv.s, inUv.t, 1.0, 1.0); - if ( outFragColor.a < 0.001 ) discard; - if ( inGui.mode == 1 ) { - outFragColor = inGui.color; - } else { - outFragColor *= inGui.color; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.text.dither16.frag.glsl b/bin/data/shaders/old/dither/gui.text.dither16.frag.glsl deleted file mode 100644 index 3a33ff91..00000000 --- a/bin/data/shaders/old/dither/gui.text.dither16.frag.glsl +++ /dev/null @@ -1,196 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; - int sdf; - int shadowbox; - vec4 stroke; - float weight; - int spread; - float scale; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -const int indexMatrix16x16[256] = int[](0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255, - 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127, - 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223, - 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95, - 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247, - 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119, - 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215, - 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87, - 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253, - 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125, - 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221, - 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93, - 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245, - 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117, - 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213, - 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85); - -float indexValue16x16() { - int x = int(mod(gl_FragCoord.x, 16)); - int y = int(mod(gl_FragCoord.y, 16)); - return indexMatrix16x16[(x + y * 16)] / 256.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue16x16(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue16x16(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - if ( inGui.shadowbox == 1 ) { - outFragColor = inGui.color; - return; - } - float dist = texture(samplerColor, inUv).r; - if ( inGui.sdf == 1 ) { - float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5); - float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist); - float alpha = smoothstep(inGui.weight - smoothing, inGui.weight + smoothing, dist); - vec4 c = inGui.color; - outFragColor = mix(inGui.stroke, c, outlining); - outFragColor.a = inGui.color.a * alpha; - if ( alpha < 0.001 ) discard; - if ( alpha > 1 ) discard; - } else { - outFragColor = vec4(inGui.color) * dist; - if ( dist < 0.001 ) discard; - if ( dist > 1 ) discard; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.text.dither4.frag.glsl b/bin/data/shaders/old/dither/gui.text.dither4.frag.glsl deleted file mode 100644 index 10a8ad2f..00000000 --- a/bin/data/shaders/old/dither/gui.text.dither4.frag.glsl +++ /dev/null @@ -1,185 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; - int sdf; - int shadowbox; - vec4 stroke; - float weight; - int spread; - float scale; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - - -const int indexMatrix4x4[16] = int[](0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5); - -float indexValue4x4() { - int x = int(mod(gl_FragCoord.x, 4)); - int y = int(mod(gl_FragCoord.y, 4)); - return indexMatrix4x4[(x + y * 4)] / 16.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue4x4(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue4x4(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - if ( inGui.shadowbox == 1 ) { - outFragColor = inGui.color; - return; - } - float dist = texture(samplerColor, inUv).r; - if ( inGui.sdf == 1 ) { - float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5); - float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist); - float alpha = smoothstep(inGui.weight - smoothing, inGui.weight + smoothing, dist); - vec4 c = inGui.color; - outFragColor = mix(inGui.stroke, c, outlining); - outFragColor.a = inGui.color.a * alpha; - if ( alpha < 0.001 ) discard; - if ( alpha > 1 ) discard; - } else { - outFragColor = vec4(inGui.color) * dist; - if ( dist < 0.001 ) discard; - if ( dist > 1 ) discard; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/dither/gui.text.dither8.frag.glsl b/bin/data/shaders/old/dither/gui.text.dither8.frag.glsl deleted file mode 100644 index 205a4053..00000000 --- a/bin/data/shaders/old/dither/gui.text.dither8.frag.glsl +++ /dev/null @@ -1,187 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; - int sdf; - int shadowbox; - vec4 stroke; - float weight; - int spread; - float scale; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -const int indexMatrix8x8[64] = int[](0, 32, 8, 40, 2, 34, 10, 42, - 48, 16, 56, 24, 50, 18, 58, 26, - 12, 44, 4, 36, 14, 46, 6, 38, - 60, 28, 52, 20, 62, 30, 54, 22, - 3, 35, 11, 43, 1, 33, 9, 41, - 51, 19, 59, 27, 49, 17, 57, 25, - 15, 47, 7, 39, 13, 45, 5, 37, - 63, 31, 55, 23, 61, 29, 53, 21); - -float indexValue8x8() { - int x = int(mod(gl_FragCoord.x, 8)); - int y = int(mod(gl_FragCoord.y, 8)); - return indexMatrix8x8[(x + y * 8)] / 64.0; -} - -const int paletteSize = 28; -const vec3 palette[28] = vec3[]( - vec3(0, 0, 0), - vec3(0, 0, 1), - vec3(0, 0, 0.502), - vec3(0, 0, 0.753), - vec3(0, 1, 0.251), - vec3(0, 1, 0.50), - vec3(60.0/360.0, 1, 0.251), - vec3(60.0/360.0, 1, 0.5), - vec3(120.0/360.0, 1, 0.251), - vec3(120.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.251), - vec3(180.0/360.0, 1, 0.5), - vec3(240.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.5), - vec3(300.0/360.0, 1, 0.251), - vec3(300.0/360.0, 1, 0.5), - vec3(60.0/360.0, 0.333, 0.376), - vec3(60.0/360.0, 1, 0.751), - vec3(180.0/360.0, 1, 0.125), - vec3(150.0/360.0, 1, 0.5), - vec3(210.0/360.0, 1, 0.5), - vec3(180.0/360.0, 1, 0.751), - vec3(210.0/360.0, 1, 0.251), - vec3(240.0/360.0, 1, 0.751), - vec3(270.0/360.0, 1, 0.5), - vec3(330.0/360.0, 1, 0.5), - vec3(30.0/360.0, 1, 0.251), - vec3(24.0/360.0, 1, 0.625) -); - -vec3 hslToRgb(vec3 HSL) { - vec3 RGB; { - float H = HSL.x; - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - RGB = clamp(vec3(R,G,B), 0, 1); - } - float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; - return (RGB - 0.5) * C + HSL.z; -} - -vec3 rgbToHsl(vec3 RGB) { - float Epsilon = 1e-10; - vec3 HCV; { - vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0); - vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx); - float C = Q.x - min(Q.w, Q.y); - float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); - HCV = vec3(H, C, Q.x); - } - float L = HCV.z - HCV.y * 0.5; - float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); - return vec3(HCV.x, S, L); -} - -float hueDistance(float h1, float h2) { - float diff = abs((h1 - h2)); - return min(abs((1.0 - diff)), diff); -} - -vec3[2] closestColors(float hue) { - vec3 ret[2]; - vec3 closest = vec3(-2, 0, 0); - vec3 secondClosest = vec3(-2, 0, 0); - vec3 temp; - for (int i = 0; i < paletteSize; ++i) { - temp = palette[i]; - float tempDistance = hueDistance(temp.x, hue); - if (tempDistance < hueDistance(closest.x, hue)) { - secondClosest = closest; - closest = temp; - } else { - if (tempDistance < hueDistance(secondClosest.x, hue)) { - secondClosest = temp; - } - } - } - ret[0] = closest; - ret[1] = secondClosest; - return ret; -} - -const float lightnessSteps = 4.0; -float lightnessStep(float l) { - /* Quantize the lightness to one of `lightnessSteps` values */ - return floor((0.5 + l * lightnessSteps)) / lightnessSteps; -} - -vec3 dither1(vec3 color) { - vec3 hsl = rgbToHsl(color); - - vec3 cs[2] = closestColors(hsl.x); - vec3 c1 = cs[0]; - vec3 c2 = cs[1]; - float d = indexValue8x8(); - float hueDiff = hueDistance(hsl.x, c1.x) / hueDistance(c2.x, c1.x); - - float l1 = lightnessStep(max((hsl.z - 0.125), 0.0)); - float l2 = lightnessStep(min((hsl.z + 0.124), 1.0)); - float lightnessDiff = (hsl.z - l1) / (l2 - l1); - - vec3 resultColor = (hueDiff < d) ? c1 : c2; - //resultColor.z = (lightnessDiff < d) ? l1 : l2; - return hslToRgb(resultColor); -} - -float dither(float color) { - float closestColor = (color < 0.5) ? 0 : 1; - float secondClosestColor = 1 - closestColor; - float d = indexValue8x8(); - float distance = abs(closestColor - color); - return (distance < d) ? closestColor : secondClosestColor; -} - -vec3 dither(vec3 color) { - vec3 hsl = rgbToHsl(color); - hsl.y = dither(hsl.y); - return hslToRgb(hsl); -} - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - if ( inGui.shadowbox == 1 ) { - outFragColor = inGui.color; - return; - } - float dist = texture(samplerColor, inUv).r; - if ( inGui.sdf == 1 ) { - float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5); - float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist); - float alpha = smoothstep(inGui.weight - smoothing, inGui.weight + smoothing, dist); - vec4 c = inGui.color; - outFragColor = mix(inGui.stroke, c, outlining); - outFragColor.a = inGui.color.a * alpha; - if ( alpha < 0.001 ) discard; - if ( alpha > 1 ) discard; - } else { - outFragColor = vec4(inGui.color) * dist; - if ( dist < 0.001 ) discard; - if ( dist > 1 ) discard; - } - - outFragColor.rgb = dither(outFragColor.rgb); -} \ No newline at end of file diff --git a/bin/data/shaders/old/gui.frag.glsl b/bin/data/shaders/old/gui.frag.glsl deleted file mode 100644 index 3e683c5c..00000000 --- a/bin/data/shaders/old/gui.frag.glsl +++ /dev/null @@ -1,29 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - outFragColor = texture(samplerColor, inUv);// vec4(inUv.s, inUv.t, 1.0, 1.0); - if ( outFragColor.a < 0.001 ) discard; - if ( inGui.mode == 1 ) { - outFragColor = inGui.color; - } else { - outFragColor *= inGui.color; - } -} \ No newline at end of file diff --git a/bin/data/shaders/old/gui.text.frag.glsl b/bin/data/shaders/old/gui.text.frag.glsl deleted file mode 100644 index e805a1f8..00000000 --- a/bin/data/shaders/old/gui.text.frag.glsl +++ /dev/null @@ -1,47 +0,0 @@ -#version 450 - -layout (binding = 1) uniform sampler2D samplerColor; - -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; - int sdf; - int shadowbox; - vec4 stroke; - float weight; - int spread; - float scale; -}; - -layout (location = 0) in vec2 inUv; -layout (location = 1) in flat Gui inGui; -layout (location = 0) out vec4 outFragColor; - -void main() { - if ( inUv.x < inGui.offset.x ) discard; - if ( inUv.y < inGui.offset.y ) discard; - if ( inUv.x > inGui.offset.z ) discard; - if ( inUv.y > inGui.offset.w ) discard; - - if ( inGui.shadowbox == 1 ) { - outFragColor = inGui.color; - return; - } - float dist = texture(samplerColor, inUv).r; - if ( inGui.sdf == 1 ) { - float smoothing = ( inGui.spread > 0 && inGui.scale > 0 ) ? 0.25 / (inGui.spread * inGui.scale) : 0.25 / (4 * 1.5); - float outlining = smoothstep(0.5 - smoothing, 0.5 + smoothing, dist); - float alpha = smoothstep(inGui.weight - smoothing, inGui.weight + smoothing, dist); - vec4 c = inGui.color; - outFragColor = mix(inGui.stroke, c, outlining); - outFragColor.a = inGui.color.a * alpha; - if ( alpha < 0.001 ) discard; - if ( alpha > 1 ) discard; - } else { - outFragColor = vec4(inGui.color) * dist; - if ( dist < 0.001 ) discard; - if ( dist > 1 ) discard; - } -} \ No newline at end of file diff --git a/bin/data/shaders/old/gui.text.vert.glsl b/bin/data/shaders/old/gui.text.vert.glsl deleted file mode 100644 index 9abade45..00000000 --- a/bin/data/shaders/old/gui.text.vert.glsl +++ /dev/null @@ -1,40 +0,0 @@ -#version 450 - -layout (location = 0) in vec2 inPos; -layout (location = 1) in vec2 inUv; - -struct Matrices { - mat4 model; -}; -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; - int sdf; - int shadowbox; - vec4 stroke; - float weight; - int spread; - float scale; -}; - -layout (binding = 0) uniform UBO { - Matrices matrices; - Gui gui; -} ubo; - -layout (location = 0) out vec2 outUv; -layout (location = 1) out flat Gui outGui; - -out gl_PerVertex { - vec4 gl_Position; -}; - - -void main() { - outUv = inUv; - outGui = ubo.gui; - - gl_Position = ubo.matrices.model * vec4(inPos.xy, ubo.gui.depth, 1.0); -} \ No newline at end of file diff --git a/bin/data/shaders/old/gui.vert.glsl b/bin/data/shaders/old/gui.vert.glsl deleted file mode 100644 index 19e3daaf..00000000 --- a/bin/data/shaders/old/gui.vert.glsl +++ /dev/null @@ -1,34 +0,0 @@ -#version 450 - -layout (location = 0) in vec2 inPos; -layout (location = 1) in vec2 inUv; - -struct Matrices { - mat4 model; -}; -struct Gui { - vec4 offset; - vec4 color; - int mode; - float depth; -}; - -layout (binding = 0) uniform UBO { - Matrices matrices; - Gui gui; -} ubo; - -layout (location = 0) out vec2 outUv; -layout (location = 1) out flat Gui outGui; - -out gl_PerVertex { - vec4 gl_Position; -}; - - -void main() { - outUv = inUv; - outGui = ubo.gui; - - gl_Position = ubo.matrices.model * vec4(inPos.xy, ubo.gui.depth, 1.0); -} \ No newline at end of file diff --git a/client/client/ext.cpp b/client/client/ext.cpp index f0d04bf8..bcbf3fef 100644 --- a/client/client/ext.cpp +++ b/client/client/ext.cpp @@ -1,4 +1,5 @@ #include "../main.h" +#if !UF_ENV_DREAMCAST #include #include @@ -91,6 +92,7 @@ void client::initialize() { */ } + #if UF_USE_OPENAL /* Initialize OpenAL */ { if ( !ext::oal.initialize() ) { std::cerr << "[ERROR] AL failed to initialize!" << std::endl; @@ -98,6 +100,7 @@ void client::initialize() { return; } } + #endif /* Initialize hooks */ { // if ( client::config["engine"]["hook"]["mode"] == "Both" || client::config["engine"]["hook"]["mode"] == "Readable" ) { @@ -250,9 +253,12 @@ void client::terminate() { client::window.terminate(); + #if UF_USE_BULLET if ( !ext::oal.terminate() ) { std::cerr << "[ERROR] AL failed to terminate!" << std::endl; std::exit(EXIT_SUCCESS); return; } -} \ No newline at end of file + #endif +} +#endif \ No newline at end of file diff --git a/client/dc.cpp b/client/dc.cpp new file mode 100644 index 00000000..e1a51fc7 --- /dev/null +++ b/client/dc.cpp @@ -0,0 +1,109 @@ +#include + +#if UF_ENV_DREAMCAST + +#include +#include + +int main(int argc, char **argv) { + ext::opengl::settings::width = 640; + ext::opengl::settings::height = 480; + + ext::opengl::initialize(); + + { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glShadeModel(GL_SMOOTH); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f, (GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); // Calculate The Aspect Ratio Of The Window + glMatrixMode(GL_MODELVIEW); + } +#if 0 + while ( true ) { + ext::opengl::tick(); + ext::opengl::render(); + } +#endif +#if 0 + ext::opengl::CommandBuffer commands; + + commands.record([]{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, ext::opengl::settings::width, ext::opengl::settings::height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(-1.5f,0.0f,-6.0f); + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + glTranslatef(3.0f,0.0f,0.0f); + glBegin(GL_QUADS); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + }); + while ( true ) { + commands.submit(); + glKosSwapBuffers(); + } +#endif +#if 1 + while ( true ) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, ext::opengl::settings::width, ext::opengl::settings::height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(-1.5f,0.0f,-6.0f); + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + glTranslatef(3.0f,0.0f,0.0f); + glBegin(GL_QUADS); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + glKosSwapBuffers(); + } +#endif + + ext::opengl::destroy(); + return 0; +} +#endif \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp index f5988c52..3c1291d1 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -1,11 +1,16 @@ #include "main.h" +#if !UF_ENV_DREAMCAST #include #include #include -#define HANDLE_EXCEPTIONS 0 +#if UF_NO_EXCEPTIONS + #define HANDLE_EXCEPTIONS 0 +#else + #define HANDLE_EXCEPTIONS 1 +#endif int main(int argc, char** argv){ for ( size_t i = 0; i < argc; ++i ) { @@ -72,4 +77,5 @@ int main(int argc, char** argv){ ext::terminate(); client::terminate(); return 0; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/client/main.h b/client/main.h index dcd2312b..3990dace 100644 --- a/client/main.h +++ b/client/main.h @@ -1,6 +1,6 @@ #pragma once - #include +#if !UF_ENV_DREAMCAST #include #include #include @@ -15,4 +15,5 @@ namespace client { void tick(); void render(); void terminate(); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/dreamcast.h b/engine/inc/dreamcast.h new file mode 100644 index 00000000..5b01f208 --- /dev/null +++ b/engine/inc/dreamcast.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +namespace std { + template + std::string to_string( const T& val ) { + std::stringstream ss; + ss << val; + return ss.str(); + } + + inline float strtof(const char* str, char** endptr) { return ::strtof(str, endptr); } + inline double strtold(const char* str, char** endptr) { return ::strtold(str, endptr); } + inline long long int strtoll(const char* str, char** endptr, int base) { return ::strtoll(str, endptr, base); } + inline unsigned long long int strtoull(const char* str, char** endptr, int base) { return ::strtoull(str, endptr, base); } + + template + inline int snprintf( char* s, size_t n, const char* format, Args... args ) { + return ::snprintf(s, n, format, args...); + } + + inline unsigned long long stoull( const std::string& s, std::size_t* pos = 0, int base = 10 ) { + std::wstring ws(s.begin(), s.end()); + return std::__cxx11::stoull( ws, pos, base ); + } + inline int stoi( const std::string& s, std::size_t* pos = 0, int base = 10 ) { + std::wstring ws(s.begin(), s.end()); + return std::__cxx11::stoi( ws, pos, base ); + } + inline double cbrt( double x ) { + return ::cbrt( x ); + } +} \ No newline at end of file diff --git a/engine/inc/gltf/tiny_gltf.h b/engine/inc/gltf/tiny_gltf.h index 88e10931..ac2c413d 100644 --- a/engine/inc/gltf/tiny_gltf.h +++ b/engine/inc/gltf/tiny_gltf.h @@ -1579,7 +1579,7 @@ class TinyGLTF { #endif -#elif !defined(__ANDROID__) +#elif !defined(__ANDROID__) && !defined(__sh__) #include #endif @@ -2566,7 +2566,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) { #else #if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \ - defined(__ANDROID__) || defined(__EMSCRIPTEN__) + defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__sh__) // no expansion std::string s = filepath; #else diff --git a/engine/inc/meshoptimizer.h b/engine/inc/meshoptimizer.h index 3acbe897..665e27ef 100644 --- a/engine/inc/meshoptimizer.h +++ b/engine/inc/meshoptimizer.h @@ -46,7 +46,7 @@ struct meshopt_Stream * destination must contain enough space for the resulting remap table (vertex_count elements) * indices can be NULL if the input is unindexed */ -MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(uint32_t* destination, const uint32_t* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); /** * Generates a vertex remap table from multiple vertex streams and an optional index buffer and returns number of unique vertices @@ -57,7 +57,7 @@ MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(unsigned int* destination, * destination must contain enough space for the resulting remap table (vertex_count elements) * indices can be NULL if the input is unindexed */ -MESHOPTIMIZER_API size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); +MESHOPTIMIZER_API size_t meshopt_generateVertexRemapMulti(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); /** * Generates vertex buffer from the source vertex buffer and remap table generated by meshopt_generateVertexRemap @@ -65,7 +65,7 @@ MESHOPTIMIZER_API size_t meshopt_generateVertexRemapMulti(unsigned int* destinat * destination must contain enough space for the resulting vertex buffer (unique_vertex_count elements, returned by meshopt_generateVertexRemap) * vertex_count should be the initial vertex count and not the value returned by meshopt_generateVertexRemap */ -MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap); +MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const uint32_t* remap); /** * Generate index buffer from the source index buffer and remap table generated by meshopt_generateVertexRemap @@ -73,7 +73,7 @@ MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* * destination must contain enough space for the resulting index buffer (index_count elements) * indices can be NULL if the input is unindexed */ -MESHOPTIMIZER_API void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap); +MESHOPTIMIZER_API void meshopt_remapIndexBuffer(uint32_t* destination, const uint32_t* indices, size_t index_count, const uint32_t* remap); /** * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary @@ -82,7 +82,7 @@ MESHOPTIMIZER_API void meshopt_remapIndexBuffer(unsigned int* destination, const * * destination must contain enough space for the resulting index buffer (index_count elements) */ -MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride); +MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(uint32_t* destination, const uint32_t* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride); /** * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary @@ -91,7 +91,7 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destinati * * destination must contain enough space for the resulting index buffer (index_count elements) */ -MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); +MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count); /** * Vertex transform cache optimizer @@ -100,7 +100,7 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* dest * * destination must contain enough space for the resulting index buffer (index_count elements) */ -MESHOPTIMIZER_API void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); +MESHOPTIMIZER_API void meshopt_optimizeVertexCache(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count); /** * Vertex transform cache optimizer for strip-like caches @@ -109,7 +109,7 @@ MESHOPTIMIZER_API void meshopt_optimizeVertexCache(unsigned int* destination, co * * destination must contain enough space for the resulting index buffer (index_count elements) */ -MESHOPTIMIZER_API void meshopt_optimizeVertexCacheStrip(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); +MESHOPTIMIZER_API void meshopt_optimizeVertexCacheStrip(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count); /** * Vertex transform cache optimizer for FIFO caches @@ -120,7 +120,7 @@ MESHOPTIMIZER_API void meshopt_optimizeVertexCacheStrip(unsigned int* destinatio * destination must contain enough space for the resulting index buffer (index_count elements) * cache_size should be less than the actual GPU cache size to avoid cache thrashing */ -MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size); +MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count, uint32_t cache_size); /** * Overdraw optimizer @@ -132,7 +132,7 @@ MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer * threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently */ -MESHOPTIMIZER_API void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold); +MESHOPTIMIZER_API void meshopt_optimizeOverdraw(uint32_t* destination, const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold); /** * Vertex fetch cache optimizer @@ -143,7 +143,7 @@ MESHOPTIMIZER_API void meshopt_optimizeOverdraw(unsigned int* destination, const * destination must contain enough space for the resulting vertex buffer (vertex_count elements) * indices is used both as an input and as an output index buffer */ -MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, uint32_t* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); /** * Vertex fetch cache optimizer @@ -153,7 +153,7 @@ MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, unsigned * * destination must contain enough space for the resulting remap table (vertex_count elements) */ -MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count); +MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count); /** * Index buffer encoder @@ -164,7 +164,7 @@ MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(unsigned int* destinat * * buffer must contain enough space for the encoded index buffer (use meshopt_encodeIndexBufferBound to compute worst case size) */ -MESHOPTIMIZER_API size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count); +MESHOPTIMIZER_API size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const uint32_t* indices, size_t index_count); MESHOPTIMIZER_API size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count); /** @@ -191,7 +191,7 @@ MESHOPTIMIZER_API int meshopt_decodeIndexBuffer(void* destination, size_t index_ * * buffer must contain enough space for the encoded index sequence (use meshopt_encodeIndexSequenceBound to compute worst case size) */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const uint32_t* indices, size_t index_count); MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_encodeIndexSequenceBound(size_t index_count, size_t vertex_count); /** @@ -261,7 +261,7 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_decodeFilterExp(void* buffer, size_t ver * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!) * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(uint32_t* destination, const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error); /** * Experimental: Mesh simplifier (sloppy) @@ -274,7 +274,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, co * destination must contain enough space for the target index buffer * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(uint32_t* destination, const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count); /** * Experimental: Point cloud simplifier @@ -286,7 +286,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destinati * destination must contain enough space for the target index buffer * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(uint32_t* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count); /** * Mesh stripifier @@ -298,7 +298,7 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destinati * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_stripifyBound * restart_index should be 0xffff or 0xffffffff depending on index size, or 0 to use degenerate triangles */ -MESHOPTIMIZER_API size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index); +MESHOPTIMIZER_API size_t meshopt_stripify(uint32_t* destination, const uint32_t* indices, size_t index_count, size_t vertex_count, uint32_t restart_index); MESHOPTIMIZER_API size_t meshopt_stripifyBound(size_t index_count); /** @@ -308,13 +308,13 @@ MESHOPTIMIZER_API size_t meshopt_stripifyBound(size_t index_count); * * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_unstripifyBound */ -MESHOPTIMIZER_API size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index); +MESHOPTIMIZER_API size_t meshopt_unstripify(uint32_t* destination, const uint32_t* indices, size_t index_count, uint32_t restart_index); MESHOPTIMIZER_API size_t meshopt_unstripifyBound(size_t index_count); struct meshopt_VertexCacheStatistics { - unsigned int vertices_transformed; - unsigned int warps_executed; + uint32_t vertices_transformed; + uint32_t warps_executed; float acmr; /* transformed vertices / triangle count; best case 0.5, worst case 3.0, optimum depends on topology */ float atvr; /* transformed vertices / vertex count; best case 1.0, worst case 6.0, optimum is 1.0 (each vertex is transformed once) */ }; @@ -324,12 +324,12 @@ struct meshopt_VertexCacheStatistics * Returns cache hit statistics using a simplified FIFO model * Results may not match actual GPU performance */ -MESHOPTIMIZER_API struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size); +MESHOPTIMIZER_API struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const uint32_t* indices, size_t index_count, size_t vertex_count, uint32_t cache_size, uint32_t warp_size, uint32_t primgroup_size); struct meshopt_OverdrawStatistics { - unsigned int pixels_covered; - unsigned int pixels_shaded; + uint32_t pixels_covered; + uint32_t pixels_shaded; float overdraw; /* shaded pixels / covered pixels; best case 1.0 */ }; @@ -340,11 +340,11 @@ struct meshopt_OverdrawStatistics * * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer */ -MESHOPTIMIZER_API struct meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_API struct meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); struct meshopt_VertexFetchStatistics { - unsigned int bytes_fetched; + uint32_t bytes_fetched; float overfetch; /* fetched bytes / vertex buffer size; best case 1.0 (each byte is fetched once) */ }; @@ -353,11 +353,11 @@ struct meshopt_VertexFetchStatistics * Returns cache hit statistics using a simplified direct mapped model * Results may not match actual GPU performance */ -MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size); +MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const uint32_t* indices, size_t index_count, size_t vertex_count, size_t vertex_size); struct meshopt_Meshlet { - unsigned int vertices[64]; + uint32_t vertices[64]; unsigned char indices[126][3]; unsigned char triangle_count; unsigned char vertex_count; @@ -372,7 +372,7 @@ struct meshopt_Meshlet * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126) */ -MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); +MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const uint32_t* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles); MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles); struct meshopt_Bounds @@ -412,7 +412,7 @@ struct meshopt_Bounds * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size) */ -MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); /** @@ -422,7 +422,7 @@ MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(co * * destination must contain enough space for the resulting remap table (vertex_count elements) */ -MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(uint32_t* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); /** * Experimental: Spatial sorter @@ -431,7 +431,7 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destinati * destination must contain enough space for the resulting index buffer (index_count elements) * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer */ -MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); +MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortTriangles(uint32_t* destination, const uint32_t* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); /** * Set allocation callbacks @@ -482,16 +482,16 @@ inline float meshopt_quantizeFloat(float v, int N); * * These functions mirror the C interface the library provides, providing template-based overloads so that * the caller can use an arbitrary type for the index data, both for input and output. - * When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not, + * When the supplied type is the same size as that of uint32_t, the wrappers are zero-cost; when it's not, * the wrappers end up allocating memory and copying index data to convert from one type to another. */ #if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS) template -inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); +inline size_t meshopt_generateVertexRemap(uint32_t* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); template -inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count); +inline size_t meshopt_generateVertexRemapMulti(uint32_t* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count); template -inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap); +inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const uint32_t* remap); template inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride); template @@ -501,11 +501,11 @@ inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t template inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count); template -inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size); +inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, uint32_t cache_size); template inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold); template -inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count); +inline size_t meshopt_optimizeVertexFetchRemap(uint32_t* destination, const T* indices, size_t index_count, size_t vertex_count); template inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size); template @@ -525,7 +525,7 @@ inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_co template inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index); template -inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size); +inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, uint32_t cache_size, uint32_t warp_size, uint32_t buffer_size); template inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); template @@ -564,8 +564,8 @@ inline int meshopt_quantizeSnorm(float v, int N) inline unsigned short meshopt_quantizeHalf(float v) { - union { float f; unsigned int ui; } u = {v}; - unsigned int ui = u.ui; + union { float f; uint32_t ui; } u = {v}; + uint32_t ui = u.ui; int s = (ui >> 16) & 0x8000; int em = ui & 0x7fffffff; @@ -587,14 +587,14 @@ inline unsigned short meshopt_quantizeHalf(float v) inline float meshopt_quantizeFloat(float v, int N) { - union { float f; unsigned int ui; } u = {v}; - unsigned int ui = u.ui; + union { float f; uint32_t ui; } u = {v}; + uint32_t ui = u.ui; const int mask = (1 << (23 - N)) - 1; const int round = (1 << (23 - N)) >> 1; int e = ui & 0x7f800000; - unsigned int rui = (ui + round) & ~mask; + uint32_t rui = (ui + round) & ~mask; /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */ ui = e == 0x7f800000 ? ui : rui; @@ -653,14 +653,14 @@ template void (*meshopt_Allocator::StorageT::deallocate)(void*) /* Inline implementation for C++ templated wrappers */ #if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS) -template +template struct meshopt_IndexAdapter; template struct meshopt_IndexAdapter { T* result; - unsigned int* data; + uint32_t* data; size_t count; meshopt_IndexAdapter(T* result_, const T* input, size_t count_) @@ -668,9 +668,9 @@ struct meshopt_IndexAdapter , data(0) , count(count_) { - size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int); + size_t size = count > size_t(-1) / sizeof(uint32_t) ? size_t(-1) : count * sizeof(uint32_t); - data = static_cast(meshopt_Allocator::Storage::allocate(size)); + data = static_cast(meshopt_Allocator::Storage::allocate(size)); if (input) { @@ -694,16 +694,16 @@ struct meshopt_IndexAdapter template struct meshopt_IndexAdapter { - unsigned int* data; + uint32_t* data; meshopt_IndexAdapter(T* result, const T* input, size_t) - : data(reinterpret_cast(result ? result : const_cast(input))) + : data(reinterpret_cast(result ? result : const_cast(input))) { } }; template -inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) +inline size_t meshopt_generateVertexRemap(uint32_t* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size) { meshopt_IndexAdapter in(0, indices, indices ? index_count : 0); @@ -711,7 +711,7 @@ inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* in } template -inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count) +inline size_t meshopt_generateVertexRemapMulti(uint32_t* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count) { meshopt_IndexAdapter in(0, indices, indices ? index_count : 0); @@ -719,7 +719,7 @@ inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const } template -inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap) +inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const uint32_t* remap) { meshopt_IndexAdapter in(0, indices, indices ? index_count : 0); meshopt_IndexAdapter out(destination, 0, index_count); @@ -764,7 +764,7 @@ inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, s } template -inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size) +inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, uint32_t cache_size) { meshopt_IndexAdapter in(0, indices, index_count); meshopt_IndexAdapter out(destination, 0, index_count); @@ -782,7 +782,7 @@ inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t in } template -inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count) +inline size_t meshopt_optimizeVertexFetchRemap(uint32_t* destination, const T* indices, size_t index_count, size_t vertex_count) { meshopt_IndexAdapter in(0, indices, index_count); @@ -868,7 +868,7 @@ inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_ } template -inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size) +inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, uint32_t cache_size, uint32_t warp_size, uint32_t buffer_size) { meshopt_IndexAdapter in(0, indices, index_count); diff --git a/engine/inc/uf/config.h b/engine/inc/uf/config.h index aa41600e..c8238c9e 100644 --- a/engine/inc/uf/config.h +++ b/engine/inc/uf/config.h @@ -8,6 +8,7 @@ #undef UF_ENV_LINUX #undef UF_ENV_MACOS #undef UF_ENV_FREEBSD + #undef UF_ENV_DREAMCAST #undef UF_ENV_UNKNOWN #endif @@ -21,22 +22,39 @@ #endif #define _WIN32_WINNT 0x0600 #define WINVER 0x0600 -// #warning Using "Windows" + + #define UF_IO_ROOT "./data/" #elif defined(linux) || defined(__linux) // Linux #define UF_ENV "Linux" #define UF_ENV_LINUX 1 #define UF_ENV_HEADER "linux.h" + + #define UF_IO_ROOT "./data/" #elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh) // MacOS #define UF_ENV "OSX" #define UF_ENV_OSX 1 #define UF_ENV_HEADER "osx.h" + + #define UF_IO_ROOT "./data/" #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) // FreeBSD #define UF_ENV "FreeBSD" #define UF_ENV_FREEBSD 1 #define UF_ENV_HEADER "freebsd.h" + + #define UF_IO_ROOT "./data/" +#elif defined(__sh__) + // Dreamcast + #define UF_ENV "Dreamcast" + #define UF_ENV_DREAMCAST 1 + #define UF_ENV_HEADER "dreamcast.h" + #include UF_ENV_HEADER + + #define _arch_dreamcast + + #define UF_IO_ROOT "/rc/data/" #else // Unsupported system #define UF_ENV "Unknown" @@ -81,45 +99,11 @@ // Legacy support #define UF_API_VAR UF_API -#define UF_API_CALL __cdecl +#define UF_API_CALL //__cdecl #ifdef UF_DISABLE_ALIGNAS #define alignas(X) #endif #include "macros.h" -#include "simd.h" - -//#define UF_USE_NLOHMANN 1 // wrapper works, please use this -//#define UF_USE_JSONCPP 0 // originally implemented JSON with JSONCPP, internal wrapper broke things -//#define UF_USE_RAPIDJSON 0 // wrapper for rapidjson is incomplete -//#define UF_USE_LUA 0 // wrapper for SOL2 Lua tables is incomplete - -/* -// External libraries -#ifndef UF_USE_GLEW - #define UF_USE_GLEW 1 -#endif -#ifndef UF_USE_JSON - #define UF_USE_JSON 1 -#endif -#ifndef UF_USE_LUA - #define UF_USE_LUA 0 -#endif -#ifndef UF_USE_NCURSES - #define UF_USE_NCURSES 1 -#endif -#ifndef UF_USE_OPENGL - #define UF_USE_OPENGL 0 -#endif -#ifndef UF_USE_SFML - #define UF_USE_SFML 0 -#endif -// Planned -#ifndef UF_USE_VULKAN - #define UF_USE_VULKAN 0 -#endif -#ifndef UF_USE_DIRECTX - #define UF_USE_DIRECTX 0 -#endif -*/ \ No newline at end of file +#include "simd.h" \ No newline at end of file diff --git a/engine/inc/uf/ext/bullet/bullet.h b/engine/inc/uf/ext/bullet/bullet.h index b7f36b6e..26ee77f6 100644 --- a/engine/inc/uf/ext/bullet/bullet.h +++ b/engine/inc/uf/ext/bullet/bullet.h @@ -1,14 +1,14 @@ #pragma once #include - #include #include #include #include +#if UF_USE_BULLET #include "btBulletDynamicsCommon.h" - +#endif namespace pod { struct UF_API Bullet { size_t uid = 0; @@ -17,11 +17,16 @@ namespace pod { pod::Transform<>* transform = NULL; bool shared = false; // share control of the transform both in-engine and bullet, set to true if you're directly modifying the transform + #if UF_USE_BULLET btRigidBody* body = NULL; btCollisionShape* shape = NULL; + #else + void* body = NULL; + void* shape = NULL; + #endif }; } - +#if UF_USE_BULLET namespace ext { namespace bullet { extern UF_API bool debugDrawEnabled; @@ -74,4 +79,5 @@ namespace ext { } } -#include "bullet.inl" \ No newline at end of file +#include "bullet.inl" +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/freetype/freetype.h b/engine/inc/uf/ext/freetype/freetype.h index c28aa715..4ca36216 100644 --- a/engine/inc/uf/ext/freetype/freetype.h +++ b/engine/inc/uf/ext/freetype/freetype.h @@ -1,7 +1,7 @@ #pragma once #include -#if defined(UF_USE_FREETYPE) +#if UF_USE_FREETYPE #include #include FT_FREETYPE_H diff --git a/engine/inc/uf/ext/json/json.h b/engine/inc/uf/ext/json/json.h index 8958fdad..72e66fc4 100644 --- a/engine/inc/uf/ext/json/json.h +++ b/engine/inc/uf/ext/json/json.h @@ -14,7 +14,9 @@ #error "JSON implementation not defined" #endif -#include +#if UF_USE_LUA + #include +#endif namespace ext { namespace json { @@ -36,10 +38,10 @@ namespace ext { void UF_API forEach( const ext::json::Value& json, const std::function& function ); void UF_API forEach( const ext::json::Value& json, const std::function& function ); - std::string UF_API encode( const sol::table& table ); std::string UF_API encode( const ext::json::Value& json, bool pretty = true ); void UF_API decode( ext::json::Value& json, const std::string& str ); + #if UF_USE_LUA + std::string UF_API encode( const sol::table& table ); + #endif } -} - -#include "json.inl" \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/ext/json/json.inl b/engine/inc/uf/ext/json/json.inl deleted file mode 100644 index e69de29b..00000000 diff --git a/engine/inc/uf/ext/json/nlohmann.h b/engine/inc/uf/ext/json/nlohmann.h index 05fdd1f0..38e57c6a 100644 --- a/engine/inc/uf/ext/json/nlohmann.h +++ b/engine/inc/uf/ext/json/nlohmann.h @@ -89,6 +89,10 @@ template<> inline bool ext::json::Value::is(bool strict) const { return s template<> inline bool ext::json::Value::is(bool strict) const { return strict ? is_number_float() : is_number(); } template<> inline bool ext::json::Value::is(bool strict) const { return is_string(); } +#if UF_ENV_DREAMCAST + template<> inline bool ext::json::Value::is(bool strict) const { return strict ? is_number_integer() : is_number(); } + template<> inline bool ext::json::Value::is(bool strict) const { return strict ? is_number_unsigned() : is_number(); } +#endif template inline T ext::json::Value::as() const { if ( !is() ) return T(); return get(); diff --git a/engine/inc/uf/ext/lua/lua.h b/engine/inc/uf/ext/lua/lua.h index ba0210ab..e971d2be 100644 --- a/engine/inc/uf/ext/lua/lua.h +++ b/engine/inc/uf/ext/lua/lua.h @@ -1,7 +1,7 @@ #pragma once #include - +#if UF_USE_LUA #define SOL_LUAJIT 1 #define SOL_USING_CXX_LUA_JIT 1 #define SOL_NO_EXCEPTIONS 1 @@ -42,4 +42,5 @@ namespace ext { } } -#include "lua.inl" \ No newline at end of file +#include "lua.inl" +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/oal/oal.h b/engine/inc/uf/ext/oal/oal.h index 06a36499..28132d51 100644 --- a/engine/inc/uf/ext/oal/oal.h +++ b/engine/inc/uf/ext/oal/oal.h @@ -1,7 +1,7 @@ #pragma once #include -#if defined(UF_USE_OPENAL) +#if UF_USE_OPENAL #include #include diff --git a/engine/inc/uf/ext/opengl/buffer.h b/engine/inc/uf/ext/opengl/buffer.h index 9831db73..6dde0150 100644 --- a/engine/inc/uf/ext/opengl/buffer.h +++ b/engine/inc/uf/ext/opengl/buffer.h @@ -10,38 +10,49 @@ namespace ext { struct Device; struct UF_API Buffer { - GLhandle(VkDevice) device; - GLhandle(VkBuffer) buffer = GL_NULL_HANDLE; - GLhandle(VkDeviceMemory) memory = GL_NULL_HANDLE; - GLhandle(VkDescriptorBufferInfo) descriptor; // = {GL_NULL_HANDLE,0,0}; + Device* device; + void* buffer = GL_NULL_HANDLE; + + struct { + void* buffer = NULL; + GLsizeiptr offset = 0; + GLsizeiptr range = GL_WHOLE_SIZE; + } descriptor = {GL_NULL_HANDLE,0,0}; + + struct CreateInfo { + GLenum flags = 0; + GLsizeiptr size = 0; + GLenum usage = 0; + }; + GLsizeiptr size = 0; GLsizeiptr alignment = 0; - void* mapped = nullptr; - - GLhandle(VkBufferUsageFlags) usageFlags; - GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags; - - GLhandle(VkMemoryAllocateInfo) memAlloc; - GLhandle(VkMemoryRequirements) memReqs; + GLenum usageFlags = 0; GLhandle(VmaAllocation) allocation; - GLhandle(VmaAllocationInfo) allocationInfo; - - GLhandle(VkResult) map( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); + struct AllocationInfo { + uint32_t memoryType = 0; + GLhandle(VkDeviceMemory) deviceMemory = GL_NULL_HANDLE; + GLsizeiptr offset = 0; + GLsizeiptr size = 0; + void* pMappedData = NULL; + void* pUserData = NULL; + } allocationInfo; + bool map( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); void unmap(); - GLhandle(VkResult) bind( GLsizeiptr offset = 0 ); + bool bind( GLsizeiptr offset = 0 ); void setupDescriptor( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); void copyTo( void* data, GLsizeiptr size ); - GLhandle(VkResult) flush( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); - GLhandle(VkResult) invalidate( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); - void allocate( GLhandle(VkBufferCreateInfo) ); + bool flush( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); + bool invalidate( GLsizeiptr size = GL_WHOLE_SIZE, GLsizeiptr offset = 0 ); + void allocate( const CreateInfo& ); // RAII ~Buffer(); - void initialize( GLhandle(VkDevice) device ); + void initialize( Device& device ); void destroy(); }; struct UF_API Buffers { @@ -53,9 +64,13 @@ namespace ext { void initialize( Device& device ); void destroy(); // - size_t initializeBuffer( void* data, GLsizeiptr length, GLhandle(VkBufferUsageFlags) usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ); - template inline size_t initializeBuffer( T data, GLsizeiptr length, GLhandle(VkBufferUsageFlags) usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (void*) &data, length, usageFlags, memoryPropertyFlags, stage ); } - template inline size_t initializeBuffer( T data, GLhandle(VkBufferUsageFlags) usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (void*) &data, static_cast(sizeof(T)), usageFlags, memoryPropertyFlags, stage ); } + size_t initializeBuffer( void* data, GLsizeiptr length, GLenum usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ); + template inline size_t initializeBuffer( T data, GLsizeiptr length, GLenum usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ) { + return initializeBuffer( (void*) &data, length, usageFlags, memoryPropertyFlags, stage ); + } + template inline size_t initializeBuffer( T data, GLenum usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags = GLenumerator(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), bool stage = GL_DEFAULT_STAGE_BUFFERS ) { + return initializeBuffer( (void*) &data, static_cast(sizeof(T)), usageFlags, memoryPropertyFlags, stage ); + } void updateBuffer( void* data, GLsizeiptr length, size_t index = 0, bool stage = GL_DEFAULT_STAGE_BUFFERS ); void updateBuffer( void* data, GLsizeiptr length, Buffer& buffer, bool stage = GL_DEFAULT_STAGE_BUFFERS ); diff --git a/engine/inc/uf/ext/opengl/commands.h b/engine/inc/uf/ext/opengl/commands.h new file mode 100644 index 00000000..cefa5541 --- /dev/null +++ b/engine/inc/uf/ext/opengl/commands.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include + +namespace ext { + namespace opengl { + struct UF_API CommandBuffer { + typedef std::function function_t; + + std::vector commands; + + void record( const CommandBuffer::function_t& ); + void submit(); + void flush(); + size_t size() const; + }; + } +} \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/device.h b/engine/inc/uf/ext/opengl/device.h index df88ef50..d64c2099 100644 --- a/engine/inc/uf/ext/opengl/device.h +++ b/engine/inc/uf/ext/opengl/device.h @@ -2,15 +2,21 @@ #include #include +#include #include #include #include namespace ext { namespace opengl { - class UF_API Device { + struct UF_API Device { public: uf::Window* window; + spec::Context* context; + spec::Context::Settings contextSettings; + + void initialize(); + void destroy(); }; } } \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/enums.h b/engine/inc/uf/ext/opengl/enums.h index dd9ddc49..864665ba 100644 --- a/engine/inc/uf/ext/opengl/enums.h +++ b/engine/inc/uf/ext/opengl/enums.h @@ -7,26 +7,26 @@ namespace ext { namespace enums { namespace Compare { typedef GLenum type_t; - static const GLenum NEVER = GLenumerator(VK_COMPARE_OP_NEVER); - static const GLenum LESS = GLenumerator(VK_COMPARE_OP_LESS); - static const GLenum EQUAL = GLenumerator(VK_COMPARE_OP_EQUAL); - static const GLenum LESS_OR_EQUAL = GLenumerator(VK_COMPARE_OP_LESS_OR_EQUAL); - static const GLenum GREATER = GLenumerator(VK_COMPARE_OP_GREATER); - static const GLenum NOT_EQUAL = GLenumerator(VK_COMPARE_OP_NOT_EQUAL); - static const GLenum GREATER_OR_EQUAL = GLenumerator(VK_COMPARE_OP_GREATER_OR_EQUAL); - static const GLenum ALWAYS = GLenumerator(VK_COMPARE_OP_ALWAYS); + static const GLenum NEVER = GL_NEVER; + static const GLenum LESS = GL_LESS; + static const GLenum EQUAL = GL_EQUAL; + static const GLenum LESS_OR_EQUAL = GL_LEQUAL; + static const GLenum GREATER = GL_GREATER; + static const GLenum NOT_EQUAL = GL_NOTEQUAL; + static const GLenum GREATER_OR_EQUAL = GL_GEQUAL; + static const GLenum ALWAYS = GL_ALWAYS; } namespace Format { typedef GLenum type_t; - static const GLenum D32_SFLOAT = GLenumerator(VK_FORMAT_D32_SFLOAT); - static const GLenum R16G16B16A16_SFLOAT = GLenumerator(VK_FORMAT_R16G16B16A16_SFLOAT); - static const GLenum R8_UNORM = GLenumerator(VK_FORMAT_R8_UNORM); - static const GLenum R32_UINT = GLenumerator(VK_FORMAT_R32_UINT); - static const GLenum R32G32_SINT = GLenumerator(VK_FORMAT_R32G32_SINT); - static const GLenum R32G32_SFLOAT = GLenumerator(VK_FORMAT_R32G32_SFLOAT); - static const GLenum R32G32B32_SFLOAT = GLenumerator(VK_FORMAT_R32G32B32_SFLOAT); - static const GLenum R32G32B32A32_SFLOAT = GLenumerator(VK_FORMAT_R32G32B32A32_SFLOAT); - static const GLenum R8G8B8A8_UNORM = GLenumerator(VK_FORMAT_R8G8B8A8_UNORM); + static const GLenum D32_SFLOAT = 0x00000001; //GLenumerator(VK_FORMAT_D32_SFLOAT); + static const GLenum R16G16B16A16_SFLOAT = 0x00000002; //GLenumerator(VK_FORMAT_R16G16B16A16_SFLOAT); + static const GLenum R8_UNORM = 0x00000004; //GLenumerator(VK_FORMAT_R8_UNORM); + static const GLenum R32_UINT = 0x00000008; //GLenumerator(VK_FORMAT_R32_UINT); + static const GLenum R32G32_SINT = 0x00000010; //GLenumerator(VK_FORMAT_R32G32_SINT); + static const GLenum R32G32_SFLOAT = 0x00000020; //GLenumerator(VK_FORMAT_R32G32_SFLOAT); + static const GLenum R32G32B32_SFLOAT = 0x00000040; //GLenumerator(VK_FORMAT_R32G32B32_SFLOAT); + static const GLenum R32G32B32A32_SFLOAT = 0x00000080; //GLenumerator(VK_FORMAT_R32G32B32A32_SFLOAT); + static const GLenum R8G8B8A8_UNORM = 0x00000100; //GLenumerator(VK_FORMAT_R8G8B8A8_UNORM); } namespace Face { typedef GLenum type_t; @@ -35,21 +35,32 @@ namespace ext { } namespace CullMode { typedef GLenum type_t; - static const GLenum NONE = GL_NONE; + static const GLenum NONE = 0; static const GLenum FRONT = GL_FRONT; static const GLenum BACK = GL_BACK; static const GLenum BOTH = GL_FRONT_AND_BACK; } namespace Shader { typedef GLenum type_t; - static const GLenum VERTEX = GLenumerator(VK_SHADER_STAGE_VERTEX_BIT); - static const GLenum TESSELLATION_CONTROL = GLenumerator(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); - static const GLenum TESSELLATION_EVALUATION = GLenumerator(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT); - static const GLenum GEOMETRY = GLenumerator(VK_SHADER_STAGE_GEOMETRY_BIT); - static const GLenum FRAGMENT = GLenumerator(VK_SHADER_STAGE_FRAGMENT_BIT); - static const GLenum COMPUTE = GLenumerator(VK_SHADER_STAGE_COMPUTE_BIT); + #if UF_ENV_DREAMCAST + static const GLenum VERTEX = 0x00000001; + static const GLenum TESSELLATION_CONTROL = 0x00000002; + static const GLenum TESSELLATION_EVALUATION = 0x00000003; + static const GLenum GEOMETRY = 0x00000004; + static const GLenum FRAGMENT = 0x00000005; + static const GLenum COMPUTE = 0x00000006; + static const GLenum ALL_GRAPHICS = 0x00000007; + static const GLenum ALL = 0x00000008; + #else + static const GLenum VERTEX = GL_VERTEX_SHADER; + static const GLenum TESSELLATION_CONTROL = GL_TESS_CONTROL_SHADER; + static const GLenum TESSELLATION_EVALUATION = GL_TESS_EVALUATION_SHADER; + static const GLenum GEOMETRY = GL_GEOMETRY_SHADER; + static const GLenum FRAGMENT = GL_FRAGMENT_SHADER; + static const GLenum COMPUTE = GL_COMPUTE_SHADER; static const GLenum ALL_GRAPHICS = GLenumerator(VK_SHADER_STAGE_ALL_GRAPHICS); static const GLenum ALL = GLenumerator(VK_SHADER_STAGE_ALL); + #endif } namespace PrimitiveTopology { typedef GLenum type_t; @@ -85,15 +96,15 @@ namespace ext { } namespace Buffer { typedef GLenum type_t; - static const GLenum TRANSFER_SRC = GLenumerator(VK_BUFFER_USAGE_TRANSFER_SRC_BIT); - static const GLenum TRANSFER_DST = GLenumerator(VK_BUFFER_USAGE_TRANSFER_DST_BIT); - static const GLenum UNIFORM_TEXEL = GLenumerator(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT); - static const GLenum STORAGE_TEXEL = GLenumerator(VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT); - static const GLenum UNIFORM = GLenumerator(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); - static const GLenum STORAGE = GLenumerator(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); - static const GLenum INDEX = GLenumerator(VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - static const GLenum VERTEX = GLenumerator(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - static const GLenum INDIRECT = GLenumerator(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); + static const GLenum TRANSFER_SRC = 0x00000001; + static const GLenum TRANSFER_DST = 0x00000002; + static const GLenum UNIFORM_TEXEL = 0x00000004; + static const GLenum STORAGE_TEXEL = 0x00000008; + static const GLenum UNIFORM = 0x00000010; + static const GLenum STORAGE = 0x00000020; + static const GLenum INDEX = 0x00000040; + static const GLenum VERTEX = 0x00000080; + static const GLenum INDIRECT = 0x00000100; } } } diff --git a/engine/inc/uf/ext/opengl/graphic.h b/engine/inc/uf/ext/opengl/graphic.h index ba3ebc03..269e744f 100644 --- a/engine/inc/uf/ext/opengl/graphic.h +++ b/engine/inc/uf/ext/opengl/graphic.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,7 @@ namespace ext { void initialize( Graphic& graphic, GraphicDescriptor& descriptor ); void update( Graphic& graphic ); void update( Graphic& graphic, GraphicDescriptor& descriptor ); - void record( Graphic& graphic, GLhandle(VkCommandBuffer), size_t = 0, size_t = 0 ); + void record( Graphic& graphic, CommandBuffer&, size_t = 0, size_t = 0 ); void destroy(); }; struct UF_API Material { @@ -127,8 +128,8 @@ namespace ext { Pipeline& getPipeline( GraphicDescriptor& descriptor ); void updatePipelines(); - void record( GLhandle(VkCommandBuffer) commandBuffer, size_t pass = 0, size_t draw = 0 ); - void record( GLhandle(VkCommandBuffer) commandBuffer, GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0 ); + void record( CommandBuffer& commandBuffer, size_t pass = 0, size_t draw = 0 ); + void record( CommandBuffer& commandBuffer, GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0 ); bool hasStorage( const std::string& name ); Buffer* getStorageBuffer( const std::string& name ); diff --git a/engine/inc/uf/ext/opengl/graphic.inl b/engine/inc/uf/ext/opengl/graphic.inl index cf663a5f..8a3103c6 100644 --- a/engine/inc/uf/ext/opengl/graphic.inl +++ b/engine/inc/uf/ext/opengl/graphic.inl @@ -12,8 +12,8 @@ void ext::opengl::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t int32_t vertexBuffer = -1; int32_t indexBuffer = -1; for ( size_t i = 0; i < buffers.size(); ++i ) { - if ( buffers[i].usageFlags & 1 ) vertexBuffer = i; - if ( buffers[i].usageFlags & 2 ) indexBuffer = i; + if ( buffers[i].usageFlags & uf::renderer::enums::Buffer::VERTEX ) vertexBuffer = i; + if ( buffers[i].usageFlags & uf::renderer::enums::Buffer::INDEX ) indexBuffer = i; } if ( vertexBuffer > 0 && indexBuffer > 0 ) { @@ -31,10 +31,12 @@ void ext::opengl::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t } } // can't reuse buffers, re-create buffers + /* { for ( auto& buffer : buffers ) buffer.destroy(); buffers.clear(); } + */ } descriptor.geometry = mesh; @@ -43,11 +45,11 @@ void ext::opengl::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t initializeBuffer( (void*) mesh.vertices.data(), mesh.vertices.size() * mesh.sizes.vertex, - /*VK_BUFFER_USAGE_VERTEX_BUFFER_BIT*/ 1 + uf::renderer::enums::Buffer::VERTEX ); initializeBuffer( (void*) mesh.indices.data(), mesh.indices.size() * mesh.sizes.indices, - /*VK_BUFFER_USAGE_INDEX_BUFFER_BIT*/ 2 + uf::renderer::enums::Buffer::INDEX ); } \ 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 926e7979..16670db6 100644 --- a/engine/inc/uf/ext/opengl/ogl.h +++ b/engine/inc/uf/ext/opengl/ogl.h @@ -1,25 +1,39 @@ #pragma once #include -#include #if defined(UF_ENV_WINDOWS) // The Visual C++ version of gl.h uses WINGDIAPI and APIENTRY but doesn't define them #ifdef _MSC_VER #include #endif + #include #include #include #include + #include #elif defined(UF_ENV_LINUX) || defined(UF_ENV_FREEBSD) #include #include #elif defined(UF_ENV_MACOS) #include #include +#elif defined(UF_ENV_DREAMCAST) + #include + #include + #include + + #define GL_NONE 0 + #define GLsizeiptr GLsizei #endif -#include #define GL_NULL_HANDLE NULL #define GL_WHOLE_SIZE -1 #define GLhandle(x) size_t -#define GLenumerator(x) 0 \ No newline at end of file +#define GLenumerator(x) 0 + +#define GL_DEBUG_MESSAGE(...)\ + uf::iostream << "[" << __FUNCTION__ << "@" << __FILE__ ":" << __LINE__ << "] " << __VA_ARGS__ << "\n" + +#define GL_VALIDATION_MESSAGE(...)\ + if ( ext::opengl::settings::validation ) GL_DEBUG_MESSAGE(__VA_ARGS__); + \ No newline at end of file diff --git a/engine/inc/uf/ext/opengl/rendermode.h b/engine/inc/uf/ext/opengl/rendermode.h index 52132db6..4ab37543 100644 --- a/engine/inc/uf/ext/opengl/rendermode.h +++ b/engine/inc/uf/ext/opengl/rendermode.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace ext { @@ -20,7 +21,7 @@ namespace ext { GLhandle(VkSemaphore) renderCompleteSemaphore; std::vector fences; - typedef std::vector commands_container_t; + typedef CommandBuffer commands_container_t; std::thread::id mostRecentCommandPoolId; uf::ThreadUnique commands; diff --git a/engine/inc/uf/ext/opengl/rendermodes/base.h b/engine/inc/uf/ext/opengl/rendermodes/base.h index 15c97169..014d35d0 100644 --- a/engine/inc/uf/ext/opengl/rendermodes/base.h +++ b/engine/inc/uf/ext/opengl/rendermodes/base.h @@ -4,7 +4,7 @@ namespace ext { namespace opengl { - struct UF_API BaseRenderMode : RenderMode { + struct UF_API BaseRenderMode : public RenderMode { // virtual ~RenderMode(); // RAII virtual const std::string getType() const; diff --git a/engine/inc/uf/ext/opengl/rendermodes/compute.h b/engine/inc/uf/ext/opengl/rendermodes/compute.h index bcce4dbd..55f9a618 100644 --- a/engine/inc/uf/ext/opengl/rendermodes/compute.h +++ b/engine/inc/uf/ext/opengl/rendermodes/compute.h @@ -5,7 +5,7 @@ namespace ext { namespace opengl { - struct UF_API ComputeRenderMode : RenderMode { + struct UF_API ComputeRenderMode : public RenderMode { ext::opengl::Graphic blitter, compute; pod::Vector2ui dispatchSize = { 32, 32 }; diff --git a/engine/inc/uf/ext/opengl/rendermodes/deferred.h b/engine/inc/uf/ext/opengl/rendermodes/deferred.h index df363673..2f0e54f0 100644 --- a/engine/inc/uf/ext/opengl/rendermodes/deferred.h +++ b/engine/inc/uf/ext/opengl/rendermodes/deferred.h @@ -5,7 +5,7 @@ namespace ext { namespace opengl { - struct UF_API DeferredRenderMode : RenderMode { + struct UF_API DeferredRenderMode : public RenderMode { ext::opengl::Graphic blitter; // RAII diff --git a/engine/inc/uf/ext/opengl/rendermodes/rendertarget.h b/engine/inc/uf/ext/opengl/rendermodes/rendertarget.h index 3f78d16c..a02bab97 100644 --- a/engine/inc/uf/ext/opengl/rendermodes/rendertarget.h +++ b/engine/inc/uf/ext/opengl/rendermodes/rendertarget.h @@ -5,7 +5,7 @@ namespace ext { namespace opengl { - struct UF_API RenderTargetRenderMode : RenderMode { + struct UF_API RenderTargetRenderMode : public RenderMode { ext::opengl::Graphic blitter; // const std::string getTarget() const; diff --git a/engine/inc/uf/ext/openvr/openvr.h b/engine/inc/uf/ext/openvr/openvr.h index fb3cb297..5f6bf9fa 100644 --- a/engine/inc/uf/ext/openvr/openvr.h +++ b/engine/inc/uf/ext/openvr/openvr.h @@ -1,10 +1,13 @@ #pragma once #include + +#if UF_USE_OPENVR #include #include #include #include + #ifdef USE_OPENVR_MINGW #include #else @@ -77,4 +80,5 @@ namespace ext { pod::Matrix4t<> UF_API eyeMatrix( vr::Hmd_Eye ); */ } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/ultralight/ultralight.h b/engine/inc/uf/ext/ultralight/ultralight.h index 93392a16..d6d9e3da 100644 --- a/engine/inc/uf/ext/ultralight/ultralight.h +++ b/engine/inc/uf/ext/ultralight/ultralight.h @@ -1,11 +1,13 @@ #pragma once #include +#if UF_USE_ULTRALIGHT #include #include #include #include +#include #include @@ -41,4 +43,5 @@ namespace ext { void UF_API input( pod::HTML&, const std::string& ); uf::Image UF_API capture( pod::HTML& ); } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/ext/vorbis/vorbis.h b/engine/inc/uf/ext/vorbis/vorbis.h index 40890351..e1cbd1b5 100644 --- a/engine/inc/uf/ext/vorbis/vorbis.h +++ b/engine/inc/uf/ext/vorbis/vorbis.h @@ -1,7 +1,7 @@ #pragma once #include -#if defined(UF_USE_VORBIS) +#if UF_USE_VORBIS #include diff --git a/engine/inc/uf/ext/vulkan/graphic.inl b/engine/inc/uf/ext/vulkan/graphic.inl index 46b1318f..8fd4f1ca 100644 --- a/engine/inc/uf/ext/vulkan/graphic.inl +++ b/engine/inc/uf/ext/vulkan/graphic.inl @@ -12,8 +12,8 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t int32_t vertexBuffer = -1; int32_t indexBuffer = -1; for ( size_t i = 0; i < buffers.size(); ++i ) { - if ( buffers[i].usageFlags & VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ) vertexBuffer = i; - if ( buffers[i].usageFlags & VK_BUFFER_USAGE_INDEX_BUFFER_BIT ) indexBuffer = i; + if ( buffers[i].usageFlags & uf::renderer::enums::Buffer::VERTEX ) vertexBuffer = i; + if ( buffers[i].usageFlags & uf::renderer::enums::Buffer::INDEX ) indexBuffer = i; } if ( vertexBuffer > 0 && indexBuffer > 0 ) { @@ -31,10 +31,12 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t } } // can't reuse buffers, re-create buffers + /* { for ( auto& buffer : buffers ) buffer.destroy(); buffers.clear(); } + */ } descriptor.geometry = mesh; @@ -43,11 +45,11 @@ void ext::vulkan::Graphic::initializeGeometry( uf::BaseMesh& mesh, size_t initializeBuffer( (void*) mesh.vertices.data(), mesh.vertices.size() * mesh.sizes.vertex, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT + uf::renderer::enums::Buffer::VERTEX ); initializeBuffer( (void*) mesh.indices.data(), mesh.indices.size() * mesh.sizes.indices, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT + uf::renderer::enums::Buffer::INDEX ); } \ No newline at end of file diff --git a/engine/inc/uf/macros.h b/engine/inc/uf/macros.h index 4723bc89..201f8371 100644 --- a/engine/inc/uf/macros.h +++ b/engine/inc/uf/macros.h @@ -16,4 +16,5 @@ if ( __VA_ARGS__ (time = TOKEN_PASTE(TIMER, __LINE__)(x)) >= x ) #define UF_DEBUG 1 -#define UF_DEBUG_PRINT() if ( UF_DEBUG ) uf::iostream << __FILE__ << ":" << __FUNCTION__ << "@" << __LINE__ << "\n"; \ No newline at end of file +//#define UF_DEBUG_PRINT() if ( UF_DEBUG ) uf::iostream << __FILE__ << ":" << __FUNCTION__ << "@" << __LINE__ << "\n"; +#define UF_DEBUG_PRINT() if ( UF_DEBUG ) std::cout << __FILE__ << ":" << __FUNCTION__ << "@" << __LINE__ << std::endl; \ No newline at end of file diff --git a/engine/inc/uf/spec/context/context.h b/engine/inc/uf/spec/context/context.h index 23e7ffc4..89075d44 100644 --- a/engine/inc/uf/spec/context/context.h +++ b/engine/inc/uf/spec/context/context.h @@ -6,8 +6,4 @@ // include universal #include "universal.h" // defines which implementation to use -#include UF_ENV_HEADER - -#if UF_USE_SFML - #include "unknown.h" -#endif \ No newline at end of file +#include UF_ENV_HEADER \ No newline at end of file diff --git a/engine/inc/uf/spec/context/dreamcast.h b/engine/inc/uf/spec/context/dreamcast.h new file mode 100644 index 00000000..c212e64b --- /dev/null +++ b/engine/inc/uf/spec/context/dreamcast.h @@ -0,0 +1,8 @@ +#pragma once + +#include "universal.h" +#include "unknown.h" + +namespace spec { + typedef spec::unknown::Context Context; +} \ No newline at end of file diff --git a/engine/inc/uf/spec/context/universal.h b/engine/inc/uf/spec/context/universal.h index 2a07a094..116cd421 100644 --- a/engine/inc/uf/spec/context/universal.h +++ b/engine/inc/uf/spec/context/universal.h @@ -22,23 +22,12 @@ namespace spec { typedef spec::Window window_t; #endif struct Settings { - unsigned int depthBits; - unsigned int stencilBits; - unsigned int bitsPerPixel; - unsigned int antialiasingLevel; - unsigned int majorVersion; - unsigned int minorVersion; - - explicit Settings(unsigned int depth = 24, unsigned int stencil = 4, unsigned int antialiasing = 0, unsigned int bitsPerPixel = 8, unsigned int major = 2, unsigned int minor = 0) : - depthBits (depth), - stencilBits (stencil), - bitsPerPixel (bitsPerPixel), - antialiasingLevel (antialiasing), - majorVersion (major), - minorVersion (minor) - { - - } + uint32_t depthBits = 24; + uint32_t stencilBits = 4; + uint32_t bitsPerPixel = 8; + uint32_t antialiasingLevel = 0; + uint32_t majorVersion = 2; + uint32_t minorVersion = 0; }; protected: Context::window_t::handle_t m_window; diff --git a/engine/inc/uf/spec/dreamcast.h b/engine/inc/uf/spec/dreamcast.h new file mode 100644 index 00000000..22e2ca8f --- /dev/null +++ b/engine/inc/uf/spec/dreamcast.h @@ -0,0 +1,11 @@ +#pragma once + +#include +// In the event some fool includes this file directly +#include "universal.h" +// Windows-specific stuffs +#ifdef UF_ENV_DREAMCAST + +// Headers + +#endif \ No newline at end of file diff --git a/engine/inc/uf/spec/time/dreamcast.h b/engine/inc/uf/spec/time/dreamcast.h new file mode 100644 index 00000000..16c85e3e --- /dev/null +++ b/engine/inc/uf/spec/time/dreamcast.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "universal.h" + +#if UF_ENV_DREAMCAST + +namespace spec { + namespace dreamcast { + class UF_API Time : public spec::uni::Time { + public: + static Time::exp_t unit; + }; + } + typedef dreamcast::Time Time; + extern UF_API Time time; +} + +#endif \ No newline at end of file diff --git a/engine/inc/uf/spec/universal.h b/engine/inc/uf/spec/universal.h index e14e7c66..dc2aa024 100644 --- a/engine/inc/uf/spec/universal.h +++ b/engine/inc/uf/spec/universal.h @@ -28,7 +28,6 @@ #endif */ - #include UF_ENV_HEADER // define some universal shit diff --git a/engine/inc/uf/spec/window/dreamcast.h b/engine/inc/uf/spec/window/dreamcast.h new file mode 100644 index 00000000..09035380 --- /dev/null +++ b/engine/inc/uf/spec/window/dreamcast.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include "universal.h" +#include + +#if UF_ENV_DREAMCAST +namespace spec { + namespace dreamcast { + class UF_API Window : public spec::uni::Window { + public: + typedef size_t handle_t; + protected: + spec::dreamcast::Window::handle_t m_handle; + // size_t m_cursor; + // size_t m_icon; + + spec::dreamcast::Window::vector_t m_lastSize; + bool m_keyRepeatEnabled; + bool m_resizing; + bool m_mouseInside; + bool m_mouseGrabbed; + uint16_t m_surrogate; + bool m_syncParse; + bool m_asyncParse; + public: + // C-tors + UF_API Window(); + UF_API Window( spec::dreamcast::Window::handle_t ); + UF_API Window( const spec::dreamcast::Window::vector_t& size, const spec::dreamcast::Window::title_t& title = L"Window" ); + /*virtual*/ void UF_API create( const spec::dreamcast::Window::vector_t& size, const spec::dreamcast::Window::title_t& title = L"Window" ); + // D-tors + /*virtual*/ ~Window(); + void UF_API terminate(); + // Gets + spec::dreamcast::Window::handle_t UF_API getHandle() const; + /*virtual*/ spec::dreamcast::Window::vector_t UF_API getPosition() const; + /*virtual*/ spec::dreamcast::Window::vector_t UF_API getSize() const; + /*virtual*/ size_t UF_API getRefreshRate() const; + // Attribute modifiers + /*virtual*/ void UF_API setPosition( const spec::dreamcast::Window::vector_t& position ); + /*virtual*/ void UF_API centerWindow(); + /*virtual*/ void UF_API setMousePosition( const spec::dreamcast::Window::vector_t& position ); + /*virtual*/ spec::dreamcast::Window::vector_t UF_API getMousePosition(); + /*virtual*/ void UF_API setSize( const spec::dreamcast::Window::vector_t& size ); + /*virtual*/ void UF_API setTitle( const spec::dreamcast::Window::title_t& title ); + /*virtual*/ void UF_API setIcon( const spec::dreamcast::Window::vector_t& size, uint8_t* pixels ); + /*virtual*/ void UF_API setVisible( bool visibility ); + /*virtual*/ void UF_API setCursorVisible( bool visibility ); + /*virtual*/ void UF_API setKeyRepeatEnabled( bool state ); + /*virtual*/ void UF_API setMouseGrabbed(bool state); + + /*virtual*/ void UF_API requestFocus(); + /*virtual*/ bool UF_API hasFocus() const; + // Update + /*virtual*/ void UF_API processEvents(); + static /*virtual*/ bool UF_API isKeyPressed(const std::string&); + bool UF_API pollEvents( bool block = false ); + // Win32 specific functions + void UF_API registerWindowClass(); + void UF_API processEvent(/*UINT message, WPARAM wParam, LPARAM lParam*/); + void UF_API grabMouse(bool state); + + 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; +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/audio/audio.h b/engine/inc/uf/utils/audio/audio.h index 93e0d382..6f19e88d 100644 --- a/engine/inc/uf/utils/audio/audio.h +++ b/engine/inc/uf/utils/audio/audio.h @@ -2,9 +2,17 @@ #include -#if defined(UF_USE_OPENAL) - +#if UF_USE_OPENAL #include +#else + namespace ext { + namespace al { + typedef size_t Source; + typedef size_t Buffer; + } + } + typedef float ALfloat; +#endif #include #include @@ -99,6 +107,4 @@ namespace uf { void cleanup( bool = false ); }; -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/engine/inc/uf/utils/graphic/descriptor.h b/engine/inc/uf/utils/graphic/descriptor.h index 629fdf40..62c2a69a 100644 --- a/engine/inc/uf/utils/graphic/descriptor.h +++ b/engine/inc/uf/utils/graphic/descriptor.h @@ -13,6 +13,7 @@ namespace ext { struct /*UF_API*/ VertexDescriptor { ext::RENDERER::enums::Format::type_t format; // VK_FORMAT_R32G32B32_SFLOAT size_t offset; // offsetof(Vertex, position) + std::string name; }; } } @@ -68,4 +69,13 @@ namespace ext { } } -#undef UF_RENDERER \ No newline at end of file +#undef UF_RENDERER +#define UF_VERTEX_DESCRIPTION( TYPE, FORMAT, ATTRIBUTE ) {\ + uf::renderer::enums::Format::FORMAT,\ + offsetof(TYPE, ATTRIBUTE),\ + #ATTRIBUTE\ + }, + +#define UF_VERTEX_DESCRIPTOR( TYPE, ... )\ + std::vector TYPE::descriptor = { __VA_ARGS__ }; + \ No newline at end of file diff --git a/engine/inc/uf/utils/graphic/mesh.h b/engine/inc/uf/utils/graphic/mesh.h index 5f460924..6eb1db96 100644 --- a/engine/inc/uf/utils/graphic/mesh.h +++ b/engine/inc/uf/utils/graphic/mesh.h @@ -6,7 +6,10 @@ #include #include + +#if UF_USE_MESHOPTIMIZER #include +#endif #if UF_USE_VULKAN namespace uf { diff --git a/engine/inc/uf/utils/graphic/mesh.inl b/engine/inc/uf/utils/graphic/mesh.inl index 72d99418..4b93df01 100644 --- a/engine/inc/uf/utils/graphic/mesh.inl +++ b/engine/inc/uf/utils/graphic/mesh.inl @@ -78,6 +78,7 @@ uf::BaseMesh uf::BaseMesh::simplify( float threshold ) { } template void uf::BaseMesh::optimize( size_t o ) { +#if UF_USE_MESHOPTIMIZER // generate indices auto vertices = std::move( this->vertices ); U indices = vertices.size(); @@ -102,6 +103,11 @@ void uf::BaseMesh::optimize( size_t o ) { if ( o >= 3 ) { meshopt_optimizeVertexFetch(&this->vertices[0], &this->indices[0], this->indices.size(), &this->vertices[0], this->vertices.size(), sizeof(T)); } +#else + this->indices.clear(); + this->indices.reserve(vertices.size()); + for ( size_t i = 0; i < vertices.size(); ++i ) + this->indices.emplace_back(i); /* old nasty way @@ -119,4 +125,5 @@ void uf::BaseMesh::optimize( size_t o ) { mesh.indices.push_back( unique[vertex] ); } */ +#endif } \ No newline at end of file diff --git a/engine/inc/uf/utils/serialize/serializer.h b/engine/inc/uf/utils/serialize/serializer.h index 9facc956..59766c40 100644 --- a/engine/inc/uf/utils/serialize/serializer.h +++ b/engine/inc/uf/utils/serialize/serializer.h @@ -18,7 +18,9 @@ namespace uf { Serializer( const std::string& str = "{}" ); Serializer( const ext::json::base_value& ); Serializer( const ext::json::Value& ); + #if UF_USE_LUA Serializer( const sol::table& ); + #endif Serializer::output_t serialize( bool pretty = false ) const; void deserialize( const std::string& ); @@ -69,7 +71,9 @@ namespace uf { uf::Serializer& operator=( const std::string& str ); uf::Serializer& operator=( const ext::json::base_value& json ); uf::Serializer& operator=( const ext::json::Value& json ); + #if UF_USE_LUA uf::Serializer& operator=( const sol::table& json ); + #endif uf::Serializer& operator<<( const std::string& str ); uf::Serializer& operator>>( std::string& str ); const uf::Serializer& operator>>( std::string& str ) const; diff --git a/engine/inc/uf/utils/string/io.h b/engine/inc/uf/utils/string/io.h index 7256bf29..bf5fe4e6 100644 --- a/engine/inc/uf/utils/string/io.h +++ b/engine/inc/uf/utils/string/io.h @@ -6,6 +6,8 @@ namespace uf { namespace io { + extern UF_API const std::string root; + std::string UF_API absolute( const std::string& ); std::string UF_API filename( const std::string& ); std::string UF_API extension( const std::string& ); diff --git a/engine/inc/uf/utils/text/glyph.h b/engine/inc/uf/utils/text/glyph.h index 45806404..5b011bf9 100644 --- a/engine/inc/uf/utils/text/glyph.h +++ b/engine/inc/uf/utils/text/glyph.h @@ -1,7 +1,7 @@ #pragma once #include - +#if UF_USE_FREETYPE #include #include @@ -47,4 +47,5 @@ namespace uf { void useSdf( bool = true ); void setSpread( int ); }; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/userdata/userdata.inl b/engine/inc/uf/utils/userdata/userdata.inl index aa02f854..ebfaf712 100644 --- a/engine/inc/uf/utils/userdata/userdata.inl +++ b/engine/inc/uf/utils/userdata/userdata.inl @@ -39,7 +39,11 @@ pod::Userdata* uf::userdata::create( uf::MemoryPool& requestedMemoryPool, const #include template T& uf::userdata::get( pod::Userdata* userdata, bool validate ) { - if ( validate && !uf::userdata::is( userdata ) ) throw std::logic_error("Userdata size|type mismatch"); +#if !UF_NO_EXCEPTIONS + if ( validate && !uf::userdata::is( userdata ) ) { + throw std::logic_error("Userdata size|type mismatch"); + } +#endif union { uint8_t* original; T* casted; @@ -49,7 +53,11 @@ T& uf::userdata::get( pod::Userdata* userdata, bool validate ) { } template const T& uf::userdata::get( const pod::Userdata* userdata, bool validate ) { - if ( validate && !uf::userdata::is( userdata ) ) throw std::logic_error("Userdata size|type mismatch"); +#if !UF_NO_EXCEPTIONS + if ( validate && !uf::userdata::is( userdata ) ) { + throw std::logic_error("Userdata size|type mismatch"); + } +#endif union { const uint8_t* original; const T* casted; diff --git a/engine/inc/uf/utils/window/window.h b/engine/inc/uf/utils/window/window.h index bcb01afb..d33e4c06 100644 --- a/engine/inc/uf/utils/window/window.h +++ b/engine/inc/uf/utils/window/window.h @@ -53,6 +53,8 @@ namespace uf { /*virtual*/ bool UF_API_CALL pollEvents(bool block = false); /*virtual*/ bool UF_API_CALL setActive( bool active = true ); /*virtual*/ void UF_API_CALL display(); + /*virtual*/ Window::window_t* UF_API_CALL getHandle(); + /*virtual*/ const Window::window_t* UF_API_CALL getHandle() const; }; } #elif UF_USE_SFML diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index c6aeb67a..5b6815bb 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -99,7 +99,7 @@ std::string uf::Asset::cache( const std::string& uri, const std::string& hash ) std::string extension = uf::io::extension( uri ); if ( uri.substr(0,5) == "https" ) { std::string hash = hashed( uri ); - std::string cached = "./data/cache/" + hash + "." + extension; + std::string cached = uf::io::root + "/cache/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( uri, cached, hash ) ) { uf::iostream << "Failed to preload `" + uri + "` (`" + cached + "`): HTTP error" << "\n"; return ""; @@ -122,7 +122,7 @@ std::string uf::Asset::load( const std::string& uri, const std::string& hash ) { std::string extension = uf::io::extension( uri ); if ( uri.substr(0,5) == "https" ) { std::string hash = hashed( uri ); - std::string cached = "./data/cache/" + hash + "." + extension; + std::string cached = uf::io::root + "/cache/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( uri, cached, hash ) ) { uf::iostream << "Failed to load `" + uri + "` (`" + cached + "`): HTTP error" << "\n"; return ""; @@ -158,9 +158,11 @@ std::string uf::Asset::load( const std::string& uri, const std::string& hash ) { } else if ( extension == "json" ) { UF_ASSET_REGISTER(uf::Serializer) asset.readFromFile(filename); + #if UF_USE_LUA } else if ( extension == "lua" ) { UF_ASSET_REGISTER(pod::LuaScript) asset = ext::lua::script( filename ); + #endif } else if ( extension == "gltf" || extension == "glb" ) { UF_ASSET_REGISTER(pod::Graph) auto& metadata = this->getComponent(); diff --git a/engine/src/engine/asset/masterdata.cpp b/engine/src/engine/asset/masterdata.cpp index 5098e1fa..bb17f9d6 100644 --- a/engine/src/engine/asset/masterdata.cpp +++ b/engine/src/engine/asset/masterdata.cpp @@ -2,7 +2,7 @@ #include //std::string uf::MasterData::root = "https://el..xyz/mastertable/get/%TABLE%/%KEY%?.json"; -std::string uf::MasterData::root = "./data/master/%TABLE%.json"; +std::string uf::MasterData::root = uf::io::root + "/master/%TABLE%.json"; uf::Asset uf::MasterData::assetLoader; uf::Serializer uf::MasterData::load( const std::string& table, size_t key ) { diff --git a/engine/src/engine/object/behavior.cpp b/engine/src/engine/object/behavior.cpp index 1e603947..34ec2570 100644 --- a/engine/src/engine/object/behavior.cpp +++ b/engine/src/engine/object/behavior.cpp @@ -33,6 +33,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { } } +#if UF_USE_BULLET if ( ext::json::isObject(metadata["system"]["physics"]) ) { float mass = metadata["system"]["physics"]["mass"].as(); if ( metadata["system"]["physics"]["type"].as() == "BoundingBox" ) { @@ -58,6 +59,7 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) { } } } +#endif this->addHook( "object:TransformReferenceController.%UID%", [&](ext::json::Value& json){ auto& transform = this->getComponent>(); diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index ebdaf32e..d3ff60c8 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -42,7 +42,11 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { { pod::Graph* graphPointer = NULL; + #if UF_NO_EXCEPTIONS + graphPointer = &assetLoader.get(filename); + #else try { graphPointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !graphPointer ) return; auto& graph = this->getComponent(); graph = std::move( *graphPointer ); @@ -98,15 +102,19 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); const uf::Image* imagePointer = NULL; + #if UF_NO_EXCEPTIONS + imagePointer = &assetLoader.get(filename); + #else try { imagePointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !imagePointer ) continue; uf::Image image = *imagePointer; auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); } - #if UF_USE_VULKAN graphic.process = true; + #if UF_USE_VULKAN { auto& shader = graphic.material.getShader("vertex"); struct SpecializationConstant { diff --git a/engine/src/engine/object/behaviors/lua.cpp b/engine/src/engine/object/behaviors/lua.cpp index 722a6ccc..9bb42c5d 100644 --- a/engine/src/engine/object/behaviors/lua.cpp +++ b/engine/src/engine/object/behaviors/lua.cpp @@ -12,10 +12,10 @@ #include #include - UF_BEHAVIOR_REGISTER_CPP(uf::LuaBehavior) #define this (&self) void uf::LuaBehavior::initialize( uf::Object& self ) { +#if UF_USE_LUA this->addHook( "asset:Load.%UID%", [&](ext::json::Value& json){ std::string filename = json["filename"].as(); @@ -32,6 +32,7 @@ void uf::LuaBehavior::initialize( uf::Object& self ) { return; }); +#endif } void uf::LuaBehavior::destroy( uf::Object& self ) { diff --git a/engine/src/ext/bullet/bullet.cpp b/engine/src/ext/bullet/bullet.cpp index a116449b..d4304531 100644 --- a/engine/src/ext/bullet/bullet.cpp +++ b/engine/src/ext/bullet/bullet.cpp @@ -1,4 +1,5 @@ #include +#if UF_USE_BULLET #include #include @@ -72,78 +73,8 @@ namespace ext { } } - -/* -static bool fixMeshNormal( btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0 ) { - const btTriangleShape* tri_shape = static_cast(colObj0Wrap->getCollisionShape()); - btVector3 tri_normal; - tri_shape->calcNormal(cp.m_normalWorldOnB); - cp.m_normalWorldOnB = colObj0Wrap->getWorldTransform().getBasis() * cp.m_normalWorldOnB; - - // Reproject collision point along normal. - cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; - cp.m_localPointB = colObj0Wrap->getWorldTransform().invXform(cp.m_positionWorldOnB); - return true; -} - -btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p) { - btVector3 diff = p - from; - btVector3 v = to - from; - btScalar t = v.dot(diff); - if (t > 0) { - btScalar dotVV = v.dot(v); - if (t < dotVV) diff -= (t / dotVV) * v; - else diff -= v; - } - return diff.dot(diff); -} - -bool ProcessHeightfieldCollision(btManifoldPoint& cp, btVector3& cppos, btHeightfieldTerrainShape* heightfield_shape, btTriangleShape* triangle_shape, int part_id, int index) { - // This can be classified as an edge collision if the contact normal differs from the triangle normal - btVector3 triangle_normal; - triangle_shape->calcNormal(triangle_normal); - if (cp.m_normalWorldOnB.dot(triangle_normal) < 1 - SIMD_EPSILON) { - // Need to find the edge that matches this contact normal - int ev0 = -1, ev1 = -1; - btVector3* vertices = &triangle_shape->getVertexPtr(0); - for (int v0 = 2, v1 = 0; v1 < 3; v0 = v1, v1++) { - float d = SegmentSqrDistance(vertices[v0], vertices[v1], cppos); - if (d < SIMD_EPSILON) { - ev0 = v0; - ev1 = v1; - } - } - - // Leave contact point alone if the edge can't be found - if (ev0 == -1) return true; - - // Get the triangle that shares this edge. If this is a boundary edge, the contact normal is - // perfectly valid - btVector3 neighbour_vertices[3]; - if (!heightfield_shape->getNeighbourTriangle(part_id, index, ev0, neighbour_vertices)) return true; - - // If the two faces have similar normals, use the face normal and ignore the edge normal - btVector3 other_normal = (neighbour_vertices[1]-neighbour_vertices[0]).cross(neighbour_vertices[2]-neighbour_vertices[0]); - other_normal.normalize(); - if (triangle_normal.dot(other_normal) > 1 - SIMD_EPSILON) cp.m_normalWorldOnB = triangle_normal; - } - - return true; -} -*/ +#if !UF_ENV_DREAMCAST static bool contactCallback(btManifoldPoint &ManifoldPoint, const btCollisionObjectWrapper *Object0, int PartID0, int Index0, const btCollisionObjectWrapper *Object1, int PartID1, int Index1) { -/* - if ( colObj0Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE ) { - fixMeshNormal( cp, colObj0Wrap, partId0, index0 ); - } - if ( colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE ) { - fixMeshNormal( cp, colObj1Wrap, partId1, index1 ); - } - btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1,index1); - //btAdjustInternalEdgeContacts(cp,colObj1Wrap,colObj0Wrap, partId1,index1, BT_TRIANGLE_CONVEX_BACKFACE_MODE); - //btAdjustInternalEdgeContacts(cp,colObj1Wrap,colObj0Wrap, partId1,index1, BT_TRIANGLE_CONVEX_DOUBLE_SIDED+BT_TRIANGLE_CONCAVE_DOUBLE_SIDED); -*/ - if( Object1->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE ) return false; pod::Vector3f Before = { @@ -153,37 +84,16 @@ static bool contactCallback(btManifoldPoint &ManifoldPoint, const btCollisionObj }; btAdjustInternalEdgeContacts(ManifoldPoint, Object1, Object0, PartID1, Index1); btAdjustInternalEdgeContacts(ManifoldPoint, Object0, Object1, PartID0, Index0); -/* - if ( Object0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE ) { - fixMeshNormal( ManifoldPoint, Object0, PartID0, Index0 ); - } - if ( Object1->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE ) { - fixMeshNormal( ManifoldPoint, Object1, PartID1, Index1 ); - } -*/ + pod::Vector3f After = { ManifoldPoint.m_normalWorldOnB.getX(), ManifoldPoint.m_normalWorldOnB.getY(), ManifoldPoint.m_normalWorldOnB.getZ(), }; -// if ( Before != After ) std::cout << "Before: " << uf::string::toString(Before) << "\tafter: " << uf::string::toString(After) << std::endl; - return false; } - -/* -void FixMeshNormal(btManifoldPoint& cp, const btCollisionObject* colObj0, int , int ) { - const btTriangleMeshShape* tri_shape = static_cast(colObj0->getCollisionShape()); - btVector3 tri_normal; - tri_shape->calcNormal(cp.m_normalWorldOnB); - cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis() * cp.m_normalWorldOnB; - - // Reproject collision point along normal. - cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; - cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); -} -*/ +#endif void ext::bullet::initialize() { ext::bullet::collisionConfiguration = new btDefaultCollisionConfiguration(); @@ -193,7 +103,9 @@ void ext::bullet::initialize() { ext::bullet::dynamicsWorld = new btDiscreteDynamicsWorld(ext::bullet::dispatcher, ext::bullet::overlappingPairCache, ext::bullet::solver, ext::bullet::collisionConfiguration); ext::bullet::dynamicsWorld->setGravity(btVector3(0, -9.81, 0)); +#if !UF_ENV_DREAMCAST gContactAddedCallback = contactCallback; +#endif ext::bullet::debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); ext::bullet::dynamicsWorld->setDebugDrawer(&ext::bullet::debugDrawer); @@ -485,8 +397,8 @@ void UF_API ext::bullet::debugDraw( uf::Object& object ) { graphic.material.device = &uf::renderer::device; graphic.descriptor.cullMode = uf::renderer::enums::CullMode::NONE; - graphic.material.attachShader("./data/shaders/base.colored.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader("./data/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root + "/shaders/base.colored.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); graphic.initialize(); graphic.initializeGeometry( mesh, 0 ); @@ -499,4 +411,5 @@ void UF_API ext::bullet::debugDraw( uf::Object& object ) { graphic.initializeGeometry( mesh, 0 ); graphic.getPipeline().update( graphic ); } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/freetype/freetype.cpp b/engine/src/ext/freetype/freetype.cpp index 81ad4285..5e9b20d7 100644 --- a/engine/src/ext/freetype/freetype.cpp +++ b/engine/src/ext/freetype/freetype.cpp @@ -1,5 +1,6 @@ -#include #include +#if UF_USE_FREETYPE +#include ext::freetype::Library ext::freetype::library; @@ -103,4 +104,5 @@ UF_API std::string ext::freetype::getError( int error ) { } return ft_errors[0].err_msg; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index e9e2683a..81859c2a 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -295,7 +295,7 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t image.loadFromBuffer( &i.image[0], {i.width, i.height}, 8, i.component, true ); if ( graph.metadata["dump images"].as() ) { - std::string target = "./data/dump/" + uf::string::sha256(filename) + "." + std::to_string(_i++) + ".png"; + std::string target = uf::io::root + "/dump/" + uf::string::sha256(filename) + "." + std::to_string(_i++) + ".png"; image.save( target ); } } diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 9b50f35a..cd3191ad 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -58,18 +58,18 @@ namespace { if ( graph.mode & ext::gltf::LoadMode::LOAD ) { if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { - graphic.material.attachShader("./data/shaders/gltf.skinned.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/gltf.skinned.vert.spv", uf::renderer::enums::Shader::VERTEX); } else { - graphic.material.attachShader("./data/shaders/gltf.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/gltf.vert.spv", uf::renderer::enums::Shader::VERTEX); } } else { if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { - graphic.material.attachShader("./data/shaders/gltf.skinned.instanced.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/gltf.skinned.instanced.vert.spv", uf::renderer::enums::Shader::VERTEX); } else { - graphic.material.attachShader("./data/shaders/gltf.instanced.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root + "/shaders/gltf.instanced.vert.spv", uf::renderer::enums::Shader::VERTEX); } } - graphic.material.attachShader("./data/shaders/gltf.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root + "/shaders/gltf.frag.spv", uf::renderer::enums::Shader::FRAGMENT); { auto& shader = graphic.material.getShader("vertex"); struct SpecializationConstant { @@ -278,6 +278,7 @@ void uf::graph::process( pod::Graph& graph ) { auto& info = graph.metadata["tags"][nodeName]; if ( info["collision"].is() ) { std::string type = info["collision"].as(); + #if UF_USE_BULLET if ( type == "static mesh" ) { bool applyTransform = false; //!(graph.mode & ext::gltf::LoadMode::TRANSFORM); auto& collider = ext::bullet::create( entity->as(), mesh, applyTransform, 1 ); @@ -294,6 +295,7 @@ void uf::graph::process( pod::Graph& graph ) { } else if ( type == "bounding box" ) { } + #endif } } }); diff --git a/engine/src/ext/gltf/mesh.cpp b/engine/src/ext/gltf/mesh.cpp index 0f008451..8e0cf713 100644 --- a/engine/src/ext/gltf/mesh.cpp +++ b/engine/src/ext/gltf/mesh.cpp @@ -1,55 +1,19 @@ #include #include -std::vector ext::gltf::mesh::ID::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(ext::gltf::mesh::ID, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(ext::gltf::mesh::ID, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(ext::gltf::mesh::ID, normal) - }, - { - uf::renderer::enums::Format::R32G32B32A32_SFLOAT, - offsetof(ext::gltf::mesh::ID, tangent) - }, - { - uf::renderer::enums::Format::R32G32_SINT, - offsetof(ext::gltf::mesh::ID, id) - } -}; -std::vector ext::gltf::mesh::Skinned::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, normal) - }, - { - uf::renderer::enums::Format::R32G32B32A32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, tangent) - }, - { - uf::renderer::enums::Format::R32G32_SINT, - offsetof(ext::gltf::mesh::Skinned, id) - }, - { - uf::renderer::enums::Format::R32G32B32A32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, joints) - }, - { - uf::renderer::enums::Format::R32G32B32A32_SFLOAT, - offsetof(ext::gltf::mesh::Skinned, weights) - }, -}; \ No newline at end of file +UF_VERTEX_DESCRIPTOR(ext::gltf::mesh::ID, + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::ID, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::ID, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::ID, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::ID, R32G32B32A32_SFLOAT, tangent) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::ID, R32G32_SINT, id) +); +UF_VERTEX_DESCRIPTOR(ext::gltf::mesh::Skinned, + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32B32A32_SFLOAT, tangent) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32_SINT, id) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32B32A32_SFLOAT, joints) + UF_VERTEX_DESCRIPTION(ext::gltf::mesh::Skinned, R32G32B32A32_SFLOAT, weights) +); \ No newline at end of file diff --git a/engine/src/ext/json/json.cpp b/engine/src/ext/json/json.cpp index 2590929e..34678358 100644 --- a/engine/src/ext/json/json.cpp +++ b/engine/src/ext/json/json.cpp @@ -124,17 +124,22 @@ std::string ext::json::encode( const ext::json::Value& json, bool pretty ) { return ext::lua::state["json"]["encode"]( table ); #endif } +#if UF_USE_LUA std::string ext::json::encode( const sol::table& table ) { return ext::lua::state["json"]["encode"]( table ); } - +#endif void ext::json::decode( ext::json::Value& json, const std::string& str ) { #if defined(UF_JSON_USE_NLOHMANN) && UF_JSON_USE_NLOHMANN +#if UF_NO_EXCEPTIONS + json = nlohmann::json::parse(str, nullptr, true, true); +#else try { json = nlohmann::json::parse(str, nullptr, true, true); } catch ( nlohmann::json::parse_error& e ) { uf::iostream << "[JSON] " << e.what() << "\n"; } +#endif #elif defined(UF_JSON_USE_JSONCPP) && UF_JSON_USE_JSONCPP Json::Reader reader; if ( !reader.parse(str, json) ) { diff --git a/engine/src/ext/json/jsoncpp.cpp b/engine/src/ext/json/jsoncpp.cpp deleted file mode 100644 index 7a597deb..00000000 --- a/engine/src/ext/json/jsoncpp.cpp +++ /dev/null @@ -1,5326 +0,0 @@ -#if defined(UF_USE_JSONCPP) - -/// Json-cpp amalgamated source (http://jsoncpp.sourceforge.net/). -/// It is intended to be used with #include "json/json.h" - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - -/* -The JsonCpp library's source code, including accompanying documentation, -tests and demonstration applications, are licensed under the following -conditions... - -Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all -jurisdictions which recognize such a disclaimer. In such jurisdictions, -this software is released into the Public Domain. - -In jurisdictions which do not recognize Public Domain property (e.g. Germany as of -2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and -The JsonCpp Authors, and is released under the terms of the MIT License (see below). - -In jurisdictions which recognize Public Domain property, the user of this -software may choose to accept it either as 1) Public Domain, 2) under the -conditions of the MIT License (see below), or 3) under the terms of dual -Public Domain/MIT License conditions described here, as they choose. - -The MIT License is about as close to Public Domain as a license can get, and is -described in clear, concise terms at: - - http://en.wikipedia.org/wiki/MIT_License - -The full text of the MIT License follows: - -======================================================================== -Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, copy, -modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -======================================================================== -(END LICENSE TEXT) - -The MIT license is compatible with both the GPL and commercial -software, affording one all of the rights of Public Domain with the -minor nuisance of being required to keep the above copyright notice -and license text in the source code. Note also that by accepting the -Public Domain "license" you can re-license your copy using whatever -license you like. - -*/ - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: LICENSE -// ////////////////////////////////////////////////////////////////////// - - - - - - -#include "json/json.h" - -#ifndef JSON_IS_AMALGAMATION -#error "Compile with -I PATH_TO_JSON_DIRECTORY" -#endif - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED -#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -#if !defined(JSON_IS_AMALGAMATION) -#include -#endif - -// Also support old flag NO_LOCALE_SUPPORT -#ifdef NO_LOCALE_SUPPORT -#define JSONCPP_NO_LOCALE_SUPPORT -#endif - -#ifndef JSONCPP_NO_LOCALE_SUPPORT -#include -#endif - -/* This header provides common string manipulation support, such as UTF-8, - * portable conversion from/to string... - * - * It is an internal header that must not be exposed. - */ - -namespace Json { -static inline char getDecimalPoint() { -#ifdef JSONCPP_NO_LOCALE_SUPPORT - return '\0'; -#else - struct lconv* lc = localeconv(); - return lc ? *(lc->decimal_point) : '\0'; -#endif -} - -/// Converts a unicode code-point to UTF-8. -static inline String codePointToUTF8(unsigned int cp) { - String result; - - // based on description from http://en.wikipedia.org/wiki/UTF-8 - - if (cp <= 0x7f) { - result.resize(1); - result[0] = static_cast(cp); - } else if (cp <= 0x7FF) { - result.resize(2); - result[1] = static_cast(0x80 | (0x3f & cp)); - result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); - } else if (cp <= 0xFFFF) { - result.resize(3); - result[2] = static_cast(0x80 | (0x3f & cp)); - result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); - } else if (cp <= 0x10FFFF) { - result.resize(4); - result[3] = static_cast(0x80 | (0x3f & cp)); - result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); - result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); - result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); - } - - return result; -} - -enum { - /// Constant that specify the size of the buffer that must be passed to - /// uintToString. - uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 -}; - -// Defines a char buffer for use with uintToString(). -using UIntToStringBuffer = char[uintToStringBufferSize]; - -/** Converts an unsigned integer to string. - * @param value Unsigned integer to convert to string - * @param current Input/Output string buffer. - * Must have at least uintToStringBufferSize chars free. - */ -static inline void uintToString(LargestUInt value, char*& current) { - *--current = 0; - do { - *--current = static_cast(value % 10U + static_cast('0')); - value /= 10; - } while (value != 0); -} - -/** Change ',' to '.' everywhere in buffer. - * - * We had a sophisticated way, but it did not work in WinCE. - * @see https://github.com/open-source-parsers/jsoncpp/pull/9 - */ -template Iter fixNumericLocale(Iter begin, Iter end) { - for (; begin != end; ++begin) { - if (*begin == ',') { - *begin = '.'; - } - } - return begin; -} - -template void fixNumericLocaleInput(Iter begin, Iter end) { - char decimalPoint = getDecimalPoint(); - if (decimalPoint == '\0' || decimalPoint == '.') { - return; - } - for (; begin != end; ++begin) { - if (*begin == '.') { - *begin = decimalPoint; - } - } -} - -/** - * Return iterator that would be the new end of the range [begin,end), if we - * were to delete zeros in the end of string, but not the last zero before '.'. - */ -template Iter fixZerosInTheEnd(Iter begin, Iter end) { - for (; begin != end; --end) { - if (*(end - 1) != '0') { - return end; - } - // Don't delete the last zero before the decimal point. - if (begin != (end - 1) && *(end - 2) == '.') { - return end; - } - } - return end; -} - -} // namespace Json - -#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_tool.h -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors -// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#if __cplusplus >= 201103L - -#if !defined(sscanf) -#define sscanf std::sscanf -#endif - -#endif //__cplusplus - -#if defined(_MSC_VER) -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -#endif //_MSC_VER - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile -// time to change the stack limit -#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) -#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 -#endif - -static size_t const stackLimit_g = - JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue() - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using CharReaderPtr = std::unique_ptr; -#else -using CharReaderPtr = std::auto_ptr; -#endif - -// Implementation of class Features -// //////////////////////////////// - -Features::Features() = default; - -Features Features::all() { return {}; } - -Features Features::strictMode() { - Features features; - features.allowComments_ = false; - features.strictRoot_ = true; - features.allowDroppedNullPlaceholders_ = false; - features.allowNumericKeys_ = false; - return features; -} - -// Implementation of class Reader -// //////////////////////////////// - -bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -// Class Reader -// ////////////////////////////////////////////////////////////////// - -Reader::Reader() : features_(Features::all()) {} - -Reader::Reader(const Features& features) : features_(features) {} - -bool Reader::parse(const std::string& document, Value& root, - bool collectComments) { - document_.assign(document.begin(), document.end()); - const char* begin = document_.c_str(); - const char* end = begin + document_.length(); - return parse(begin, end, root, collectComments); -} - -bool Reader::parse(std::istream& is, Value& root, bool collectComments) { - // std::istream_iterator begin(is); - // std::istream_iterator end; - // Those would allow streamed input from a file, if parse() were a - // template function. - - // Since String is reference-counted, this at least does not - // create an extra copy. - String doc; - std::getline(is, doc, static_cast EOF); - return parse(doc.data(), doc.data() + doc.size(), root, collectComments); -} - -bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - bool successful = readValue(); - Token token; - skipCommentTokens(token); - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool Reader::readValue() { - // readValue() may call itself only if it calls readObject() or ReadArray(). - // These methods execute nodes_.push() just before and nodes_.pop)() just - // after calling readValue(). parse() executes one nodes_.push(), so > instead - // of >=. - if (nodes_.size() > stackLimit_g) - throwRuntimeError("Exceeded stackLimit in readValue()."); - - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // Else, fall through... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void Reader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool Reader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - token.type_ = tokenNumber; - readNumber(); - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void Reader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -bool Reader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool Reader::readComment() { - Location commentBegin = current_ - 1; - Char c = getNextChar(); - bool successful = false; - if (c == '*') - successful = readCStyleComment(); - else if (c == '/') - successful = readCppStyleComment(); - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (c != '*' || !containsNewLine(commentBegin, current_)) - placement = commentAfterOnSameLine; - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - Reader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void Reader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool Reader::readCStyleComment() { - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - } - return getNextChar() == '/'; -} - -bool Reader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -void Reader::readNumber() { - Location p = current_; - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } -} - -bool Reader::readString() { - Char c = '\0'; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool Reader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool Reader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - skipSpaces(); - if (current_ != end_ && *current_ == ']') // empty array - { - Token endArray; - readToken(endArray); - return true; - } - int index = 0; - for (;;) { - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool Reader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - bool isNegative = *current == '-'; - if (isNegative) - ++current; - // TODO: Help the compiler do the div and mod at compile time or get rid of - // them. - Value::LargestUInt maxIntegerValue = - isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 - : Value::maxLargestUInt; - Value::LargestUInt threshold = maxIntegerValue / 10; - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, b) this is the last digit, and - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > maxIntegerValue % 10) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - if (isNegative && value == maxIntegerValue) - decoded = Value::minLargestInt; - else if (isNegative) - decoded = -Value::LargestInt(value); - else if (value <= Value::LargestUInt(Value::maxInt)) - decoded = Value::LargestInt(value); - else - decoded = value; - return true; -} - -bool Reader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - String buffer(token.start_, token.end_); - IStringStream is(buffer); - if (!(is >> value)) - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - decoded = value; - return true; -} - -bool Reader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool Reader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool Reader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool Reader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool Reader::recoverFromError(TokenType skipUntilToken) { - size_t const errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool Reader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& Reader::currentValue() { return *(nodes_.top()); } - -Reader::Char Reader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void Reader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String Reader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -// Deprecated. Preserved for backward compatibility -String Reader::getFormatedErrorMessages() const { - return getFormattedErrorMessages(); -} - -String Reader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector Reader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - Reader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -bool Reader::pushError(const Value& value, const String& message) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = nullptr; - errors_.push_back(info); - return true; -} - -bool Reader::pushError(const Value& value, const String& message, - const Value& extra) { - ptrdiff_t const length = end_ - begin_; - if (value.getOffsetStart() > length || value.getOffsetLimit() > length || - extra.getOffsetLimit() > length) - return false; - Token token; - token.type_ = tokenError; - token.start_ = begin_ + value.getOffsetStart(); - token.end_ = begin_ + value.getOffsetLimit(); - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = begin_ + extra.getOffsetStart(); - errors_.push_back(info); - return true; -} - -bool Reader::good() const { return errors_.empty(); } - -// Originally copied from the Features class (now deprecated), used internally -// for features implementation. -class OurFeatures { -public: - static OurFeatures all(); - bool allowComments_; - bool allowTrailingCommas_; - bool strictRoot_; - bool allowDroppedNullPlaceholders_; - bool allowNumericKeys_; - bool allowSingleQuotes_; - bool failIfExtra_; - bool rejectDupKeys_; - bool allowSpecialFloats_; - bool skipBom_; - size_t stackLimit_; -}; // OurFeatures - -OurFeatures OurFeatures::all() { return {}; } - -// Implementation of class Reader -// //////////////////////////////// - -// Originally copied from the Reader class (now deprecated), used internally -// for implementing JSON reading. -class OurReader { -public: - using Char = char; - using Location = const Char*; - struct StructuredError { - ptrdiff_t offset_start; - ptrdiff_t offset_limit; - String message; - }; - - explicit OurReader(OurFeatures const& features); - bool parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments = true); - String getFormattedErrorMessages() const; - std::vector getStructuredErrors() const; - -private: - OurReader(OurReader const&); // no impl - void operator=(OurReader const&); // no impl - - enum TokenType { - tokenEndOfStream = 0, - tokenObjectBegin, - tokenObjectEnd, - tokenArrayBegin, - tokenArrayEnd, - tokenString, - tokenNumber, - tokenTrue, - tokenFalse, - tokenNull, - tokenNaN, - tokenPosInf, - tokenNegInf, - tokenArraySeparator, - tokenMemberSeparator, - tokenComment, - tokenError - }; - - class Token { - public: - TokenType type_; - Location start_; - Location end_; - }; - - class ErrorInfo { - public: - Token token_; - String message_; - Location extra_; - }; - - using Errors = std::deque; - - bool readToken(Token& token); - void skipSpaces(); - void skipBom(bool skipBom); - bool match(const Char* pattern, int patternLength); - bool readComment(); - bool readCStyleComment(bool* containsNewLineResult); - bool readCppStyleComment(); - bool readString(); - bool readStringSingleQuote(); - bool readNumber(bool checkInf); - bool readValue(); - bool readObject(Token& token); - bool readArray(Token& token); - bool decodeNumber(Token& token); - bool decodeNumber(Token& token, Value& decoded); - bool decodeString(Token& token); - bool decodeString(Token& token, String& decoded); - bool decodeDouble(Token& token); - bool decodeDouble(Token& token, Value& decoded); - bool decodeUnicodeCodePoint(Token& token, Location& current, Location end, - unsigned int& unicode); - bool decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, unsigned int& unicode); - bool addError(const String& message, Token& token, Location extra = nullptr); - bool recoverFromError(TokenType skipUntilToken); - bool addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken); - void skipUntilSpace(); - Value& currentValue(); - Char getNextChar(); - void getLocationLineAndColumn(Location location, int& line, - int& column) const; - String getLocationLineAndColumn(Location location) const; - void addComment(Location begin, Location end, CommentPlacement placement); - void skipCommentTokens(Token& token); - - static String normalizeEOL(Location begin, Location end); - static bool containsNewLine(Location begin, Location end); - - using Nodes = std::stack; - - Nodes nodes_{}; - Errors errors_{}; - String document_{}; - Location begin_ = nullptr; - Location end_ = nullptr; - Location current_ = nullptr; - Location lastValueEnd_ = nullptr; - Value* lastValue_ = nullptr; - bool lastValueHasAComment_ = false; - String commentsBefore_{}; - - OurFeatures const features_; - bool collectComments_ = false; -}; // OurReader - -// complete copy of Read impl, for OurReader - -bool OurReader::containsNewLine(OurReader::Location begin, - OurReader::Location end) { - return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; }); -} - -OurReader::OurReader(OurFeatures const& features) : features_(features) {} - -bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root, - bool collectComments) { - if (!features_.allowComments_) { - collectComments = false; - } - - begin_ = beginDoc; - end_ = endDoc; - collectComments_ = collectComments; - current_ = begin_; - lastValueEnd_ = nullptr; - lastValue_ = nullptr; - commentsBefore_.clear(); - errors_.clear(); - while (!nodes_.empty()) - nodes_.pop(); - nodes_.push(&root); - - // skip byte order mark if it exists at the beginning of the UTF-8 text. - skipBom(features_.skipBom_); - bool successful = readValue(); - nodes_.pop(); - Token token; - skipCommentTokens(token); - if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) { - addError("Extra non-whitespace after JSON value.", token); - return false; - } - if (collectComments_ && !commentsBefore_.empty()) - root.setComment(commentsBefore_, commentAfter); - if (features_.strictRoot_) { - if (!root.isArray() && !root.isObject()) { - // Set error location to start of doc, ideally should be first token found - // in doc - token.type_ = tokenError; - token.start_ = beginDoc; - token.end_ = endDoc; - addError( - "A valid JSON document must be either an array or an object value.", - token); - return false; - } - } - return successful; -} - -bool OurReader::readValue() { - // To preserve the old behaviour we cast size_t to int. - if (nodes_.size() > features_.stackLimit_) - throwRuntimeError("Exceeded stackLimit in readValue()."); - Token token; - skipCommentTokens(token); - bool successful = true; - - if (collectComments_ && !commentsBefore_.empty()) { - currentValue().setComment(commentsBefore_, commentBefore); - commentsBefore_.clear(); - } - - switch (token.type_) { - case tokenObjectBegin: - successful = readObject(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenArrayBegin: - successful = readArray(token); - currentValue().setOffsetLimit(current_ - begin_); - break; - case tokenNumber: - successful = decodeNumber(token); - break; - case tokenString: - successful = decodeString(token); - break; - case tokenTrue: { - Value v(true); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenFalse: { - Value v(false); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNull: { - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNaN: { - Value v(std::numeric_limits::quiet_NaN()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenPosInf: { - Value v(std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenNegInf: { - Value v(-std::numeric_limits::infinity()); - currentValue().swapPayload(v); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - } break; - case tokenArraySeparator: - case tokenObjectEnd: - case tokenArrayEnd: - if (features_.allowDroppedNullPlaceholders_) { - // "Un-read" the current token and mark the current value as a null - // token. - current_--; - Value v; - currentValue().swapPayload(v); - currentValue().setOffsetStart(current_ - begin_ - 1); - currentValue().setOffsetLimit(current_ - begin_); - break; - } // else, fall through ... - default: - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return addError("Syntax error: value, object or array expected.", token); - } - - if (collectComments_) { - lastValueEnd_ = current_; - lastValueHasAComment_ = false; - lastValue_ = ¤tValue(); - } - - return successful; -} - -void OurReader::skipCommentTokens(Token& token) { - if (features_.allowComments_) { - do { - readToken(token); - } while (token.type_ == tokenComment); - } else { - readToken(token); - } -} - -bool OurReader::readToken(Token& token) { - skipSpaces(); - token.start_ = current_; - Char c = getNextChar(); - bool ok = true; - switch (c) { - case '{': - token.type_ = tokenObjectBegin; - break; - case '}': - token.type_ = tokenObjectEnd; - break; - case '[': - token.type_ = tokenArrayBegin; - break; - case ']': - token.type_ = tokenArrayEnd; - break; - case '"': - token.type_ = tokenString; - ok = readString(); - break; - case '\'': - if (features_.allowSingleQuotes_) { - token.type_ = tokenString; - ok = readStringSingleQuote(); - } else { - // If we don't allow single quotes, this is a failure case. - ok = false; - } - break; - case '/': - token.type_ = tokenComment; - ok = readComment(); - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - token.type_ = tokenNumber; - readNumber(false); - break; - case '-': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenNegInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case '+': - if (readNumber(true)) { - token.type_ = tokenNumber; - } else { - token.type_ = tokenPosInf; - ok = features_.allowSpecialFloats_ && match("nfinity", 7); - } - break; - case 't': - token.type_ = tokenTrue; - ok = match("rue", 3); - break; - case 'f': - token.type_ = tokenFalse; - ok = match("alse", 4); - break; - case 'n': - token.type_ = tokenNull; - ok = match("ull", 3); - break; - case 'N': - if (features_.allowSpecialFloats_) { - token.type_ = tokenNaN; - ok = match("aN", 2); - } else { - ok = false; - } - break; - case 'I': - if (features_.allowSpecialFloats_) { - token.type_ = tokenPosInf; - ok = match("nfinity", 7); - } else { - ok = false; - } - break; - case ',': - token.type_ = tokenArraySeparator; - break; - case ':': - token.type_ = tokenMemberSeparator; - break; - case 0: - token.type_ = tokenEndOfStream; - break; - default: - ok = false; - break; - } - if (!ok) - token.type_ = tokenError; - token.end_ = current_; - return ok; -} - -void OurReader::skipSpaces() { - while (current_ != end_) { - Char c = *current_; - if (c == ' ' || c == '\t' || c == '\r' || c == '\n') - ++current_; - else - break; - } -} - -void OurReader::skipBom(bool skipBom) { - // The default behavior is to skip BOM. - if (skipBom) { - if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) { - begin_ += 3; - current_ = begin_; - } - } -} - -bool OurReader::match(const Char* pattern, int patternLength) { - if (end_ - current_ < patternLength) - return false; - int index = patternLength; - while (index--) - if (current_[index] != pattern[index]) - return false; - current_ += patternLength; - return true; -} - -bool OurReader::readComment() { - const Location commentBegin = current_ - 1; - const Char c = getNextChar(); - bool successful = false; - bool cStyleWithEmbeddedNewline = false; - - const bool isCStyleComment = (c == '*'); - const bool isCppStyleComment = (c == '/'); - if (isCStyleComment) { - successful = readCStyleComment(&cStyleWithEmbeddedNewline); - } else if (isCppStyleComment) { - successful = readCppStyleComment(); - } - - if (!successful) - return false; - - if (collectComments_) { - CommentPlacement placement = commentBefore; - - if (!lastValueHasAComment_) { - if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { - if (isCppStyleComment || !cStyleWithEmbeddedNewline) { - placement = commentAfterOnSameLine; - lastValueHasAComment_ = true; - } - } - } - - addComment(commentBegin, current_, placement); - } - return true; -} - -String OurReader::normalizeEOL(OurReader::Location begin, - OurReader::Location end) { - String normalized; - normalized.reserve(static_cast(end - begin)); - OurReader::Location current = begin; - while (current != end) { - char c = *current++; - if (c == '\r') { - if (current != end && *current == '\n') - // convert dos EOL - ++current; - // convert Mac EOL - normalized += '\n'; - } else { - normalized += c; - } - } - return normalized; -} - -void OurReader::addComment(Location begin, Location end, - CommentPlacement placement) { - assert(collectComments_); - const String& normalized = normalizeEOL(begin, end); - if (placement == commentAfterOnSameLine) { - assert(lastValue_ != nullptr); - lastValue_->setComment(normalized, placement); - } else { - commentsBefore_ += normalized; - } -} - -bool OurReader::readCStyleComment(bool* containsNewLineResult) { - *containsNewLineResult = false; - - while ((current_ + 1) < end_) { - Char c = getNextChar(); - if (c == '*' && *current_ == '/') - break; - if (c == '\n') - *containsNewLineResult = true; - } - - return getNextChar() == '/'; -} - -bool OurReader::readCppStyleComment() { - while (current_ != end_) { - Char c = getNextChar(); - if (c == '\n') - break; - if (c == '\r') { - // Consume DOS EOL. It will be normalized in addComment. - if (current_ != end_ && *current_ == '\n') - getNextChar(); - // Break on Moc OS 9 EOL. - break; - } - } - return true; -} - -bool OurReader::readNumber(bool checkInf) { - Location p = current_; - if (checkInf && p != end_ && *p == 'I') { - current_ = ++p; - return false; - } - char c = '0'; // stopgap for already consumed character - // integral part - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - // fractional part - if (c == '.') { - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - // exponential part - if (c == 'e' || c == 'E') { - c = (current_ = p) < end_ ? *p++ : '\0'; - if (c == '+' || c == '-') - c = (current_ = p) < end_ ? *p++ : '\0'; - while (c >= '0' && c <= '9') - c = (current_ = p) < end_ ? *p++ : '\0'; - } - return true; -} -bool OurReader::readString() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '"') - break; - } - return c == '"'; -} - -bool OurReader::readStringSingleQuote() { - Char c = 0; - while (current_ != end_) { - c = getNextChar(); - if (c == '\\') - getNextChar(); - else if (c == '\'') - break; - } - return c == '\''; -} - -bool OurReader::readObject(Token& token) { - Token tokenName; - String name; - Value init(objectValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - while (readToken(tokenName)) { - bool initialTokenOk = true; - while (tokenName.type_ == tokenComment && initialTokenOk) - initialTokenOk = readToken(tokenName); - if (!initialTokenOk) - break; - if (tokenName.type_ == tokenObjectEnd && - (name.empty() || - features_.allowTrailingCommas_)) // empty object or trailing comma - return true; - name.clear(); - if (tokenName.type_ == tokenString) { - if (!decodeString(tokenName, name)) - return recoverFromError(tokenObjectEnd); - } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { - Value numberName; - if (!decodeNumber(tokenName, numberName)) - return recoverFromError(tokenObjectEnd); - name = numberName.asString(); - } else { - break; - } - if (name.length() >= (1U << 30)) - throwRuntimeError("keylength >= 2^30"); - if (features_.rejectDupKeys_ && currentValue().isMember(name)) { - String msg = "Duplicate key: '" + name + "'"; - return addErrorAndRecover(msg, tokenName, tokenObjectEnd); - } - - Token colon; - if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { - return addErrorAndRecover("Missing ':' after object member name", colon, - tokenObjectEnd); - } - Value& value = currentValue()[name]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenObjectEnd); - - Token comma; - if (!readToken(comma) || - (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && - comma.type_ != tokenComment)) { - return addErrorAndRecover("Missing ',' or '}' in object declaration", - comma, tokenObjectEnd); - } - bool finalizeTokenOk = true; - while (comma.type_ == tokenComment && finalizeTokenOk) - finalizeTokenOk = readToken(comma); - if (comma.type_ == tokenObjectEnd) - return true; - } - return addErrorAndRecover("Missing '}' or object member name", tokenName, - tokenObjectEnd); -} - -bool OurReader::readArray(Token& token) { - Value init(arrayValue); - currentValue().swapPayload(init); - currentValue().setOffsetStart(token.start_ - begin_); - int index = 0; - for (;;) { - skipSpaces(); - if (current_ != end_ && *current_ == ']' && - (index == 0 || - (features_.allowTrailingCommas_ && - !features_.allowDroppedNullPlaceholders_))) // empty array or trailing - // comma - { - Token endArray; - readToken(endArray); - return true; - } - Value& value = currentValue()[index++]; - nodes_.push(&value); - bool ok = readValue(); - nodes_.pop(); - if (!ok) // error already set - return recoverFromError(tokenArrayEnd); - - Token currentToken; - // Accept Comment after last item in the array. - ok = readToken(currentToken); - while (currentToken.type_ == tokenComment && ok) { - ok = readToken(currentToken); - } - bool badTokenType = (currentToken.type_ != tokenArraySeparator && - currentToken.type_ != tokenArrayEnd); - if (!ok || badTokenType) { - return addErrorAndRecover("Missing ',' or ']' in array declaration", - currentToken, tokenArrayEnd); - } - if (currentToken.type_ == tokenArrayEnd) - break; - } - return true; -} - -bool OurReader::decodeNumber(Token& token) { - Value decoded; - if (!decodeNumber(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeNumber(Token& token, Value& decoded) { - // Attempts to parse the number as an integer. If the number is - // larger than the maximum supported value of an integer then - // we decode the number as a double. - Location current = token.start_; - const bool isNegative = *current == '-'; - if (isNegative) { - ++current; - } - - // We assume we can represent the largest and smallest integer types as - // unsigned integers with separate sign. This is only true if they can fit - // into an unsigned integer. - static_assert(Value::maxLargestInt <= Value::maxLargestUInt, - "Int must be smaller than UInt"); - - // We need to convert minLargestInt into a positive number. The easiest way - // to do this conversion is to assume our "threshold" value of minLargestInt - // divided by 10 can fit in maxLargestInt when absolute valued. This should - // be a safe assumption. - static_assert(Value::minLargestInt <= -Value::maxLargestInt, - "The absolute value of minLargestInt must be greater than or " - "equal to maxLargestInt"); - static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt, - "The absolute value of minLargestInt must be only 1 magnitude " - "larger than maxLargest Int"); - - static constexpr Value::LargestUInt positive_threshold = - Value::maxLargestUInt / 10; - static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10; - - // For the negative values, we have to be more careful. Since typically - // -Value::minLargestInt will cause an overflow, we first divide by 10 and - // then take the inverse. This assumes that minLargestInt is only a single - // power of 10 different in magnitude, which we check above. For the last - // digit, we take the modulus before negating for the same reason. - static constexpr auto negative_threshold = - Value::LargestUInt(-(Value::minLargestInt / 10)); - static constexpr auto negative_last_digit = - Value::UInt(-(Value::minLargestInt % 10)); - - const Value::LargestUInt threshold = - isNegative ? negative_threshold : positive_threshold; - const Value::UInt max_last_digit = - isNegative ? negative_last_digit : positive_last_digit; - - Value::LargestUInt value = 0; - while (current < token.end_) { - Char c = *current++; - if (c < '0' || c > '9') - return decodeDouble(token, decoded); - - const auto digit(static_cast(c - '0')); - if (value >= threshold) { - // We've hit or exceeded the max value divided by 10 (rounded down). If - // a) we've only just touched the limit, meaing value == threshold, - // b) this is the last digit, or - // c) it's small enough to fit in that rounding delta, we're okay. - // Otherwise treat this number as a double to avoid overflow. - if (value > threshold || current != token.end_ || - digit > max_last_digit) { - return decodeDouble(token, decoded); - } - } - value = value * 10 + digit; - } - - if (isNegative) { - // We use the same magnitude assumption here, just in case. - const auto last_digit = static_cast(value % 10); - decoded = -Value::LargestInt(value / 10) * 10 - last_digit; - } else if (value <= Value::LargestUInt(Value::maxLargestInt)) { - decoded = Value::LargestInt(value); - } else { - decoded = value; - } - - return true; -} - -bool OurReader::decodeDouble(Token& token) { - Value decoded; - if (!decodeDouble(token, decoded)) - return false; - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeDouble(Token& token, Value& decoded) { - double value = 0; - const String buffer(token.start_, token.end_); - IStringStream is(buffer); - if (!(is >> value)) { - return addError( - "'" + String(token.start_, token.end_) + "' is not a number.", token); - } - decoded = value; - return true; -} - -bool OurReader::decodeString(Token& token) { - String decoded_string; - if (!decodeString(token, decoded_string)) - return false; - Value decoded(decoded_string); - currentValue().swapPayload(decoded); - currentValue().setOffsetStart(token.start_ - begin_); - currentValue().setOffsetLimit(token.end_ - begin_); - return true; -} - -bool OurReader::decodeString(Token& token, String& decoded) { - decoded.reserve(static_cast(token.end_ - token.start_ - 2)); - Location current = token.start_ + 1; // skip '"' - Location end = token.end_ - 1; // do not include '"' - while (current != end) { - Char c = *current++; - if (c == '"') - break; - if (c == '\\') { - if (current == end) - return addError("Empty escape sequence in string", token, current); - Char escape = *current++; - switch (escape) { - case '"': - decoded += '"'; - break; - case '/': - decoded += '/'; - break; - case '\\': - decoded += '\\'; - break; - case 'b': - decoded += '\b'; - break; - case 'f': - decoded += '\f'; - break; - case 'n': - decoded += '\n'; - break; - case 'r': - decoded += '\r'; - break; - case 't': - decoded += '\t'; - break; - case 'u': { - unsigned int unicode; - if (!decodeUnicodeCodePoint(token, current, end, unicode)) - return false; - decoded += codePointToUTF8(unicode); - } break; - default: - return addError("Bad escape sequence in string", token, current); - } - } else { - decoded += c; - } - } - return true; -} - -bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current, - Location end, unsigned int& unicode) { - - if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) - return false; - if (unicode >= 0xD800 && unicode <= 0xDBFF) { - // surrogate pairs - if (end - current < 6) - return addError( - "additional six characters expected to parse unicode surrogate pair.", - token, current); - if (*(current++) == '\\' && *(current++) == 'u') { - unsigned int surrogatePair; - if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { - unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); - } else - return false; - } else - return addError("expecting another \\u token to begin the second half of " - "a unicode surrogate pair", - token, current); - } - return true; -} - -bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current, - Location end, - unsigned int& ret_unicode) { - if (end - current < 4) - return addError( - "Bad unicode escape sequence in string: four digits expected.", token, - current); - int unicode = 0; - for (int index = 0; index < 4; ++index) { - Char c = *current++; - unicode *= 16; - if (c >= '0' && c <= '9') - unicode += c - '0'; - else if (c >= 'a' && c <= 'f') - unicode += c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - unicode += c - 'A' + 10; - else - return addError( - "Bad unicode escape sequence in string: hexadecimal digit expected.", - token, current); - } - ret_unicode = static_cast(unicode); - return true; -} - -bool OurReader::addError(const String& message, Token& token, Location extra) { - ErrorInfo info; - info.token_ = token; - info.message_ = message; - info.extra_ = extra; - errors_.push_back(info); - return false; -} - -bool OurReader::recoverFromError(TokenType skipUntilToken) { - size_t errorCount = errors_.size(); - Token skip; - for (;;) { - if (!readToken(skip)) - errors_.resize(errorCount); // discard errors caused by recovery - if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) - break; - } - errors_.resize(errorCount); - return false; -} - -bool OurReader::addErrorAndRecover(const String& message, Token& token, - TokenType skipUntilToken) { - addError(message, token); - return recoverFromError(skipUntilToken); -} - -Value& OurReader::currentValue() { return *(nodes_.top()); } - -OurReader::Char OurReader::getNextChar() { - if (current_ == end_) - return 0; - return *current_++; -} - -void OurReader::getLocationLineAndColumn(Location location, int& line, - int& column) const { - Location current = begin_; - Location lastLineStart = current; - line = 0; - while (current < location && current != end_) { - Char c = *current++; - if (c == '\r') { - if (*current == '\n') - ++current; - lastLineStart = current; - ++line; - } else if (c == '\n') { - lastLineStart = current; - ++line; - } - } - // column & line start at 1 - column = int(location - lastLineStart) + 1; - ++line; -} - -String OurReader::getLocationLineAndColumn(Location location) const { - int line, column; - getLocationLineAndColumn(location, line, column); - char buffer[18 + 16 + 16 + 1]; - jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); - return buffer; -} - -String OurReader::getFormattedErrorMessages() const { - String formattedMessage; - for (const auto& error : errors_) { - formattedMessage += - "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; - formattedMessage += " " + error.message_ + "\n"; - if (error.extra_) - formattedMessage += - "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; - } - return formattedMessage; -} - -std::vector OurReader::getStructuredErrors() const { - std::vector allErrors; - for (const auto& error : errors_) { - OurReader::StructuredError structured; - structured.offset_start = error.token_.start_ - begin_; - structured.offset_limit = error.token_.end_ - begin_; - structured.message = error.message_; - allErrors.push_back(structured); - } - return allErrors; -} - -class OurCharReader : public CharReader { - bool const collectComments_; - OurReader reader_; - -public: - OurCharReader(bool collectComments, OurFeatures const& features) - : collectComments_(collectComments), reader_(features) {} - bool parse(char const* beginDoc, char const* endDoc, Value* root, - String* errs) override { - bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); - if (errs) { - *errs = reader_.getFormattedErrorMessages(); - } - return ok; - } -}; - -CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); } -CharReaderBuilder::~CharReaderBuilder() = default; -CharReader* CharReaderBuilder::newCharReader() const { - bool collectComments = settings_["collectComments"].asBool(); - OurFeatures features = OurFeatures::all(); - features.allowComments_ = settings_["allowComments"].asBool(); - features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool(); - features.strictRoot_ = settings_["strictRoot"].asBool(); - features.allowDroppedNullPlaceholders_ = - settings_["allowDroppedNullPlaceholders"].asBool(); - features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); - features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); - - // Stack limit is always a size_t, so we get this as an unsigned int - // regardless of it we have 64-bit integer support enabled. - features.stackLimit_ = static_cast(settings_["stackLimit"].asUInt()); - features.failIfExtra_ = settings_["failIfExtra"].asBool(); - features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); - features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); - features.skipBom_ = settings_["skipBom"].asBool(); - return new OurCharReader(collectComments, features); -} - -bool CharReaderBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "collectComments", - "allowComments", - "allowTrailingCommas", - "strictRoot", - "allowDroppedNullPlaceholders", - "allowNumericKeys", - "allowSingleQuotes", - "stackLimit", - "failIfExtra", - "rejectDupKeys", - "allowSpecialFloats", - "skipBom", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& CharReaderBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void CharReaderBuilder::strictMode(Json::Value* settings) { - //! [CharReaderBuilderStrictMode] - (*settings)["allowComments"] = false; - (*settings)["allowTrailingCommas"] = false; - (*settings)["strictRoot"] = true; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = true; - (*settings)["rejectDupKeys"] = true; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderStrictMode] -} -// static -void CharReaderBuilder::setDefaults(Json::Value* settings) { - //! [CharReaderBuilderDefaults] - (*settings)["collectComments"] = true; - (*settings)["allowComments"] = true; - (*settings)["allowTrailingCommas"] = true; - (*settings)["strictRoot"] = false; - (*settings)["allowDroppedNullPlaceholders"] = false; - (*settings)["allowNumericKeys"] = false; - (*settings)["allowSingleQuotes"] = false; - (*settings)["stackLimit"] = 1000; - (*settings)["failIfExtra"] = false; - (*settings)["rejectDupKeys"] = false; - (*settings)["allowSpecialFloats"] = false; - (*settings)["skipBom"] = true; - //! [CharReaderBuilderDefaults] -} - -////////////////////////////////// -// global functions - -bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root, - String* errs) { - OStringStream ssin; - ssin << sin.rdbuf(); - String doc = ssin.str(); - char const* begin = doc.data(); - char const* end = begin + doc.size(); - // Note that we do not actually need a null-terminator. - CharReaderPtr const reader(fact.newCharReader()); - return reader->parse(begin, end, root, errs); -} - -IStream& operator>>(IStream& sin, Value& root) { - CharReaderBuilder b; - String errs; - bool ok = parseFromStream(b, sin, &root, &errs); - if (!ok) { - throwRuntimeError(errs); - } - return sin; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_reader.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -// included by json_value.cpp - -namespace Json { - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIteratorBase -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIteratorBase::ValueIteratorBase() : current_() {} - -ValueIteratorBase::ValueIteratorBase( - const Value::ObjectValues::iterator& current) - : current_(current), isNull_(false) {} - -Value& ValueIteratorBase::deref() { return current_->second; } -const Value& ValueIteratorBase::deref() const { return current_->second; } - -void ValueIteratorBase::increment() { ++current_; } - -void ValueIteratorBase::decrement() { --current_; } - -ValueIteratorBase::difference_type -ValueIteratorBase::computeDistance(const SelfType& other) const { - // Iterator for null value are initialized using the default - // constructor, which initialize current_ to the default - // std::map::iterator. As begin() and end() are two instance - // of the default std::map::iterator, they can not be compared. - // To allow this, we handle this comparison specifically. - if (isNull_ && other.isNull_) { - return 0; - } - - // Usage of std::distance is not portable (does not compile with Sun Studio 12 - // RogueWave STL, - // which is the one used by default). - // Using a portable hand-made version for non random iterator instead: - // return difference_type( std::distance( current_, other.current_ ) ); - difference_type myDistance = 0; - for (Value::ObjectValues::iterator it = current_; it != other.current_; - ++it) { - ++myDistance; - } - return myDistance; -} - -bool ValueIteratorBase::isEqual(const SelfType& other) const { - if (isNull_) { - return other.isNull_; - } - return current_ == other.current_; -} - -void ValueIteratorBase::copy(const SelfType& other) { - current_ = other.current_; - isNull_ = other.isNull_; -} - -Value ValueIteratorBase::key() const { - const Value::CZString czstring = (*current_).first; - if (czstring.data()) { - if (czstring.isStaticString()) - return Value(StaticString(czstring.data())); - return Value(czstring.data(), czstring.data() + czstring.length()); - } - return Value(czstring.index()); -} - -UInt ValueIteratorBase::index() const { - const Value::CZString czstring = (*current_).first; - if (!czstring.data()) - return czstring.index(); - return Value::UInt(-1); -} - -String ValueIteratorBase::name() const { - char const* keey; - char const* end; - keey = memberName(&end); - if (!keey) - return String(); - return String(keey, end); -} - -char const* ValueIteratorBase::memberName() const { - const char* cname = (*current_).first.data(); - return cname ? cname : ""; -} - -char const* ValueIteratorBase::memberName(char const** end) const { - const char* cname = (*current_).first.data(); - if (!cname) { - *end = nullptr; - return nullptr; - } - *end = cname + (*current_).first.length(); - return cname; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueConstIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueConstIterator::ValueConstIterator() = default; - -ValueConstIterator::ValueConstIterator( - const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueConstIterator::ValueConstIterator(ValueIterator const& other) - : ValueIteratorBase(other) {} - -ValueConstIterator& ValueConstIterator:: -operator=(const ValueIteratorBase& other) { - copy(other); - return *this; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class ValueIterator -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -ValueIterator::ValueIterator() = default; - -ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) - : ValueIteratorBase(current) {} - -ValueIterator::ValueIterator(const ValueConstIterator& other) - : ValueIteratorBase(other) { - throwRuntimeError("ConstIterator to Iterator should never be allowed."); -} - -ValueIterator::ValueIterator(const ValueIterator& other) = default; - -ValueIterator& ValueIterator::operator=(const SelfType& other) { - copy(other); - return *this; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_valueiterator.inl -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include - -// Provide implementation equivalent of std::snprintf for older _MSC compilers -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include -static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size, - const char* format, va_list ap) { - int count = -1; - if (size != 0) - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); - return count; -} - -int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size, - const char* format, ...) { - va_list ap; - va_start(ap, format); - const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap); - va_end(ap); - return count; -} -#endif - -// Disable warning C4702 : unreachable code -#if defined(_MSC_VER) -#pragma warning(disable : 4702) -#endif - -#define JSON_ASSERT_UNREACHABLE assert(false) - -namespace Json { -template -static std::unique_ptr cloneUnique(const std::unique_ptr& p) { - std::unique_ptr r; - if (p) { - r = std::unique_ptr(new T(*p)); - } - return r; -} - -// This is a walkaround to avoid the static initialization of Value::null. -// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of -// 8 (instead of 4) as a bit of future-proofing. -#if defined(__ARMEL__) -#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) -#else -#define ALIGNAS(byte_alignment) -#endif - -// static -Value const& Value::nullSingleton() { - static Value const nullStatic; - return nullStatic; -} - -#if JSON_USE_NULLREF -// for backwards compatibility, we'll leave these global references around, but -// DO NOT use them in JSONCPP library code any more! -// static -Value const& Value::null = Value::nullSingleton(); - -// static -Value const& Value::nullRef = Value::nullSingleton(); -#endif - -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -template -static inline bool InRange(double d, T min, U max) { - // The casts can lose precision, but we are looking only for - // an approximate range. Might fail on edge cases though. ~cdunn - return d >= static_cast(min) && d <= static_cast(max); -} -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) -static inline double integerToDouble(Json::UInt64 value) { - return static_cast(Int64(value / 2)) * 2.0 + - static_cast(Int64(value & 1)); -} - -template static inline double integerToDouble(T value) { - return static_cast(value); -} - -template -static inline bool InRange(double d, T min, U max) { - return d >= integerToDouble(min) && d <= integerToDouble(max); -} -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - -/** Duplicates the specified string value. - * @param value Pointer to the string to duplicate. Must be zero-terminated if - * length is "unknown". - * @param length Length of the value. if equals to unknown, then it will be - * computed using strlen(value). - * @return Pointer on the duplicate instance of string. - */ -static inline char* duplicateStringValue(const char* value, size_t length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - if (length >= static_cast(Value::maxInt)) - length = Value::maxInt - 1; - - auto newString = static_cast(malloc(length + 1)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateStringValue(): " - "Failed to allocate string value buffer"); - } - memcpy(newString, value, length); - newString[length] = 0; - return newString; -} - -/* Record the length as a prefix. - */ -static inline char* duplicateAndPrefixStringValue(const char* value, - unsigned int length) { - // Avoid an integer overflow in the call to malloc below by limiting length - // to a sane value. - JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - - sizeof(unsigned) - 1U, - "in Json::Value::duplicateAndPrefixStringValue(): " - "length too big for prefixing"); - size_t actualLength = sizeof(length) + length + 1; - auto newString = static_cast(malloc(actualLength)); - if (newString == nullptr) { - throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): " - "Failed to allocate string value buffer"); - } - *reinterpret_cast(newString) = length; - memcpy(newString + sizeof(unsigned), value, length); - newString[actualLength - 1U] = - 0; // to avoid buffer over-run accidents by users later - return newString; -} -inline static void decodePrefixedString(bool isPrefixed, char const* prefixed, - unsigned* length, char const** value) { - if (!isPrefixed) { - *length = static_cast(strlen(prefixed)); - *value = prefixed; - } else { - *length = *reinterpret_cast(prefixed); - *value = prefixed + sizeof(unsigned); - } -} -/** Free the string duplicated by - * duplicateStringValue()/duplicateAndPrefixStringValue(). - */ -#if JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { - unsigned length = 0; - char const* valueDecoded; - decodePrefixedString(true, value, &length, &valueDecoded); - size_t const size = sizeof(unsigned) + length + 1U; - memset(value, 0, size); - free(value); -} -static inline void releaseStringValue(char* value, unsigned length) { - // length==0 => we allocated the strings memory - size_t size = (length == 0) ? strlen(value) : length; - memset(value, 0, size); - free(value); -} -#else // !JSONCPP_USING_SECURE_MEMORY -static inline void releasePrefixedStringValue(char* value) { free(value); } -static inline void releaseStringValue(char* value, unsigned) { free(value); } -#endif // JSONCPP_USING_SECURE_MEMORY - -} // namespace Json - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ValueInternals... -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -#if !defined(JSON_IS_AMALGAMATION) - -#include "json_valueiterator.inl" -#endif // if !defined(JSON_IS_AMALGAMATION) - -namespace Json { - -#if JSON_USE_EXCEPTION -Exception::Exception(String msg) : msg_(std::move(msg)) {} -Exception::~Exception() noexcept = default; -char const* Exception::what() const noexcept { return msg_.c_str(); } -RuntimeError::RuntimeError(String const& msg) : Exception(msg) {} -LogicError::LogicError(String const& msg) : Exception(msg) {} -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - throw RuntimeError(msg); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - throw LogicError(msg); -} -#else // !JSON_USE_EXCEPTION -JSONCPP_NORETURN void throwRuntimeError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -JSONCPP_NORETURN void throwLogicError(String const& msg) { - std::cerr << msg << std::endl; - abort(); -} -#endif - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::CZString -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -// Notes: policy_ indicates if the string was allocated when -// a string is stored. - -Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {} - -Value::CZString::CZString(char const* str, unsigned length, - DuplicationPolicy allocate) - : cstr_(str) { - // allocate != duplicate - storage_.policy_ = allocate & 0x3; - storage_.length_ = length & 0x3FFFFFFF; -} - -Value::CZString::CZString(const CZString& other) { - cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr - ? duplicateStringValue(other.cstr_, other.storage_.length_) - : other.cstr_); - storage_.policy_ = - static_cast( - other.cstr_ - ? (static_cast(other.storage_.policy_) == - noDuplication - ? noDuplication - : duplicate) - : static_cast(other.storage_.policy_)) & - 3U; - storage_.length_ = other.storage_.length_; -} - -Value::CZString::CZString(CZString&& other) noexcept - : cstr_(other.cstr_), index_(other.index_) { - other.cstr_ = nullptr; -} - -Value::CZString::~CZString() { - if (cstr_ && storage_.policy_ == duplicate) { - releaseStringValue(const_cast(cstr_), - storage_.length_ + 1U); // +1 for null terminating - // character for sake of - // completeness but not actually - // necessary - } -} - -void Value::CZString::swap(CZString& other) { - std::swap(cstr_, other.cstr_); - std::swap(index_, other.index_); -} - -Value::CZString& Value::CZString::operator=(const CZString& other) { - cstr_ = other.cstr_; - index_ = other.index_; - return *this; -} - -Value::CZString& Value::CZString::operator=(CZString&& other) noexcept { - cstr_ = other.cstr_; - index_ = other.index_; - other.cstr_ = nullptr; - return *this; -} - -bool Value::CZString::operator<(const CZString& other) const { - if (!cstr_) - return index_ < other.index_; - // return strcmp(cstr_, other.cstr_) < 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); -} - -bool Value::CZString::operator==(const CZString& other) const { - if (!cstr_) - return index_ == other.index_; - // return strcmp(cstr_, other.cstr_) == 0; - // Assume both are strings. - unsigned this_len = this->storage_.length_; - unsigned other_len = other.storage_.length_; - if (this_len != other_len) - return false; - JSON_ASSERT(this->cstr_ && other.cstr_); - int comp = memcmp(this->cstr_, other.cstr_, this_len); - return comp == 0; -} - -ArrayIndex Value::CZString::index() const { return index_; } - -// const char* Value::CZString::c_str() const { return cstr_; } -const char* Value::CZString::data() const { return cstr_; } -unsigned Value::CZString::length() const { return storage_.length_; } -bool Value::CZString::isStaticString() const { - return storage_.policy_ == noDuplication; -} - -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// class Value::Value -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// -// ////////////////////////////////////////////////////////////////// - -/*! \internal Default constructor initialization must be equivalent to: - * memset( this, 0, sizeof(Value) ) - * This optimization is used in ValueInternalMap fast allocator. - */ -Value::Value(ValueType type) { - static char const emptyString[] = ""; - initBasic(type); - switch (type) { - case nullValue: - break; - case intValue: - case uintValue: - value_.int_ = 0; - break; - case realValue: - value_.real_ = 0.0; - break; - case stringValue: - // allocated_ == false, so this is safe. - value_.string_ = const_cast(static_cast(emptyString)); - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(); - break; - case booleanValue: - value_.bool_ = false; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -Value::Value(Int value) { - initBasic(intValue); - value_.int_ = value; -} - -Value::Value(UInt value) { - initBasic(uintValue); - value_.uint_ = value; -} -#if defined(JSON_HAS_INT64) -Value::Value(Int64 value) { - initBasic(intValue); - value_.int_ = value; -} -Value::Value(UInt64 value) { - initBasic(uintValue); - value_.uint_ = value; -} -#endif // defined(JSON_HAS_INT64) - -Value::Value(double value) { - initBasic(realValue); - value_.real_ = value; -} - -Value::Value(const char* value) { - initBasic(stringValue, true); - JSON_ASSERT_MESSAGE(value != nullptr, - "Null Value Passed to Value Constructor"); - value_.string_ = duplicateAndPrefixStringValue( - value, static_cast(strlen(value))); -} - -Value::Value(const char* begin, const char* end) { - initBasic(stringValue, true); - value_.string_ = - duplicateAndPrefixStringValue(begin, static_cast(end - begin)); -} - -Value::Value(const String& value) { - initBasic(stringValue, true); - value_.string_ = duplicateAndPrefixStringValue( - value.data(), static_cast(value.length())); -} - -Value::Value(const StaticString& value) { - initBasic(stringValue); - value_.string_ = const_cast(value.c_str()); -} - -Value::Value(bool value) { - initBasic(booleanValue); - value_.bool_ = value; -} - -Value::Value(const Value& other) { - dupPayload(other); - dupMeta(other); -} - -Value::Value(Value&& other) noexcept { - initBasic(nullValue); - swap(other); -} - -Value::~Value() { - releasePayload(); - value_.uint_ = 0; -} - -Value& Value::operator=(const Value& other) { - Value(other).swap(*this); - return *this; -} - -Value& Value::operator=(Value&& other) noexcept { - other.swap(*this); - return *this; -} - -void Value::swapPayload(Value& other) { - std::swap(bits_, other.bits_); - std::swap(value_, other.value_); -} - -void Value::copyPayload(const Value& other) { - releasePayload(); - dupPayload(other); -} - -void Value::swap(Value& other) { - swapPayload(other); - std::swap(comments_, other.comments_); - std::swap(start_, other.start_); - std::swap(limit_, other.limit_); -} - -void Value::copy(const Value& other) { - copyPayload(other); - dupMeta(other); -} - -ValueType Value::type() const { - return static_cast(bits_.value_type_); -} - -int Value::compare(const Value& other) const { - if (*this < other) - return -1; - if (*this > other) - return 1; - return 0; -} - -bool Value::operator<(const Value& other) const { - int typeDelta = type() - other.type(); - if (typeDelta) - return typeDelta < 0; - switch (type()) { - case nullValue: - return false; - case intValue: - return value_.int_ < other.value_.int_; - case uintValue: - return value_.uint_ < other.value_.uint_; - case realValue: - return value_.real_ < other.value_.real_; - case booleanValue: - return value_.bool_ < other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return other.value_.string_ != nullptr; - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - unsigned min_len = std::min(this_len, other_len); - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, min_len); - if (comp < 0) - return true; - if (comp > 0) - return false; - return (this_len < other_len); - } - case arrayValue: - case objectValue: { - auto thisSize = value_.map_->size(); - auto otherSize = other.value_.map_->size(); - if (thisSize != otherSize) - return thisSize < otherSize; - return (*value_.map_) < (*other.value_.map_); - } - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator<=(const Value& other) const { return !(other < *this); } - -bool Value::operator>=(const Value& other) const { return !(*this < other); } - -bool Value::operator>(const Value& other) const { return other < *this; } - -bool Value::operator==(const Value& other) const { - if (type() != other.type()) - return false; - switch (type()) { - case nullValue: - return true; - case intValue: - return value_.int_ == other.value_.int_; - case uintValue: - return value_.uint_ == other.value_.uint_; - case realValue: - return value_.real_ == other.value_.real_; - case booleanValue: - return value_.bool_ == other.value_.bool_; - case stringValue: { - if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) { - return (value_.string_ == other.value_.string_); - } - unsigned this_len; - unsigned other_len; - char const* this_str; - char const* other_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len, - &other_str); - if (this_len != other_len) - return false; - JSON_ASSERT(this_str && other_str); - int comp = memcmp(this_str, other_str, this_len); - return comp == 0; - } - case arrayValue: - case objectValue: - return value_.map_->size() == other.value_.map_->size() && - (*value_.map_) == (*other.value_.map_); - default: - JSON_ASSERT_UNREACHABLE; - } - return false; // unreachable -} - -bool Value::operator!=(const Value& other) const { return !(*this == other); } - -const char* Value::asCString() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == nullptr) - return nullptr; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_str; -} - -#if JSONCPP_USING_SECURE_MEMORY -unsigned Value::getCStringLength() const { - JSON_ASSERT_MESSAGE(type() == stringValue, - "in Json::Value::asCString(): requires stringValue"); - if (value_.string_ == 0) - return 0; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return this_len; -} -#endif - -bool Value::getString(char const** begin, char const** end) const { - if (type() != stringValue) - return false; - if (value_.string_ == nullptr) - return false; - unsigned length; - decodePrefixedString(this->isAllocated(), this->value_.string_, &length, - begin); - *end = *begin + length; - return true; -} - -String Value::asString() const { - switch (type()) { - case nullValue: - return ""; - case stringValue: { - if (value_.string_ == nullptr) - return ""; - unsigned this_len; - char const* this_str; - decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len, - &this_str); - return String(this_str, this_len); - } - case booleanValue: - return value_.bool_ ? "true" : "false"; - case intValue: - return valueToString(value_.int_); - case uintValue: - return valueToString(value_.uint_); - case realValue: - return valueToString(value_.real_); - default: - JSON_FAIL_MESSAGE("Type is not convertible to string"); - } -} - -Value::Int Value::asInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); - return Int(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); - return Int(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), - "double out of Int range"); - return Int(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int."); -} - -Value::UInt Value::asUInt() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); - return UInt(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); - return UInt(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), - "double out of UInt range"); - return UInt(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt."); -} - -#if defined(JSON_HAS_INT64) - -Value::Int64 Value::asInt64() const { - switch (type()) { - case intValue: - return Int64(value_.int_); - case uintValue: - JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); - return Int64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), - "double out of Int64 range"); - return Int64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to Int64."); -} - -Value::UInt64 Value::asUInt64() const { - switch (type()) { - case intValue: - JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); - return UInt64(value_.int_); - case uintValue: - return UInt64(value_.uint_); - case realValue: - JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), - "double out of UInt64 range"); - return UInt64(value_.real_); - case nullValue: - return 0; - case booleanValue: - return value_.bool_ ? 1 : 0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); -} -#endif // if defined(JSON_HAS_INT64) - -LargestInt Value::asLargestInt() const { -#if defined(JSON_NO_INT64) - return asInt(); -#else - return asInt64(); -#endif -} - -LargestUInt Value::asLargestUInt() const { -#if defined(JSON_NO_INT64) - return asUInt(); -#else - return asUInt64(); -#endif -} - -double Value::asDouble() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return integerToDouble(value_.uint_); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return value_.real_; - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0 : 0.0; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to double."); -} - -float Value::asFloat() const { - switch (type()) { - case intValue: - return static_cast(value_.int_); - case uintValue: -#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - return static_cast(value_.uint_); -#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - // This can fail (silently?) if the value is bigger than MAX_FLOAT. - return static_cast(integerToDouble(value_.uint_)); -#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) - case realValue: - return static_cast(value_.real_); - case nullValue: - return 0.0; - case booleanValue: - return value_.bool_ ? 1.0F : 0.0F; - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to float."); -} - -bool Value::asBool() const { - switch (type()) { - case booleanValue: - return value_.bool_; - case nullValue: - return false; - case intValue: - return value_.int_ != 0; - case uintValue: - return value_.uint_ != 0; - case realValue: { - // According to JavaScript language zero or NaN is regarded as false - const auto value_classification = std::fpclassify(value_.real_); - return value_classification != FP_ZERO && value_classification != FP_NAN; - } - default: - break; - } - JSON_FAIL_MESSAGE("Value is not convertible to bool."); -} - -bool Value::isConvertibleTo(ValueType other) const { - switch (other) { - case nullValue: - return (isNumeric() && asDouble() == 0.0) || - (type() == booleanValue && !value_.bool_) || - (type() == stringValue && asString().empty()) || - (type() == arrayValue && value_.map_->empty()) || - (type() == objectValue && value_.map_->empty()) || - type() == nullValue; - case intValue: - return isInt() || - (type() == realValue && InRange(value_.real_, minInt, maxInt)) || - type() == booleanValue || type() == nullValue; - case uintValue: - return isUInt() || - (type() == realValue && InRange(value_.real_, 0, maxUInt)) || - type() == booleanValue || type() == nullValue; - case realValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case booleanValue: - return isNumeric() || type() == booleanValue || type() == nullValue; - case stringValue: - return isNumeric() || type() == booleanValue || type() == stringValue || - type() == nullValue; - case arrayValue: - return type() == arrayValue || type() == nullValue; - case objectValue: - return type() == objectValue || type() == nullValue; - } - JSON_ASSERT_UNREACHABLE; - return false; -} - -/// Number of values in array or object -ArrayIndex Value::size() const { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - case stringValue: - return 0; - case arrayValue: // size of the array is highest index + 1 - if (!value_.map_->empty()) { - ObjectValues::const_iterator itLast = value_.map_->end(); - --itLast; - return (*itLast).first.index() + 1; - } - return 0; - case objectValue: - return ArrayIndex(value_.map_->size()); - } - JSON_ASSERT_UNREACHABLE; - return 0; // unreachable; -} - -bool Value::empty() const { - if (isNull() || isArray() || isObject()) - return size() == 0U; - return false; -} - -Value::operator bool() const { return !isNull(); } - -void Value::clear() { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue || - type() == objectValue, - "in Json::Value::clear(): requires complex value"); - start_ = 0; - limit_ = 0; - switch (type()) { - case arrayValue: - case objectValue: - value_.map_->clear(); - break; - default: - break; - } -} - -void Value::resize(ArrayIndex newSize) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::resize(): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - ArrayIndex oldSize = size(); - if (newSize == 0) - clear(); - else if (newSize > oldSize) - this->operator[](newSize - 1); - else { - for (ArrayIndex index = newSize; index < oldSize; ++index) { - value_.map_->erase(index); - } - JSON_ASSERT(size() == newSize); - } -} - -Value& Value::operator[](ArrayIndex index) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex): requires arrayValue"); - if (type() == nullValue) - *this = Value(arrayValue); - CZString key(index); - auto it = value_.map_->lower_bound(key); - if (it != value_.map_->end() && (*it).first == key) - return (*it).second; - - ObjectValues::value_type defaultValue(key, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - return (*it).second; -} - -Value& Value::operator[](int index) { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index): index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -const Value& Value::operator[](ArrayIndex index) const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == arrayValue, - "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); - if (type() == nullValue) - return nullSingleton(); - CZString key(index); - ObjectValues::const_iterator it = value_.map_->find(key); - if (it == value_.map_->end()) - return nullSingleton(); - return (*it).second; -} - -const Value& Value::operator[](int index) const { - JSON_ASSERT_MESSAGE( - index >= 0, - "in Json::Value::operator[](int index) const: index cannot be negative"); - return (*this)[ArrayIndex(index)]; -} - -void Value::initBasic(ValueType type, bool allocated) { - setType(type); - setIsAllocated(allocated); - comments_ = Comments{}; - start_ = 0; - limit_ = 0; -} - -void Value::dupPayload(const Value& other) { - setType(other.type()); - setIsAllocated(false); - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - value_ = other.value_; - break; - case stringValue: - if (other.value_.string_ && other.isAllocated()) { - unsigned len; - char const* str; - decodePrefixedString(other.isAllocated(), other.value_.string_, &len, - &str); - value_.string_ = duplicateAndPrefixStringValue(str, len); - setIsAllocated(true); - } else { - value_.string_ = other.value_.string_; - } - break; - case arrayValue: - case objectValue: - value_.map_ = new ObjectValues(*other.value_.map_); - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::releasePayload() { - switch (type()) { - case nullValue: - case intValue: - case uintValue: - case realValue: - case booleanValue: - break; - case stringValue: - if (isAllocated()) - releasePrefixedStringValue(value_.string_); - break; - case arrayValue: - case objectValue: - delete value_.map_; - break; - default: - JSON_ASSERT_UNREACHABLE; - } -} - -void Value::dupMeta(const Value& other) { - comments_ = other.comments_; - start_ = other.start_; - limit_ = other.limit_; -} - -// Access an object value by name, create a null member if it does not exist. -// @pre Type of '*this' is object or null. -// @param key is null-terminated. -Value& Value::resolveReference(const char* key) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(strlen(key)), - CZString::noDuplication); // NOTE! - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -// @param key is not null-terminated. -Value& Value::resolveReference(char const* key, char const* end) { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::resolveReference(key, end): requires objectValue"); - if (type() == nullValue) - *this = Value(objectValue); - CZString actualKey(key, static_cast(end - key), - CZString::duplicateOnCopy); - auto it = value_.map_->lower_bound(actualKey); - if (it != value_.map_->end() && (*it).first == actualKey) - return (*it).second; - - ObjectValues::value_type defaultValue(actualKey, nullSingleton()); - it = value_.map_->insert(it, defaultValue); - Value& value = (*it).second; - return value; -} - -Value Value::get(ArrayIndex index, const Value& defaultValue) const { - const Value* value = &((*this)[index]); - return value == &nullSingleton() ? defaultValue : *value; -} - -bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } - -Value const* Value::find(char const* begin, char const* end) const { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::find(begin, end): requires " - "objectValue or nullValue"); - if (type() == nullValue) - return nullptr; - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - ObjectValues::const_iterator it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return nullptr; - return &(*it).second; -} -Value* Value::demand(char const* begin, char const* end) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::demand(begin, end): requires " - "objectValue or nullValue"); - return &resolveReference(begin, end); -} -const Value& Value::operator[](const char* key) const { - Value const* found = find(key, key + strlen(key)); - if (!found) - return nullSingleton(); - return *found; -} -Value const& Value::operator[](const String& key) const { - Value const* found = find(key.data(), key.data() + key.length()); - if (!found) - return nullSingleton(); - return *found; -} - -Value& Value::operator[](const char* key) { - return resolveReference(key, key + strlen(key)); -} - -Value& Value::operator[](const String& key) { - return resolveReference(key.data(), key.data() + key.length()); -} - -Value& Value::operator[](const StaticString& key) { - return resolveReference(key.c_str()); -} - -Value& Value::append(const Value& value) { return append(Value(value)); } - -Value& Value::append(Value&& value) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::append: requires arrayValue"); - if (type() == nullValue) { - *this = Value(arrayValue); - } - return this->value_.map_->emplace(size(), std::move(value)).first->second; -} - -bool Value::insert(ArrayIndex index, const Value& newValue) { - return insert(index, Value(newValue)); -} - -bool Value::insert(ArrayIndex index, Value&& newValue) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue, - "in Json::Value::insert: requires arrayValue"); - ArrayIndex length = size(); - if (index > length) { - return false; - } - for (ArrayIndex i = length; i > index; i--) { - (*this)[i] = std::move((*this)[i - 1]); - } - (*this)[index] = std::move(newValue); - return true; -} - -Value Value::get(char const* begin, char const* end, - Value const& defaultValue) const { - Value const* found = find(begin, end); - return !found ? defaultValue : *found; -} -Value Value::get(char const* key, Value const& defaultValue) const { - return get(key, key + strlen(key), defaultValue); -} -Value Value::get(String const& key, Value const& defaultValue) const { - return get(key.data(), key.data() + key.length(), defaultValue); -} - -bool Value::removeMember(const char* begin, const char* end, Value* removed) { - if (type() != objectValue) { - return false; - } - CZString actualKey(begin, static_cast(end - begin), - CZString::noDuplication); - auto it = value_.map_->find(actualKey); - if (it == value_.map_->end()) - return false; - if (removed) - *removed = std::move(it->second); - value_.map_->erase(it); - return true; -} -bool Value::removeMember(const char* key, Value* removed) { - return removeMember(key, key + strlen(key), removed); -} -bool Value::removeMember(String const& key, Value* removed) { - return removeMember(key.data(), key.data() + key.length(), removed); -} -void Value::removeMember(const char* key) { - JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue, - "in Json::Value::removeMember(): requires objectValue"); - if (type() == nullValue) - return; - - CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication); - value_.map_->erase(actualKey); -} -void Value::removeMember(const String& key) { removeMember(key.c_str()); } - -bool Value::removeIndex(ArrayIndex index, Value* removed) { - if (type() != arrayValue) { - return false; - } - CZString key(index); - auto it = value_.map_->find(key); - if (it == value_.map_->end()) { - return false; - } - if (removed) - *removed = it->second; - ArrayIndex oldSize = size(); - // shift left all items left, into the place of the "removed" - for (ArrayIndex i = index; i < (oldSize - 1); ++i) { - CZString keey(i); - (*value_.map_)[keey] = (*this)[i + 1]; - } - // erase the last one ("leftover") - CZString keyLast(oldSize - 1); - auto itLast = value_.map_->find(keyLast); - value_.map_->erase(itLast); - return true; -} - -bool Value::isMember(char const* begin, char const* end) const { - Value const* value = find(begin, end); - return nullptr != value; -} -bool Value::isMember(char const* key) const { - return isMember(key, key + strlen(key)); -} -bool Value::isMember(String const& key) const { - return isMember(key.data(), key.data() + key.length()); -} - -Value::Members Value::getMemberNames() const { - JSON_ASSERT_MESSAGE( - type() == nullValue || type() == objectValue, - "in Json::Value::getMemberNames(), value must be objectValue"); - if (type() == nullValue) - return Value::Members(); - Members members; - members.reserve(value_.map_->size()); - ObjectValues::const_iterator it = value_.map_->begin(); - ObjectValues::const_iterator itEnd = value_.map_->end(); - for (; it != itEnd; ++it) { - members.push_back(String((*it).first.data(), (*it).first.length())); - } - return members; -} - -static bool IsIntegral(double d) { - double integral_part; - return modf(d, &integral_part) == 0.0; -} - -bool Value::isNull() const { return type() == nullValue; } - -bool Value::isBool() const { return type() == booleanValue; } - -bool Value::isInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= minInt && value_.int_ <= maxInt; -#else - return true; -#endif - case uintValue: - return value_.uint_ <= UInt(maxInt); - case realValue: - return value_.real_ >= minInt && value_.real_ <= maxInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isUInt() const { - switch (type()) { - case intValue: -#if defined(JSON_HAS_INT64) - return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); -#else - return value_.int_ >= 0; -#endif - case uintValue: -#if defined(JSON_HAS_INT64) - return value_.uint_ <= maxUInt; -#else - return true; -#endif - case realValue: - return value_.real_ >= 0 && value_.real_ <= maxUInt && - IsIntegral(value_.real_); - default: - break; - } - return false; -} - -bool Value::isInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return true; - case uintValue: - return value_.uint_ <= UInt64(maxInt64); - case realValue: - // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a - // double, so double(maxInt64) will be rounded up to 2^63. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < double(maxInt64) && IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isUInt64() const { -#if defined(JSON_HAS_INT64) - switch (type()) { - case intValue: - return value_.int_ >= 0; - case uintValue: - return true; - case realValue: - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && - IsIntegral(value_.real_); - default: - break; - } -#endif // JSON_HAS_INT64 - return false; -} - -bool Value::isIntegral() const { - switch (type()) { - case intValue: - case uintValue: - return true; - case realValue: -#if defined(JSON_HAS_INT64) - // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a - // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we - // require the value to be strictly less than the limit. - return value_.real_ >= double(minInt64) && - value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); -#else - return value_.real_ >= minInt && value_.real_ <= maxUInt && - IsIntegral(value_.real_); -#endif // JSON_HAS_INT64 - default: - break; - } - return false; -} - -bool Value::isDouble() const { - return type() == intValue || type() == uintValue || type() == realValue; -} - -bool Value::isNumeric() const { return isDouble(); } - -bool Value::isString() const { return type() == stringValue; } - -bool Value::isArray() const { return type() == arrayValue; } - -bool Value::isObject() const { return type() == objectValue; } - -Value::Comments::Comments(const Comments& that) - : ptr_{cloneUnique(that.ptr_)} {} - -Value::Comments::Comments(Comments&& that) noexcept - : ptr_{std::move(that.ptr_)} {} - -Value::Comments& Value::Comments::operator=(const Comments& that) { - ptr_ = cloneUnique(that.ptr_); - return *this; -} - -Value::Comments& Value::Comments::operator=(Comments&& that) noexcept { - ptr_ = std::move(that.ptr_); - return *this; -} - -bool Value::Comments::has(CommentPlacement slot) const { - return ptr_ && !(*ptr_)[slot].empty(); -} - -String Value::Comments::get(CommentPlacement slot) const { - if (!ptr_) - return {}; - return (*ptr_)[slot]; -} - -void Value::Comments::set(CommentPlacement slot, String comment) { - if (!ptr_) { - ptr_ = std::unique_ptr(new Array()); - } - // check comments array boundry. - if (slot < CommentPlacement::numberOfCommentPlacement) { - (*ptr_)[slot] = std::move(comment); - } -} - -void Value::setComment(String comment, CommentPlacement placement) { - if (!comment.empty() && (comment.back() == '\n')) { - // Always discard trailing newline, to aid indentation. - comment.pop_back(); - } - JSON_ASSERT(!comment.empty()); - JSON_ASSERT_MESSAGE( - comment[0] == '\0' || comment[0] == '/', - "in Json::Value::setComment(): Comments must start with /"); - comments_.set(placement, std::move(comment)); -} - -bool Value::hasComment(CommentPlacement placement) const { - return comments_.has(placement); -} - -String Value::getComment(CommentPlacement placement) const { - return comments_.get(placement); -} - -void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } - -void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } - -ptrdiff_t Value::getOffsetStart() const { return start_; } - -ptrdiff_t Value::getOffsetLimit() const { return limit_; } - -String Value::toStyledString() const { - StreamWriterBuilder builder; - - String out = this->hasComment(commentBefore) ? "\n" : ""; - out += Json::writeString(builder, *this); - out += '\n'; - - return out; -} - -Value::const_iterator Value::begin() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->begin()); - break; - default: - break; - } - return {}; -} - -Value::const_iterator Value::end() const { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return const_iterator(value_.map_->end()); - break; - default: - break; - } - return {}; -} - -Value::iterator Value::begin() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->begin()); - break; - default: - break; - } - return iterator(); -} - -Value::iterator Value::end() { - switch (type()) { - case arrayValue: - case objectValue: - if (value_.map_) - return iterator(value_.map_->end()); - break; - default: - break; - } - return iterator(); -} - -// class PathArgument -// ////////////////////////////////////////////////////////////////// - -PathArgument::PathArgument() = default; - -PathArgument::PathArgument(ArrayIndex index) - : index_(index), kind_(kindIndex) {} - -PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {} - -PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {} - -// class Path -// ////////////////////////////////////////////////////////////////// - -Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2, - const PathArgument& a3, const PathArgument& a4, - const PathArgument& a5) { - InArgs in; - in.reserve(5); - in.push_back(&a1); - in.push_back(&a2); - in.push_back(&a3); - in.push_back(&a4); - in.push_back(&a5); - makePath(path, in); -} - -void Path::makePath(const String& path, const InArgs& in) { - const char* current = path.c_str(); - const char* end = current + path.length(); - auto itInArg = in.begin(); - while (current != end) { - if (*current == '[') { - ++current; - if (*current == '%') - addPathInArg(path, in, itInArg, PathArgument::kindIndex); - else { - ArrayIndex index = 0; - for (; current != end && *current >= '0' && *current <= '9'; ++current) - index = index * 10 + ArrayIndex(*current - '0'); - args_.push_back(index); - } - if (current == end || *++current != ']') - invalidPath(path, int(current - path.c_str())); - } else if (*current == '%') { - addPathInArg(path, in, itInArg, PathArgument::kindKey); - ++current; - } else if (*current == '.' || *current == ']') { - ++current; - } else { - const char* beginName = current; - while (current != end && !strchr("[.", *current)) - ++current; - args_.push_back(String(beginName, current)); - } - } -} - -void Path::addPathInArg(const String& /*path*/, const InArgs& in, - InArgs::const_iterator& itInArg, - PathArgument::Kind kind) { - if (itInArg == in.end()) { - // Error: missing argument %d - } else if ((*itInArg)->kind_ != kind) { - // Error: bad argument type - } else { - args_.push_back(**itInArg++); - } -} - -void Path::invalidPath(const String& /*path*/, int /*location*/) { - // Error: invalid path. -} - -const Value& Path::resolve(const Value& root) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) { - // Error: unable to resolve path (array value expected at position... ) - return Value::nullSingleton(); - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: unable to resolve path (object value expected at position...) - return Value::nullSingleton(); - } - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) { - // Error: unable to resolve path (object has no member named '' at - // position...) - return Value::nullSingleton(); - } - } - } - return *node; -} - -Value Path::resolve(const Value& root, const Value& defaultValue) const { - const Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray() || !node->isValidIndex(arg.index_)) - return defaultValue; - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) - return defaultValue; - node = &((*node)[arg.key_]); - if (node == &Value::nullSingleton()) - return defaultValue; - } - } - return *node; -} - -Value& Path::make(Value& root) const { - Value* node = &root; - for (const auto& arg : args_) { - if (arg.kind_ == PathArgument::kindIndex) { - if (!node->isArray()) { - // Error: node is not an array at position ... - } - node = &((*node)[arg.index_]); - } else if (arg.kind_ == PathArgument::kindKey) { - if (!node->isObject()) { - // Error: node is not an object at position... - } - node = &((*node)[arg.key_]); - } - } - return *node; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_value.cpp -// ////////////////////////////////////////////////////////////////////// - - - - - - -// ////////////////////////////////////////////////////////////////////// -// Beginning of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors -// Distributed under MIT license, or public domain if desired and -// recognized in your jurisdiction. -// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE - -#if !defined(JSON_IS_AMALGAMATION) -#include "json_tool.h" -#include -#endif // if !defined(JSON_IS_AMALGAMATION) -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if __cplusplus >= 201103L -#include -#include - -#if !defined(isnan) -#define isnan std::isnan -#endif - -#if !defined(isfinite) -#define isfinite std::isfinite -#endif - -#else -#include -#include - -#if defined(_MSC_VER) -#if !defined(isnan) -#include -#define isnan _isnan -#endif - -#if !defined(isfinite) -#include -#define isfinite _finite -#endif - -#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES - -#endif //_MSC_VER - -#if defined(__sun) && defined(__SVR4) // Solaris -#if !defined(isfinite) -#include -#define isfinite finite -#endif -#endif - -#if defined(__hpux) -#if !defined(isfinite) -#if defined(__ia64) && !defined(finite) -#define isfinite(x) \ - ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x))) -#endif -#endif -#endif - -#if !defined(isnan) -// IEEE standard states that NaN values will not compare to themselves -#define isnan(x) (x != x) -#endif - -#if !defined(__APPLE__) -#if !defined(isfinite) -#define isfinite finite -#endif -#endif -#endif - -#if defined(_MSC_VER) -// Disable warning about strdup being deprecated. -#pragma warning(disable : 4996) -#endif - -namespace Json { - -#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) -using StreamWriterPtr = std::unique_ptr; -#else -using StreamWriterPtr = std::auto_ptr; -#endif - -String valueToString(LargestInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - if (value == Value::minLargestInt) { - uintToString(LargestUInt(Value::maxLargestInt) + 1, current); - *--current = '-'; - } else if (value < 0) { - uintToString(LargestUInt(-value), current); - *--current = '-'; - } else { - uintToString(LargestUInt(value), current); - } - assert(current >= buffer); - return current; -} - -String valueToString(LargestUInt value) { - UIntToStringBuffer buffer; - char* current = buffer + sizeof(buffer); - uintToString(value, current); - assert(current >= buffer); - return current; -} - -#if defined(JSON_HAS_INT64) - -String valueToString(Int value) { return valueToString(LargestInt(value)); } - -String valueToString(UInt value) { return valueToString(LargestUInt(value)); } - -#endif // # if defined(JSON_HAS_INT64) - -namespace { -String valueToString(double value, bool useSpecialFloats, - unsigned int precision, PrecisionType precisionType) { - // Print into the buffer. We need not request the alternative representation - // that always has a decimal point because JSON doesn't distinguish the - // concepts of reals and integers. - if (!isfinite(value)) { - static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"}, - {"null", "-1e+9999", "1e+9999"}}; - return reps[useSpecialFloats ? 0 : 1] - [isnan(value) ? 0 : (value < 0) ? 1 : 2]; - } - - String buffer(size_t(36), '\0'); - while (true) { - int len = jsoncpp_snprintf( - &*buffer.begin(), buffer.size(), - (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f", - precision, value); - assert(len >= 0); - auto wouldPrint = static_cast(len); - if (wouldPrint >= buffer.size()) { - buffer.resize(wouldPrint + 1); - continue; - } - buffer.resize(wouldPrint); - break; - } - - buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end()); - - // strip the zero padding from the right - if (precisionType == PrecisionType::decimalPlaces) { - buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end()), buffer.end()); - } - - // try to ensure we preserve the fact that this was given to us as a double on - // input - if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) { - buffer += ".0"; - } - return buffer; -} -} // namespace - -String valueToString(double value, unsigned int precision, - PrecisionType precisionType) { - return valueToString(value, false, precision, precisionType); -} - -String valueToString(bool value) { return value ? "true" : "false"; } - -static bool doesAnyCharRequireEscaping(char const* s, size_t n) { - assert(s || !n); - - return std::any_of(s, s + n, [](unsigned char c) { - return c == '\\' || c == '"' || c < 0x20 || c > 0x7F; - }); -} - -static unsigned int utf8ToCodepoint(const char*& s, const char* e) { - const unsigned int REPLACEMENT_CHARACTER = 0xFFFD; - - unsigned int firstByte = static_cast(*s); - - if (firstByte < 0x80) - return firstByte; - - if (firstByte < 0xE0) { - if (e - s < 2) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = - ((firstByte & 0x1F) << 6) | (static_cast(s[1]) & 0x3F); - s += 1; - // oversized encoded characters are invalid - return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF0) { - if (e - s < 3) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x0F) << 12) | - ((static_cast(s[1]) & 0x3F) << 6) | - (static_cast(s[2]) & 0x3F); - s += 2; - // surrogates aren't valid codepoints itself - // shouldn't be UTF-8 encoded - if (calculated >= 0xD800 && calculated <= 0xDFFF) - return REPLACEMENT_CHARACTER; - // oversized encoded characters are invalid - return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated; - } - - if (firstByte < 0xF8) { - if (e - s < 4) - return REPLACEMENT_CHARACTER; - - unsigned int calculated = ((firstByte & 0x07) << 18) | - ((static_cast(s[1]) & 0x3F) << 12) | - ((static_cast(s[2]) & 0x3F) << 6) | - (static_cast(s[3]) & 0x3F); - s += 3; - // oversized encoded characters are invalid - return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated; - } - - return REPLACEMENT_CHARACTER; -} - -static const char hex2[] = "000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f" - "505152535455565758595a5b5c5d5e5f" - "606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; - -static String toHex16Bit(unsigned int x) { - const unsigned int hi = (x >> 8) & 0xff; - const unsigned int lo = x & 0xff; - String result(4, ' '); - result[0] = hex2[2 * hi]; - result[1] = hex2[2 * hi + 1]; - result[2] = hex2[2 * lo]; - result[3] = hex2[2 * lo + 1]; - return result; -} - -static void appendRaw(String& result, unsigned ch) { - result += static_cast(ch); -} - -static void appendHex(String& result, unsigned ch) { - result.append("\\u").append(toHex16Bit(ch)); -} - -static String valueToQuotedStringN(const char* value, unsigned length, - bool emitUTF8 = false) { - if (value == nullptr) - return ""; - - if (!doesAnyCharRequireEscaping(value, length)) - return String("\"") + value + "\""; - // We have to walk value and escape any special characters. - // Appending to String is not efficient, but this should be rare. - // (Note: forward slashes are *not* rare, but I am not escaping them.) - String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL - String result; - result.reserve(maxsize); // to avoid lots of mallocs - result += "\""; - char const* end = value + length; - for (const char* c = value; c != end; ++c) { - switch (*c) { - case '\"': - result += "\\\""; - break; - case '\\': - result += "\\\\"; - break; - case '\b': - result += "\\b"; - break; - case '\f': - result += "\\f"; - break; - case '\n': - result += "\\n"; - break; - case '\r': - result += "\\r"; - break; - case '\t': - result += "\\t"; - break; - // case '/': - // Even though \/ is considered a legal escape in JSON, a bare - // slash is also legal, so I see no reason to escape it. - // (I hope I am not misunderstanding something.) - // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else { - appendRaw(result, codepoint); - } - } else { - unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c` - if (codepoint < 0x20) { - appendHex(result, codepoint); - } else if (codepoint < 0x80) { - appendRaw(result, codepoint); - } else if (codepoint < 0x10000) { - // Basic Multilingual Plane - appendHex(result, codepoint); - } else { - // Extended Unicode. Encode 20 bits as a surrogate pair. - codepoint -= 0x10000; - appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff)); - appendHex(result, 0xdc00 + (codepoint & 0x3ff)); - } - } - } break; - } - } - result += "\""; - return result; -} - -String valueToQuotedString(const char* value) { - return valueToQuotedStringN(value, static_cast(strlen(value))); -} - -// Class Writer -// ////////////////////////////////////////////////////////////////// -Writer::~Writer() = default; - -// Class FastWriter -// ////////////////////////////////////////////////////////////////// - -FastWriter::FastWriter() - - = default; - -void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; } - -void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } - -void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } - -String FastWriter::write(const Value& root) { - document_.clear(); - writeValue(root); - if (!omitEndingLineFeed_) - document_ += '\n'; - return document_; -} - -void FastWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - if (!dropNullPlaceholders_) - document_ += "null"; - break; - case intValue: - document_ += valueToString(value.asLargestInt()); - break; - case uintValue: - document_ += valueToString(value.asLargestUInt()); - break; - case realValue: - document_ += valueToString(value.asDouble()); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - document_ += valueToQuotedStringN(str, static_cast(end - str)); - break; - } - case booleanValue: - document_ += valueToString(value.asBool()); - break; - case arrayValue: { - document_ += '['; - ArrayIndex size = value.size(); - for (ArrayIndex index = 0; index < size; ++index) { - if (index > 0) - document_ += ','; - writeValue(value[index]); - } - document_ += ']'; - } break; - case objectValue: { - Value::Members members(value.getMemberNames()); - document_ += '{'; - for (auto it = members.begin(); it != members.end(); ++it) { - const String& name = *it; - if (it != members.begin()) - document_ += ','; - document_ += valueToQuotedStringN(name.data(), - static_cast(name.length())); - document_ += yamlCompatibilityEnabled_ ? ": " : ":"; - writeValue(value[name]); - } - document_ += '}'; - } break; - } -} - -// Class StyledWriter -// ////////////////////////////////////////////////////////////////// - -StyledWriter::StyledWriter() = default; - -String StyledWriter::write(const Value& root) { - document_.clear(); - addChildValues_ = false; - indentString_.clear(); - writeCommentBeforeValue(root); - writeValue(root); - writeCommentAfterValueOnSameLine(root); - document_ += '\n'; - return document_; -} - -void StyledWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - document_ += " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - writeIndent(); - writeValue(childValue); - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - document_ += ','; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - document_ += "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - document_ += ", "; - document_ += childValues_[index]; - } - document_ += " ]"; - } - } -} - -bool StyledWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - document_ += value; -} - -void StyledWriter::writeIndent() { - if (!document_.empty()) { - char last = document_[document_.length() - 1]; - if (last == ' ') // already indented - return; - if (last != '\n') // Comments may add new-line - document_ += '\n'; - } - document_ += indentString_; -} - -void StyledWriter::writeWithIndent(const String& value) { - writeIndent(); - document_ += value; -} - -void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); } - -void StyledWriter::unindent() { - assert(indentString_.size() >= indentSize_); - indentString_.resize(indentString_.size() - indentSize_); -} - -void StyledWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - document_ += '\n'; - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - document_ += *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - writeIndent(); - ++iter; - } - - // Comments are stripped of trailing newlines, so add one here - document_ += '\n'; -} - -void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - document_ += " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - document_ += '\n'; - document_ += root.getComment(commentAfter); - document_ += '\n'; - } -} - -bool StyledWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -// Class StyledStreamWriter -// ////////////////////////////////////////////////////////////////// - -StyledStreamWriter::StyledStreamWriter(String indentation) - : document_(nullptr), indentation_(std::move(indentation)), - addChildValues_(), indented_(false) {} - -void StyledStreamWriter::write(OStream& out, const Value& root) { - document_ = &out; - addChildValues_ = false; - indentString_.clear(); - indented_ = true; - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *document_ << "\n"; - document_ = nullptr; // Forget the stream, for safety. -} - -void StyledStreamWriter::writeValue(const Value& value) { - switch (value.type()) { - case nullValue: - pushValue("null"); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble())); - break; - case stringValue: { - // Is NULL possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str))); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - const String& name = *it; - const Value& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedString(name.c_str())); - *document_ << " : "; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void StyledStreamWriter::writeArrayValue(const Value& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isArrayMultiLine = isMultilineArray(value); - if (isArrayMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - const Value& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *document_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *document_ << "[ "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *document_ << ", "; - *document_ << childValues_[index]; - } - *document_ << " ]"; - } - } -} - -bool StyledStreamWriter::isMultilineArray(const Value& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - const Value& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void StyledStreamWriter::pushValue(const String& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *document_ << value; -} - -void StyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - *document_ << '\n' << indentString_; -} - -void StyledStreamWriter::writeWithIndent(const String& value) { - if (!indented_) - writeIndent(); - *document_ << value; - indented_ = false; -} - -void StyledStreamWriter::indent() { indentString_ += indentation_; } - -void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *document_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would include newline - *document_ << indentString_; - ++iter; - } - indented_ = false; -} - -void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { - if (root.hasComment(commentAfterOnSameLine)) - *document_ << ' ' << root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *document_ << root.getComment(commentAfter); - } - indented_ = false; -} - -bool StyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -////////////////////////// -// BuiltStyledStreamWriter - -/// Scoped enums are not available until C++11. -struct CommentStyle { - /// Decide whether to write comments. - enum Enum { - None, ///< Drop all comments. - Most, ///< Recover odd behavior of previous versions (not implemented yet). - All ///< Keep all comments. - }; -}; - -struct BuiltStyledStreamWriter : public StreamWriter { - BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs, - String colonSymbol, String nullSymbol, - String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, - PrecisionType precisionType); - int write(Value const& root, OStream* sout) override; - -private: - void writeValue(Value const& value); - void writeArrayValue(Value const& value); - bool isMultilineArray(Value const& value); - void pushValue(String const& value); - void writeIndent(); - void writeWithIndent(String const& value); - void indent(); - void unindent(); - void writeCommentBeforeValue(Value const& root); - void writeCommentAfterValueOnSameLine(Value const& root); - static bool hasCommentForValue(const Value& value); - - using ChildValues = std::vector; - - ChildValues childValues_; - String indentString_; - unsigned int rightMargin_; - String indentation_; - CommentStyle::Enum cs_; - String colonSymbol_; - String nullSymbol_; - String endingLineFeedSymbol_; - bool addChildValues_ : 1; - bool indented_ : 1; - bool useSpecialFloats_ : 1; - bool emitUTF8_ : 1; - unsigned int precision_; - PrecisionType precisionType_; -}; -BuiltStyledStreamWriter::BuiltStyledStreamWriter( - String indentation, CommentStyle::Enum cs, String colonSymbol, - String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats, - bool emitUTF8, unsigned int precision, PrecisionType precisionType) - : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs), - colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)), - endingLineFeedSymbol_(std::move(endingLineFeedSymbol)), - addChildValues_(false), indented_(false), - useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8), - precision_(precision), precisionType_(precisionType) {} -int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) { - sout_ = sout; - addChildValues_ = false; - indented_ = true; - indentString_.clear(); - writeCommentBeforeValue(root); - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(root); - writeCommentAfterValueOnSameLine(root); - *sout_ << endingLineFeedSymbol_; - sout_ = nullptr; - return 0; -} -void BuiltStyledStreamWriter::writeValue(Value const& value) { - switch (value.type()) { - case nullValue: - pushValue(nullSymbol_); - break; - case intValue: - pushValue(valueToString(value.asLargestInt())); - break; - case uintValue: - pushValue(valueToString(value.asLargestUInt())); - break; - case realValue: - pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_, - precisionType_)); - break; - case stringValue: { - // Is NULL is possible for value.string_? No. - char const* str; - char const* end; - bool ok = value.getString(&str, &end); - if (ok) - pushValue(valueToQuotedStringN(str, static_cast(end - str), - emitUTF8_)); - else - pushValue(""); - break; - } - case booleanValue: - pushValue(valueToString(value.asBool())); - break; - case arrayValue: - writeArrayValue(value); - break; - case objectValue: { - Value::Members members(value.getMemberNames()); - if (members.empty()) - pushValue("{}"); - else { - writeWithIndent("{"); - indent(); - auto it = members.begin(); - for (;;) { - String const& name = *it; - Value const& childValue = value[name]; - writeCommentBeforeValue(childValue); - writeWithIndent(valueToQuotedStringN( - name.data(), static_cast(name.length()), emitUTF8_)); - *sout_ << colonSymbol_; - writeValue(childValue); - if (++it == members.end()) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("}"); - } - } break; - } -} - -void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { - unsigned size = value.size(); - if (size == 0) - pushValue("[]"); - else { - bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value); - if (isMultiLine) { - writeWithIndent("["); - indent(); - bool hasChildValue = !childValues_.empty(); - unsigned index = 0; - for (;;) { - Value const& childValue = value[index]; - writeCommentBeforeValue(childValue); - if (hasChildValue) - writeWithIndent(childValues_[index]); - else { - if (!indented_) - writeIndent(); - indented_ = true; - writeValue(childValue); - indented_ = false; - } - if (++index == size) { - writeCommentAfterValueOnSameLine(childValue); - break; - } - *sout_ << ","; - writeCommentAfterValueOnSameLine(childValue); - } - unindent(); - writeWithIndent("]"); - } else // output on a single line - { - assert(childValues_.size() == size); - *sout_ << "["; - if (!indentation_.empty()) - *sout_ << " "; - for (unsigned index = 0; index < size; ++index) { - if (index > 0) - *sout_ << ((!indentation_.empty()) ? ", " : ","); - *sout_ << childValues_[index]; - } - if (!indentation_.empty()) - *sout_ << " "; - *sout_ << "]"; - } - } -} - -bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) { - ArrayIndex const size = value.size(); - bool isMultiLine = size * 3 >= rightMargin_; - childValues_.clear(); - for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { - Value const& childValue = value[index]; - isMultiLine = ((childValue.isArray() || childValue.isObject()) && - !childValue.empty()); - } - if (!isMultiLine) // check if line length > max line length - { - childValues_.reserve(size); - addChildValues_ = true; - ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' - for (ArrayIndex index = 0; index < size; ++index) { - if (hasCommentForValue(value[index])) { - isMultiLine = true; - } - writeValue(value[index]); - lineLength += static_cast(childValues_[index].length()); - } - addChildValues_ = false; - isMultiLine = isMultiLine || lineLength >= rightMargin_; - } - return isMultiLine; -} - -void BuiltStyledStreamWriter::pushValue(String const& value) { - if (addChildValues_) - childValues_.push_back(value); - else - *sout_ << value; -} - -void BuiltStyledStreamWriter::writeIndent() { - // blep intended this to look at the so-far-written string - // to determine whether we are already indented, but - // with a stream we cannot do that. So we rely on some saved state. - // The caller checks indented_. - - if (!indentation_.empty()) { - // In this case, drop newlines too. - *sout_ << '\n' << indentString_; - } -} - -void BuiltStyledStreamWriter::writeWithIndent(String const& value) { - if (!indented_) - writeIndent(); - *sout_ << value; - indented_ = false; -} - -void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } - -void BuiltStyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); - indentString_.resize(indentString_.size() - indentation_.size()); -} - -void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (!root.hasComment(commentBefore)) - return; - - if (!indented_) - writeIndent(); - const String& comment = root.getComment(commentBefore); - String::const_iterator iter = comment.begin(); - while (iter != comment.end()) { - *sout_ << *iter; - if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/')) - // writeIndent(); // would write extra newline - *sout_ << indentString_; - ++iter; - } - indented_ = false; -} - -void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine( - Value const& root) { - if (cs_ == CommentStyle::None) - return; - if (root.hasComment(commentAfterOnSameLine)) - *sout_ << " " + root.getComment(commentAfterOnSameLine); - - if (root.hasComment(commentAfter)) { - writeIndent(); - *sout_ << root.getComment(commentAfter); - } -} - -// static -bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { - return value.hasComment(commentBefore) || - value.hasComment(commentAfterOnSameLine) || - value.hasComment(commentAfter); -} - -/////////////// -// StreamWriter - -StreamWriter::StreamWriter() : sout_(nullptr) {} -StreamWriter::~StreamWriter() = default; -StreamWriter::Factory::~Factory() = default; -StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); } -StreamWriterBuilder::~StreamWriterBuilder() = default; -StreamWriter* StreamWriterBuilder::newStreamWriter() const { - const String indentation = settings_["indentation"].asString(); - const String cs_str = settings_["commentStyle"].asString(); - const String pt_str = settings_["precisionType"].asString(); - const bool eyc = settings_["enableYAMLCompatibility"].asBool(); - const bool dnp = settings_["dropNullPlaceholders"].asBool(); - const bool usf = settings_["useSpecialFloats"].asBool(); - const bool emitUTF8 = settings_["emitUTF8"].asBool(); - unsigned int pre = settings_["precision"].asUInt(); - CommentStyle::Enum cs = CommentStyle::All; - if (cs_str == "All") { - cs = CommentStyle::All; - } else if (cs_str == "None") { - cs = CommentStyle::None; - } else { - throwRuntimeError("commentStyle must be 'All' or 'None'"); - } - PrecisionType precisionType(significantDigits); - if (pt_str == "significant") { - precisionType = PrecisionType::significantDigits; - } else if (pt_str == "decimal") { - precisionType = PrecisionType::decimalPlaces; - } else { - throwRuntimeError("precisionType must be 'significant' or 'decimal'"); - } - String colonSymbol = " : "; - if (eyc) { - colonSymbol = ": "; - } else if (indentation.empty()) { - colonSymbol = ":"; - } - String nullSymbol = "null"; - if (dnp) { - nullSymbol.clear(); - } - if (pre > 17) - pre = 17; - String endingLineFeedSymbol; - return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol, - endingLineFeedSymbol, usf, emitUTF8, pre, - precisionType); -} - -bool StreamWriterBuilder::validate(Json::Value* invalid) const { - static const auto& valid_keys = *new std::set{ - "indentation", - "commentStyle", - "enableYAMLCompatibility", - "dropNullPlaceholders", - "useSpecialFloats", - "emitUTF8", - "precision", - "precisionType", - }; - for (auto si = settings_.begin(); si != settings_.end(); ++si) { - auto key = si.name(); - if (valid_keys.count(key)) - continue; - if (invalid) - (*invalid)[key] = *si; - else - return false; - } - return invalid ? invalid->empty() : true; -} - -Value& StreamWriterBuilder::operator[](const String& key) { - return settings_[key]; -} -// static -void StreamWriterBuilder::setDefaults(Json::Value* settings) { - //! [StreamWriterBuilderDefaults] - (*settings)["commentStyle"] = "All"; - (*settings)["indentation"] = "\t"; - (*settings)["enableYAMLCompatibility"] = false; - (*settings)["dropNullPlaceholders"] = false; - (*settings)["useSpecialFloats"] = false; - (*settings)["emitUTF8"] = false; - (*settings)["precision"] = 17; - (*settings)["precisionType"] = "significant"; - //! [StreamWriterBuilderDefaults] -} - -String writeString(StreamWriter::Factory const& factory, Value const& root) { - OStringStream sout; - StreamWriterPtr const writer(factory.newStreamWriter()); - writer->write(root, &sout); - return sout.str(); -} - -OStream& operator<<(OStream& sout, Value const& root) { - StreamWriterBuilder builder; - StreamWriterPtr const writer(builder.newStreamWriter()); - writer->write(root, &sout); - return sout; -} - -} // namespace Json - -// ////////////////////////////////////////////////////////////////////// -// End of content of file: src/lib_json/json_writer.cpp -// ////////////////////////////////////////////////////////////////////// - -#endif \ No newline at end of file diff --git a/engine/src/ext/lua/lua.cpp b/engine/src/ext/lua/lua.cpp index 0ab1d2f5..fe417d68 100644 --- a/engine/src/ext/lua/lua.cpp +++ b/engine/src/ext/lua/lua.cpp @@ -1,7 +1,7 @@ #include - +#if UF_USE_LUA sol::state ext::lua::state; -std::string ext::lua::main = "./data/scripts/main.lua"; +std::string ext::lua::main = uf::io::root + "/scripts/main.lua"; std::unordered_map ext::lua::modules; #include @@ -262,4 +262,5 @@ void ext::lua::terminate() { delete ext::lua::onInitializationFunctions; ext::lua::onInitializationFunctions = NULL; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/asset.cpp b/engine/src/ext/lua/usertypes/asset.cpp index 6d5038b2..a4e07198 100644 --- a/engine/src/ext/lua/usertypes/asset.cpp +++ b/engine/src/ext/lua/usertypes/asset.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(uf::Asset, @@ -26,4 +26,5 @@ UF_LUA_REGISTER_USERTYPE(uf::Asset, asset.cache( uri, callback, hash ); }), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Asset::getOriginal ) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/audio.cpp b/engine/src/ext/lua/usertypes/audio.cpp index ad514d12..bb090bbd 100644 --- a/engine/src/ext/lua/usertypes/audio.cpp +++ b/engine/src/ext/lua/usertypes/audio.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(uf::Audio, @@ -30,4 +30,5 @@ UF_LUA_REGISTER_USERTYPE(uf::Audio, UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::setMaxDistance ), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getVolume ), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Audio::getFilename ) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/camera.cpp b/engine/src/ext/lua/usertypes/camera.cpp index 5eadadb7..9a3b30a8 100644 --- a/engine/src/ext/lua/usertypes/camera.cpp +++ b/engine/src/ext/lua/usertypes/camera.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(uf::Camera, @@ -40,3 +40,4 @@ UF_LUA_REGISTER_USERTYPE(uf::Camera, }), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Camera::update ) ) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/matrix.cpp b/engine/src/ext/lua/usertypes/matrix.cpp index c7791101..8fd200d1 100644 --- a/engine/src/ext/lua/usertypes/matrix.cpp +++ b/engine/src/ext/lua/usertypes/matrix.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(pod::Matrix4f, @@ -33,3 +33,4 @@ UF_LUA_REGISTER_USERTYPE(pod::Matrix4f, return uf::matrix::identity(); }) ) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/object.cpp b/engine/src/ext/lua/usertypes/object.cpp index e153c018..42bca2c2 100644 --- a/engine/src/ext/lua/usertypes/object.cpp +++ b/engine/src/ext/lua/usertypes/object.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include #include #include @@ -161,4 +161,5 @@ namespace { ); }); }); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/quaternion.cpp b/engine/src/ext/lua/usertypes/quaternion.cpp index 5decc27d..a29ea801 100644 --- a/engine/src/ext/lua/usertypes/quaternion.cpp +++ b/engine/src/ext/lua/usertypes/quaternion.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(pod::Quaternion<>, @@ -72,4 +72,5 @@ UF_LUA_REGISTER_USERTYPE(pod::Quaternion<>, UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( const pod::Quaternion<>& self ) { return uf::string::toString( self ); }) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/timer.cpp b/engine/src/ext/lua/usertypes/timer.cpp index e29cf34a..f0fc87b2 100644 --- a/engine/src/ext/lua/usertypes/timer.cpp +++ b/engine/src/ext/lua/usertypes/timer.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(uf::Timer<>, @@ -11,4 +11,5 @@ UF_LUA_REGISTER_USERTYPE(uf::Timer<>, UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::reset ), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::update ), UF_LUA_REGISTER_USERTYPE_MEMBER( uf::Timer<>::running ) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/transform.cpp b/engine/src/ext/lua/usertypes/transform.cpp index 582329d9..118d5b94 100644 --- a/engine/src/ext/lua/usertypes/transform.cpp +++ b/engine/src/ext/lua/usertypes/transform.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(pod::Transform<>, @@ -48,4 +48,5 @@ UF_LUA_REGISTER_USERTYPE(pod::Transform<>, UF_LUA_REGISTER_USERTYPE_DEFINE(getModel, []( const pod::Transform<>& t ) { return uf::transform::model( t ); }) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/vector.cpp b/engine/src/ext/lua/usertypes/vector.cpp index 33b664c9..a8eb6a6a 100644 --- a/engine/src/ext/lua/usertypes/vector.cpp +++ b/engine/src/ext/lua/usertypes/vector.cpp @@ -1,5 +1,5 @@ #include - +#if UF_USE_LUA #include UF_LUA_REGISTER_USERTYPE(pod::Vector3f, @@ -115,4 +115,5 @@ UF_LUA_REGISTER_USERTYPE(pod::Vector4f, UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector4f& self ) { return uf::string::toString( self ); }) -) \ No newline at end of file +) +#endif \ No newline at end of file diff --git a/engine/src/ext/opengl/buffer.cpp b/engine/src/ext/opengl/buffer.cpp index b29554ee..e24f5685 100644 --- a/engine/src/ext/opengl/buffer.cpp +++ b/engine/src/ext/opengl/buffer.cpp @@ -6,46 +6,57 @@ #include #include -GLhandle(VkResult) ext::opengl::Buffer::map( GLsizeiptr size, GLsizeiptr offset ) { +bool ext::opengl::Buffer::map( GLsizeiptr size, GLsizeiptr offset ) { return 0; } - void ext::opengl::Buffer::unmap() { } -GLhandle(VkResult) ext::opengl::Buffer::bind( GLsizeiptr offset ) { +bool ext::opengl::Buffer::bind( GLsizeiptr offset ) { return 0; } void ext::opengl::Buffer::setupDescriptor( GLsizeiptr size, GLsizeiptr offset ) { + descriptor.buffer = buffer; + descriptor.offset = offset; + descriptor.range = size; } -void ext::opengl::Buffer::copyTo( void* data, GLsizeiptr size ) { - +void ext::opengl::Buffer::copyTo( void* data, GLsizeiptr len ) { + if ( !buffer || !data ) return; + if ( len >= size ) len = size; + memcpy( buffer, data, len ); } -GLhandle(VkResult) ext::opengl::Buffer::flush( GLsizeiptr size, GLsizeiptr offset ) { +bool ext::opengl::Buffer::flush( GLsizeiptr size, GLsizeiptr offset ) { + return 0; +} +bool ext::opengl::Buffer::invalidate( GLsizeiptr size, GLsizeiptr offset ) { return 0; } +void ext::opengl::Buffer::allocate( const CreateInfo& bufferCreateInfo ) { + this->destroy(); + + this->buffer = malloc( bufferCreateInfo.size ); + this->usageFlags = bufferCreateInfo.usage; -GLhandle(VkResult) ext::opengl::Buffer::invalidate( GLsizeiptr size, GLsizeiptr offset ) { - return 0; -} - -void ext::opengl::Buffer::allocate( GLhandle(VkBufferCreateInfo) bufferCreateInfo ) { - + this->size = bufferCreateInfo.size; + this->allocationInfo.size = bufferCreateInfo.size; + this->allocationInfo.offset = 0; } // RAII ext::opengl::Buffer::~Buffer() { // this->destroy(); } -void ext::opengl::Buffer::initialize( GLhandle(VkDevice) device ) { - this->device = device; +void ext::opengl::Buffer::initialize( Device& device ) { + this->device = &device; } void ext::opengl::Buffer::destroy() { - + if ( device && buffer ) free(buffer); + device = NULL; + buffer = NULL; } // @@ -59,14 +70,25 @@ void ext::opengl::Buffers::destroy() { buffers.clear(); } -size_t ext::opengl::Buffers::initializeBuffer( void* data, GLsizeiptr length, GLhandle(VkBufferUsageFlags) usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags, bool stage ) { +size_t ext::opengl::Buffers::initializeBuffer( void* data, GLsizeiptr length, GLenum usageFlags, GLhandle(VkMemoryPropertyFlags) memoryPropertyFlags, bool stage ) { + size_t index = buffers.size(); + auto& buffer = buffers.emplace_back(); + + buffer.allocate( Buffer::CreateInfo{ + .flags = 0, + .size = length, + .usage = usageFlags, + } ); + buffer.copyTo( data, length ); + return index; } void ext::opengl::Buffers::updateBuffer( void* data, GLsizeiptr length, size_t index, bool stage ) { Buffer& buffer = buffers.at(index); return updateBuffer( data, length, buffer, stage ); } void ext::opengl::Buffers::updateBuffer( void* data, GLsizeiptr length, Buffer& buffer, bool stage ) { + buffer.copyTo( data, length ); } #endif \ No newline at end of file diff --git a/engine/src/ext/opengl/commands.cpp b/engine/src/ext/opengl/commands.cpp new file mode 100644 index 00000000..8f7acc6e --- /dev/null +++ b/engine/src/ext/opengl/commands.cpp @@ -0,0 +1,21 @@ +#if UF_USE_OPENGL + +#include +#include + +void ext::opengl::CommandBuffer::record( const CommandBuffer::function_t& command ) { + commands.emplace_back( command ); +} +void ext::opengl::CommandBuffer::submit() { + for ( auto& command : commands ) { + command(); + } +} +void ext::opengl::CommandBuffer::flush() { + commands.empty(); +} +size_t ext::opengl::CommandBuffer::size() const { + return commands.size(); +} + +#endif \ No newline at end of file diff --git a/engine/src/ext/opengl/device.cpp b/engine/src/ext/opengl/device.cpp index 6bfe645f..e793ea78 100644 --- a/engine/src/ext/opengl/device.cpp +++ b/engine/src/ext/opengl/device.cpp @@ -12,4 +12,32 @@ #include +void ext::opengl::Device::initialize() { + spec::Context::globalInit(); + this->context = (spec::Context*) spec::uni::Context::create( contextSettings, *this->window->getHandle() ); + +#if UF_ENV_DREAMCAST + //glKosInit(); + GLdcConfig config; + glKosInitConfig(&config); + config.fsaa_enabled = GL_FALSE; + glKosInitEx(&config); +#else + glewExperimental = GL_TRUE; + if ( glewInit() != GLEW_OK ) { + std::cout << "ERROR: " << errorString() << std::endl; + std::exit(EXIT_FAILURE); + return; + } +#endif +} +void ext::opengl::Device::destroy() { + if ( this->context ) { + this->context->terminate(); + delete this->context; + this->context = NULL; + } + spec::Context::globalCleanup(); +} + #endif \ No newline at end of file diff --git a/engine/src/ext/opengl/graphic.cpp b/engine/src/ext/opengl/graphic.cpp index 786a6b0d..fdfe5866 100644 --- a/engine/src/ext/opengl/graphic.cpp +++ b/engine/src/ext/opengl/graphic.cpp @@ -4,14 +4,15 @@ #include #include #include - +#if 0 #include #include +#endif #include #include -#define VK_DEBUG_VALIDATION_MESSAGE(x)\ - //VK_VALIDATION_MESSAGE(x); +#define GL_DEBUG_VALIDATION_MESSAGE(x)\ + GL_VALIDATION_MESSAGE(x); namespace { uint32_t VERTEX_BUFFER_BIND_ID = 0; @@ -93,7 +94,7 @@ ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& pay #if UF_SHADER_TRACK_NAMES std::string path = uf::string::join(variableName, "."); path = uf::string::replace( path, ".[", "[" ); - VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump()); + GL_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump()); #endif // is strictly an int if ( value.is(true) ) { @@ -119,13 +120,14 @@ ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& pay #endif }; #if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); + GL_VALIDATION_MESSAGE("Updating " << name << " in " << filename); + GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); #endif parse(payload); #if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); + GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); #endif + #else auto pushValue = [&]( const std::string& primitive, const ext::json::Value& input ){ if ( primitive == "bool" ) { @@ -165,8 +167,7 @@ ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& pay auto get = input.as(); memcpy( byteBuffer, &get, size ); byteBuffer += size; - } - else if ( primitive == "uint32_t" ) { + } else if ( primitive == "uint32_t" ) { size_t size = sizeof(uint32_t); // v["size"].as(); if ( byteBufferEnd < byteBuffer + size ) return false; // overflow auto get = input.as(); @@ -264,7 +265,7 @@ ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& pay #if UF_SHADER_TRACK_NAMES std::string path = uf::string::join(variableName, "."); path = uf::string::replace( path, ".[", "[" ); - VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump()); + GL_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump()); #endif pushValue( primitive, input ); } @@ -273,14 +274,14 @@ ext::opengl::userdata_t ext::opengl::jsonToUserdata( const ext::json::Value& pay if ( !variableName.empty() ) variableName.pop_back(); #endif }; - auto& definitions = metadata["definitions"]["uniforms"][name]; + //auto& definitions = metadata["definitions"]["uniforms"][name]; #if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); + GL_VALIDATION_MESSAGE("Updating " << name << " in " << filename); + GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); #endif - parseDefinition(payload, definitions); + parseDefinition(payload, definition); #if UF_SHADER_TRACK_NAMES - VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); + GL_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); #endif #endif return userdata; @@ -294,6 +295,362 @@ void ext::opengl::Shader::initialize( ext::opengl::Device& device, const std::st this->device = &device; ext::opengl::Buffers::initialize( device ); aliased = false; + +#if 0 + std::string spirv; + + { + std::ifstream is(this->filename = filename, std::ios::binary | std::ios::in | std::ios::ate); + if ( !is.is_open() ) { + GL_VALIDATION_MESSAGE("Error: Could not open shader file \"" << filename << "\""); + return; + } + is.seekg(0, std::ios::end); spirv.reserve(is.tellg()); is.seekg(0, std::ios::beg); + spirv.assign((std::istreambuf_iterator(is)), std::istreambuf_iterator()); + + assert(spirv.size() > 0); + } + + { + + GLhandle(VkShaderModuleCreateInfo) moduleCreateInfo = {}; + moduleCreateInfo.sType = GL_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + moduleCreateInfo.codeSize = spirv.size(); + moduleCreateInfo.pCode = (uint32_t*) spirv.data(); + + GL_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &module)); + } + + { + descriptor.sType = GL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + descriptor.stage = stage; + descriptor.module = module; + descriptor.pName = "main"; + + assert(descriptor.module != GL_NULL_HANDLE); + } + // set up metadata + { + metadata["filename"] = filename; + metadata["type"] = ""; + } + // do reflection + { + spirv_cross::Compiler comp( (uint32_t*) &spirv[0], spirv.size() / 4 ); + spirv_cross::ShaderResources res = comp.get_shader_resources(); + + std::function parseMembers = [&]( spirv_cross::TypeID type_id ) { + auto parseMember = [&]( auto type_id ){ + uf::Serializer payload; + + auto type = comp.get_type(type_id); + + std::string name = ""; + size_t size = 1; + ext::json::Value value; + switch ( type.basetype ) { + case spirv_cross::SPIRType::BaseType::Boolean: name = "bool"; size = sizeof(bool); value = (bool) 0; break; + case spirv_cross::SPIRType::BaseType::SByte: name = "int8_t"; size = sizeof(int8_t); value = (int8_t) 0; break; + case spirv_cross::SPIRType::BaseType::UByte: name = "uint8_t"; size = sizeof(uint8_t); value = (uint8_t) 0; break; + case spirv_cross::SPIRType::BaseType::Short: name = "int16_t"; size = sizeof(int16_t); value = (int16_t) 0; break; + case spirv_cross::SPIRType::BaseType::UShort: name = "uint16_t"; size = sizeof(uint16_t); value = (uint16_t) 0; break; + case spirv_cross::SPIRType::BaseType::Int: name = "int32_t"; size = sizeof(int32_t); value = (int32_t) 0; break; + case spirv_cross::SPIRType::BaseType::UInt: name = "uint32_t"; size = sizeof(uint32_t); value = (uint32_t) 0; break; + case spirv_cross::SPIRType::BaseType::Int64: name = "int64_t"; size = sizeof(int64_t); value = (int64_t) 0; break; + case spirv_cross::SPIRType::BaseType::UInt64: name = "uint64_t"; size = sizeof(uint64_t); value = (uint64_t) 0; break; + case spirv_cross::SPIRType::BaseType::Half: name = "half"; size = sizeof(float)/2; value = (float) 0; break; + case spirv_cross::SPIRType::BaseType::Float: name = "float"; size = sizeof(float); value = (float) 0; break; + case spirv_cross::SPIRType::BaseType::Double: name = "double"; size = sizeof(double); value = (double) 0; break; + case spirv_cross::SPIRType::BaseType::Image: name = "image2D"; break; + case spirv_cross::SPIRType::BaseType::SampledImage: name = "sampler2D"; break; + case spirv_cross::SPIRType::BaseType::Sampler: name = "sampler"; break; + default: + name = comp.get_name(type_id); + size = comp.get_declared_struct_size(type); + break; + } + if ( name == "" ) name = comp.get_name(type.type_alias); + if ( name == "" ) name = comp.get_name(type.type_alias); + if ( name == "" ) name = comp.get_name(type.parent_type); + if ( name == "" ) name = comp.get_fallback_name(type_id); + if ( type.vecsize > 1 ) { + name = "<"+name+">"; + if ( type.columns > 1 ) { + name = "Matrix"+std::to_string(type.vecsize)+"x"+std::to_string(type.columns)+name; + } else { + name = "Vector"+std::to_string(type.vecsize)+name; + } + } + { + ext::json::Value source = value; + value = ext::json::array(); + for ( size_t i = 0; i < type.vecsize * type.columns; ++i ) { + value.emplace_back(source); + } + size *= type.columns * type.vecsize; + } + for ( auto arraySize : type.array ) { + if ( arraySize > 1 ) { + ext::json::Value source = value; + value = ext::json::array(); + for ( size_t i = 0; i < arraySize; ++i ) { + value.emplace_back(source); + } + name += "[" + std::to_string(arraySize) + "]"; + size *= arraySize; + } + } + if ( ext::json::isArray(value) && value.size() == 1 ) { + value = value[0]; + } + payload["name"] = name; + payload["size"] = size; + payload["value"] = value; + return payload; + }; + uf::Serializer payload = ext::json::array(); + const auto& type = comp.get_type(type_id); + for ( auto& member_type_id : type.member_types ) { + const auto& member_type = comp.get_type(member_type_id); + std::string name = comp.get_member_name(type.type_alias, payload.size()); + if ( name == "" ) name = comp.get_member_name(type.parent_type, payload.size()); + if ( name == "" ) name = comp.get_member_name(type_id, payload.size()); + + auto& entry = payload.emplace_back(); + auto parsed = parseMember(member_type_id); + std::string type_name = parsed["name"]; + entry["name"] = type_name + " " + name; + if ( member_type.basetype == spirv_cross::SPIRType::BaseType::Struct ) { + entry["struct"] = true; + auto parsed = parseMembers(member_type_id); + if ( !member_type.array.empty() && member_type.array[0] > 1 ) { + size_t size = comp.get_declared_struct_size(member_type); + for ( auto arraySize : member_type.array ) { + ext::json::Value source = parsed; + parsed = ext::json::array(); + for ( size_t i = 0; i < arraySize; ++i ) { + parsed.emplace_back(source); + } + size = size * arraySize; + } + entry["size"] = size; + entry["value"] = parsed; + } else { + entry["size"] = comp.get_declared_struct_size(member_type); + entry["members"] = parsed; + } + } else { + entry["size"] = parsed["size"]; + entry["value"] = parsed["value"]; + } + } + return payload; + }; + + auto parseResource = [&]( const spirv_cross::Resource& resource, GLhandle(VkDescriptorType) descriptorType, size_t index ) { + const auto& type = comp.get_type(resource.type_id); + const auto& base_type = comp.get_type(resource.base_type_id); + std::string name = resource.name; + + switch ( descriptorType ) { + case GL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + size_t size = comp.get_declared_struct_size(base_type); + if ( size <= 0 ) break; + if ( size > device.properties.limits.maxUniformBufferRange ) { + GL_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of " << size << " for shader " << filename); + size = device.properties.limits.maxUniformBufferRange; + } + size_t misalignment = size % device.properties.limits.minStorageBufferOffsetAlignment; + if ( misalignment != 0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer alignment of " << misalignment << " for shader " << filename << ", correcting..."); + size += misalignment; + } + { + GL_DEBUG_VALIDATION_MESSAGE("Uniform size of " << size << " for shader " << filename); + auto& uniform = uniforms.emplace_back(); + uniform.create( size ); + } + // generate definition to JSON + { + metadata["definitions"]["uniforms"][name]["name"] = name; + metadata["definitions"]["uniforms"][name]["index"] = index; + metadata["definitions"]["uniforms"][name]["size"] = size; + metadata["definitions"]["uniforms"][name]["members"] = parseMembers(resource.type_id); + } + } break; + case GL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + // generate definition to JSON + { + metadata["definitions"]["storage"][name]["name"] = name; + metadata["definitions"]["storage"][name]["index"] = index; + metadata["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id); + } + // test + { + // updateUniform(name, getUniform(name)); + } + } break; + } + + size_t size = 1; + if ( !type.array.empty() ) { + size = type.array[0]; + } + descriptorSetLayoutBindings.push_back( ext::opengl::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), size ) ); + }; + + + //for ( const auto& resource : res.key ) { + #define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\ + const auto& resource = res.key[i];\ + GL_DEBUG_VALIDATION_MESSAGE("["< device.properties.limits.maxPushConstantsSize ) { + GL_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); + size = device.properties.limits.maxPushConstantsSize; + } + GL_DEBUG_VALIDATION_MESSAGE("Push constant size of " << size << " for shader " << filename); + { + auto& pushConstant = pushConstants.emplace_back(); + pushConstant.create( size ); + } + // generate definition to JSON + { + metadata["definitions"]["pushConstants"][name]["name"] = name; + metadata["definitions"]["pushConstants"][name]["size"] = size; + metadata["definitions"]["pushConstants"][name]["index"] = pushConstants.size() - 1; + metadata["definitions"]["pushConstants"][name]["members"] = parseMembers(resource.type_id); + } + } + + size_t specializationSize = 0; + for ( const auto& constant : comp.get_specialization_constants() ) { + const auto& value = comp.get_constant(constant.id); + const auto& type = comp.get_type(value.constant_type); + size_t size = 4; //comp.get_declared_struct_size(type); + + GLhandle(VkSpecializationMapEntry) specializationMapEntry; + specializationMapEntry.constantID = constant.constant_id; + specializationMapEntry.size = size; + specializationMapEntry.offset = specializationSize; + specializationMapEntries.push_back(specializationMapEntry); + specializationSize += size; + } + if ( specializationSize > 0 ) { + specializationConstants.create( specializationSize ); + GL_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename); + + uint8_t* s = (uint8_t*) (void*) specializationConstants; + size_t offset = 0; + + metadata["specializationConstants"] = ext::json::array(); + for ( const auto& constant : comp.get_specialization_constants() ) { + const auto& value = comp.get_constant(constant.id); + const auto& type = comp.get_type(value.constant_type); + std::string name = comp.get_name (constant.id); + + ext::json::Value member; + + size_t size = 4; + uint8_t buffer[size]; + switch ( type.basetype ) { + case spirv_cross::SPIRType::UInt: { + auto v = value.scalar(); + member["type"] = "uint32_t"; + member["value"] = v; + member["validate"] = true; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Int: { + auto v = value.scalar_i32(); + member["type"] = "int32_t"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Float: { + auto v = value.scalar_f32(); + member["type"] = "float"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + case spirv_cross::SPIRType::Boolean: { + auto v = value.scalar()!=0; + member["type"] = "bool"; + member["value"] = v; + memcpy( &buffer[0], &v, sizeof(v) ); + } break; + default: { + GL_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset " << offset << " for shader " << filename ); + } break; + } + member["name"] = name; + member["size"] = size; + member["default"] = member["value"]; + GL_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename ); + metadata["specializationConstants"].emplace_back(member); + + memcpy( &s[offset], &buffer, size ); + offset += size; + } + /* + { + specializationInfo = {}; + specializationInfo.dataSize = specializationSize; + specializationInfo.mapEntryCount = specializationMapEntries.size(); + specializationInfo.pMapEntries = specializationMapEntries.data(); + specializationInfo.pData = (void*) specializationConstants; + descriptor.pSpecializationInfo = &specializationInfo; + } + */ + } + /* + */ + // LOOP_RESOURCES( stage_inputs, GLhandle(VkVertexInputAttributeDescription) ); + // LOOP_RESOURCES( stage_outputs, GLhandle(VkPipelineColorBlendAttachmentState) ); + } + + // organize layouts + { + std::sort( descriptorSetLayoutBindings.begin(), descriptorSetLayoutBindings.end(), [&]( const GLhandle(VkDescriptorSetLayoutBinding)& l, const GLhandle(VkDescriptorSetLayoutBinding)& r ){ + return l.binding < r.binding; + } ); + } + // update uniform buffers + for ( auto& uniform : uniforms ) { + auto& userdata = uniform.data(); + initializeBuffer( + (void*) userdata.data, + userdata.len, + uf::renderer::enums::Buffer::UNIFORM + ); + } +#endif } void ext::opengl::Shader::destroy() { @@ -301,6 +658,13 @@ void ext::opengl::Shader::destroy() { if ( !device ) return; ext::opengl::Buffers::destroy(); +#if 0 + if ( module != GL_NULL_HANDLE ) { + vkDestroyShaderModule( *device, module, nullptr ); + module = GL_NULL_HANDLE; + descriptor = {}; + } +#endif for ( auto& userdata : uniforms ) userdata.destroy(); for ( auto& userdata : pushConstants ) userdata.destroy(); @@ -311,33 +675,82 @@ void ext::opengl::Shader::destroy() { bool ext::opengl::Shader::validate() { // check if uniforms match buffer size bool valid = true; +#if 0 + { + auto it = uniforms.begin(); + for ( auto& buffer : buffers ) { + if ( !(buffer.usageFlags & uf::renderer::enums::Buffer::UNIFORM) ) continue; + if ( it == uniforms.end() ) break; + auto& uniform = *(it++); + if ( uniform.data().len != buffer.allocationInfo.size ) { + GL_DEBUG_VALIDATION_MESSAGE("Uniform size mismatch: Expected " << buffer.allocationInfo.size << ", got " << uniform.data().len << "; fixing..."); + uniform.destroy(); + uniform.create(buffer.allocationInfo.size); + valid = false; + } + } + } +#endif return valid; } bool ext::opengl::Shader::hasUniform( const std::string& name ) { return !ext::json::isNull(metadata["definitions"]["uniforms"][name]); } ext::opengl::Buffer* ext::opengl::Shader::getUniformBuffer( const std::string& name ) { + if ( !hasUniform(name) ) return NULL; + size_t uniformIndex = metadata["definitions"]["uniforms"][name]["index"].as(); + for ( size_t bufferIndex = 0, uniformCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { + if ( !(buffers[bufferIndex].usageFlags & uf::renderer::enums::Buffer::UNIFORM) ) continue; + if ( uniformCounter++ != uniformIndex ) continue; + return &buffers[bufferIndex]; + } return NULL; } ext::opengl::userdata_t& ext::opengl::Shader::getUniform( const std::string& name ) { - static ext::opengl::userdata_t null; - return null; + if ( !hasUniform(name) ) { + static ext::opengl::userdata_t null; + return null; + } + auto& definition = metadata["definitions"]["uniforms"][name]; + size_t uniformSize = definition["size"].as(); + size_t uniformIndex = definition["index"].as(); + auto& userdata = uniforms[uniformIndex]; + return userdata; } bool ext::opengl::Shader::updateUniform( const std::string& name ) { - return false; + if ( !hasUniform(name) ) return false; + auto& uniform = getUniform(name); + return updateUniform(name, uniform); } bool ext::opengl::Shader::updateUniform( const std::string& name, const ext::opengl::userdata_t& userdata ) { - return false; + if ( !hasUniform(name) ) return false; + auto* bufferObject = getUniformBuffer(name); + if ( !bufferObject ) return false; + size_t size = std::max(metadata["definitions"]["uniforms"][name]["size"].as(), (size_t) bufferObject->allocationInfo.size); + updateBuffer( (void*) userdata, size, *bufferObject ); + return true; } uf::Serializer ext::opengl::Shader::getUniformJson( const std::string& name, bool cache ) { - return ext::json::null(); + if ( !hasUniform(name) ) return ext::json::null(); + if ( cache && !ext::json::isNull(metadata["uniforms"][name]) ) return metadata["uniforms"][name]; + auto& definition = metadata["definitions"]["uniforms"][name]; + if ( cache ) return metadata["uniforms"][name] = definitionToJson(definition); + return definitionToJson(definition); } ext::opengl::userdata_t ext::opengl::Shader::getUniformUserdata( const std::string& name, const ext::json::Value& payload ) { - return false; + if ( !hasUniform(name) ) return false; + return jsonToUserdata(payload, metadata["definitions"]["uniforms"][name]); } bool ext::opengl::Shader::updateUniform( const std::string& name, const ext::json::Value& payload ) { - return false; + if ( !hasUniform(name) ) return false; + + auto* bufferObject = getUniformBuffer(name); + if ( !bufferObject ) return false; + + auto uniform = getUniformUserdata( name, payload ); + updateBuffer( (void*) uniform, uniform.data().len, *bufferObject ); + return true; } bool ext::opengl::Shader::hasStorage( const std::string& name ) { @@ -345,13 +758,25 @@ bool ext::opengl::Shader::hasStorage( const std::string& name ) { } ext::opengl::Buffer* ext::opengl::Shader::getStorageBuffer( const std::string& name ) { + if ( !hasStorage(name) ) return NULL; + size_t storageIndex = metadata["definitions"]["storage"][name]["index"].as(); + for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { + if ( !(buffers[bufferIndex].usageFlags & uf::renderer::enums::Buffer::STORAGE) ) continue; + if ( storageCounter++ != storageIndex ) continue; + return &buffers[bufferIndex]; + } return NULL; } uf::Serializer ext::opengl::Shader::getStorageJson( const std::string& name, bool cache ) { - return ext::json::null(); + if ( !hasStorage(name) ) return ext::json::null(); + if ( cache && !ext::json::isNull(metadata["storage"][name]) ) return metadata["storage"][name]; + auto& definition = metadata["definitions"]["storage"][name]; + if ( cache ) return metadata["storage"][name] = definitionToJson(definition); + return definitionToJson(definition); } ext::opengl::userdata_t ext::opengl::Shader::getStorageUserdata( const std::string& name, const ext::json::Value& payload ) { - return false; + if ( !hasStorage(name) ) return false; + return jsonToUserdata(payload, metadata["definitions"]["storage"][name]); } void ext::opengl::Pipeline::initialize( Graphic& graphic ) { @@ -361,17 +786,553 @@ void ext::opengl::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des this->device = graphic.device; //this->descriptor = descriptor; Device& device = *graphic.device; -} -void ext::opengl::Pipeline::record( Graphic& graphic, GLhandle(VkCommandBuffer) commandBuffer, size_t pass, size_t draw ) { + graphic.process = true; +#if 0 + // GL_VALIDATION_MESSAGE(&graphic << ": Shaders: " << graphic.material.shaders.size() << " Textures: " << graphic.material.textures.size()); + assert( graphic.material.shaders.size() > 0 ); + RenderMode& renderMode = ext::opengl::getRenderMode( descriptor.renderMode, true); + auto& renderTarget = renderMode.getRenderTarget( descriptor.renderTarget ); + { + std::vector descriptorSetLayoutBindings; + std::vector pushConstantRanges; + std::vector poolSizes; + std::unordered_map descriptorTypes; + + for ( auto& shader : graphic.material.shaders ) { + descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); + + std::size_t offset = 0; + for ( auto& pushConstant : shader.pushConstants ) { + size_t len = pushConstant.data().len; + if ( len <= 0 || len > device.properties.limits.maxPushConstantsSize ) { + GL_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << len << " for shader " << shader.filename); + // goto PIPELINE_INITIALIZATION_INVALID; + len = device.properties.limits.maxPushConstantsSize; + } + pushConstantRanges.push_back(ext::opengl::initializers::pushConstantRange( + shader.descriptor.stage, + len, + offset + )); + offset += len; + } + } + for ( auto& descriptor : descriptorSetLayoutBindings ) { + if ( descriptorTypes.count( descriptor.descriptorType ) < 0 ) descriptorTypes[descriptor.descriptorType] = 0; + descriptorTypes[descriptor.descriptorType] += descriptor.descriptorCount; + } + for ( auto pair : descriptorTypes ) { + poolSizes.push_back(ext::opengl::initializers::descriptorPoolSize(pair.first, pair.second)); + } + GLhandle(VkDescriptorPoolCreateInfo) descriptorPoolInfo = ext::opengl::initializers::descriptorPoolCreateInfo( + poolSizes.size(), + poolSizes.data(), + 1 + ); + + GL_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + + + GLhandle(VkDescriptorSetLayoutCreateInfo) descriptorLayout = ext::opengl::initializers::descriptorSetLayoutCreateInfo( + descriptorSetLayoutBindings.data(), + descriptorSetLayoutBindings.size() + ); + GL_CHECK_RESULT(vkCreateDescriptorSetLayout( device, &descriptorLayout, nullptr, &descriptorSetLayout )); + + GLhandle(VkDescriptorSetAllocateInfo) allocInfo = ext::opengl::initializers::descriptorSetAllocateInfo( + descriptorPool, + &descriptorSetLayout, + 1 + ); + GL_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + + GLhandle(VkPipelineLayoutCreateInfo) pPipelineLayoutCreateInfo = ext::opengl::initializers::pipelineLayoutCreateInfo( + &descriptorSetLayout, + 1 + ); + pPipelineLayoutCreateInfo.pushConstantRangeCount = pushConstantRanges.size(); + pPipelineLayoutCreateInfo.pPushConstantRanges = pushConstantRanges.data(); + + GL_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + } + // Compute + for ( auto& shader : graphic.material.shaders ) { + if ( shader.descriptor.stage != uf::renderer::enums::Shader::COMPUTE ) continue; + + // Create compute shader pipelines + GLhandle(VkComputePipelineCreateInfo) computePipelineCreateInfo = ext::opengl::initializers::computePipelineCreateInfo( + pipelineLayout, + 0 + ); + computePipelineCreateInfo.stage = shader.descriptor; + GL_CHECK_RESULT(vkCreateComputePipelines(device, device.pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline)); + + return; + } + // Graphic + { + GLhandle(VkPipelineInputAssemblyStateCreateInfo) inputAssemblyState = ext::opengl::initializers::pipelineInputAssemblyStateCreateInfo( + descriptor.topology, + 0, + GL_FALSE + ); + GLhandle(VkPipelineRasterizationStateCreateInfo) rasterizationState = ext::opengl::initializers::pipelineRasterizationStateCreateInfo( + descriptor.fill, + descriptor.cullMode, // uf::renderer::enums::CullMode::NONE, + descriptor.frontFace, + 0 + ); + rasterizationState.lineWidth = graphic.descriptor.lineWidth; + rasterizationState.depthBiasEnable = graphic.descriptor.depth.bias.enable; + rasterizationState.depthBiasConstantFactor = graphic.descriptor.depth.bias.constant; + rasterizationState.depthBiasSlopeFactor = graphic.descriptor.depth.bias.slope; + rasterizationState.depthBiasClamp = graphic.descriptor.depth.bias.clamp; + + std::vector blendAttachmentStates; + + GLhandle(VkSampleCountFlagBits) samples = GL_SAMPLE_COUNT_1; + if ( renderMode.getType() != "Swapchain" ) { + auto& subpass = renderTarget.passes[descriptor.subpass]; + for ( auto& color : subpass.colors ) { + auto& attachment = renderTarget.attachments[color.attachment]; + blendAttachmentStates.push_back(attachment.blendState); + samples = std::max(samples, ext::opengl::sampleCount( attachment.descriptor.samples )); + } + // require blending if independentBlend is not an enabled feature + if ( device.enabledFeatures.independentBlend == GL_FALSE ) { + for ( size_t i = 1; i < blendAttachmentStates.size(); ++i ) { + blendAttachmentStates[i] = blendAttachmentStates[0]; + } + } + } else { + descriptor.subpass = 0; + + GLhandle(VkBool32) blendEnabled = GL_FALSE; + GLhandle(VkColorComponentFlags) writeMask = GL_COLOR_COMPONENT_R_BIT | GL_COLOR_COMPONENT_G_BIT | GL_COLOR_COMPONENT_B_BIT; + + if ( true ) { + blendEnabled = GL_TRUE; + writeMask |= GL_COLOR_COMPONENT_A_BIT; + } + + GLhandle(VkPipelineColorBlendAttachmentState) blendAttachmentState = ext::opengl::initializers::pipelineColorBlendAttachmentState( + writeMask, + blendEnabled + ); + if ( blendEnabled == GL_TRUE ) { + blendAttachmentState.srcColorBlendFactor = GL_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstColorBlendFactor = GL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.colorBlendOp = GL_BLEND_OP_ADD; + blendAttachmentState.srcAlphaBlendFactor = GL_BLEND_FACTOR_SRC_ALPHA; + blendAttachmentState.dstAlphaBlendFactor = GL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendAttachmentState.alphaBlendOp = GL_BLEND_OP_ADD; + } + blendAttachmentStates.push_back(blendAttachmentState); + } + + GLhandle(VkPipelineColorBlendStateCreateInfo) colorBlendState = ext::opengl::initializers::pipelineColorBlendStateCreateInfo( + blendAttachmentStates.size(), + blendAttachmentStates.data() + ); + GLhandle(VkPipelineDepthStencilStateCreateInfo) depthStencilState = ext::opengl::initializers::pipelineDepthStencilStateCreateInfo( + descriptor.depth.test, + descriptor.depth.write, + descriptor.depth.operation //GL_COMPARE_OP_LESS_OR_EQUAL + ); + GLhandle(VkPipelineViewportStateCreateInfo) viewportState = ext::opengl::initializers::pipelineViewportStateCreateInfo( + 1, 1, 0 + ); + GLhandle(VkPipelineMultisampleStateCreateInfo) multisampleState = ext::opengl::initializers::pipelineMultisampleStateCreateInfo( + samples, + 0 + ); + if ( device.features.sampleRateShading ) { + multisampleState.sampleShadingEnable = GL_TRUE; + multisampleState.minSampleShading = 0.25f; + } + + + std::vector dynamicStateEnables = { + GL_DYNAMIC_STATE_VIEWPORT, + GL_DYNAMIC_STATE_SCISSOR + }; + GLhandle(VkPipelineDynamicStateCreateInfo) dynamicState = ext::opengl::initializers::pipelineDynamicStateCreateInfo( + dynamicStateEnables.data(), + dynamicStateEnables.size(), + 0 + ); + + // Binding description + std::vector vertexBindingDescriptions = { + ext::opengl::initializers::vertexInputBindingDescription( + VERTEX_BUFFER_BIND_ID, + descriptor.geometry.sizes.vertex, + GL_VERTEX_INPUT_RATE_VERTEX + ) + }; + // Attribute descriptions + // Describes memory layout and shader positions + std::vector vertexAttributeDescriptions = {}; + for ( auto& attribute : descriptor.geometry.attributes ) { + auto d = ext::opengl::initializers::vertexInputAttributeDescription( + VERTEX_BUFFER_BIND_ID, + vertexAttributeDescriptions.size(), + attribute.format, + attribute.offset + ); + vertexAttributeDescriptions.push_back(d); + } + + GLhandle(VkPipelineVertexInputStateCreateInfo) vertexInputState = ext::opengl::initializers::pipelineVertexInputStateCreateInfo(); + vertexInputState.vertexBindingDescriptionCount = vertexBindingDescriptions.size(); + vertexInputState.pVertexBindingDescriptions = vertexBindingDescriptions.data(); + vertexInputState.vertexAttributeDescriptionCount = vertexAttributeDescriptions.size(); + vertexInputState.pVertexAttributeDescriptions = vertexAttributeDescriptions.data(); + + std::vector shaderDescriptors; + for ( auto& shader : graphic.material.shaders ) { + void* s = (void*) shader.specializationConstants; + size_t len = shader.specializationConstants.data().len; + for ( size_t i = 0; i < len / 4; ++i ) { + auto& payload = shader.metadata["specializationConstants"][i]; + std::string type = payload["type"].as(); + if ( type == "int32_t" ) { + int32_t& v = ((int32_t*) s)[i]; + // failsafe, because for some reason things break + if ( payload["validate"].as() && v == 0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); + v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + } + payload["value"] = v; + } else if ( type == "uint32_t" ) { + uint32_t& v = ((uint32_t*) s)[i]; + // failsafe, because for some reason things break + if ( payload["validate"].as() && v == 0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); + v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + } + payload["value"] = v; + } else if ( type == "float" ) { + float& v = ((float*) s)[i]; + // failsafe, because for some reason things break + if ( payload["validate"].as() && v == 0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); + v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + } + payload["value"] = v; + } + } + GL_DEBUG_VALIDATION_MESSAGE("Specialization constants for shader `" << shader.filename << "`: " << shader.metadata["specializationConstants"].dump(1, '\t')); + + + { + shader.specializationInfo = {}; + shader.specializationInfo.mapEntryCount = shader.specializationMapEntries.size(); + shader.specializationInfo.pMapEntries = shader.specializationMapEntries.data(); + shader.specializationInfo.pData = (void*) shader.specializationConstants; + shader.specializationInfo.dataSize = shader.specializationConstants.data().len; + shader.descriptor.pSpecializationInfo = &shader.specializationInfo; + } + shaderDescriptors.push_back(shader.descriptor); + } + + GLhandle(VkGraphicsPipelineCreateInfo) pipelineCreateInfo = ext::opengl::initializers::pipelineCreateInfo( + pipelineLayout, + renderTarget.renderPass, + 0 + ); + pipelineCreateInfo.pVertexInputState = &vertexInputState; + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pDepthStencilState = &depthStencilState; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.stageCount = shaderDescriptors.size(); + pipelineCreateInfo.pStages = shaderDescriptors.data(); + pipelineCreateInfo.subpass = descriptor.subpass; + + GL_CHECK_RESULT(vkCreateGraphicsPipelines( device, device.pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipeline)); + GL_DEBUG_VALIDATION_MESSAGE("Created graphics pipeline"); + } + + graphic.process = true; + return; +PIPELINE_INITIALIZATION_INVALID: + graphic.process = false; + GL_DEBUG_VALIDATION_MESSAGE("Pipeline initialization invalid, updating next tick..."); + uf::thread::add( uf::thread::get("Main"), [&]() -> int { + this->initialize( graphic, descriptor ); + return 0;}, true ); + return; +#endif +} +void ext::opengl::Pipeline::record( Graphic& graphic, CommandBuffer& commandBuffer, size_t pass, size_t draw ) { +#if 0 + auto bindPoint = GL_PIPELINE_BIND_POINT_GRAPHICS; + for ( auto& shader : graphic.material.shaders ) { + if ( shader.descriptor.stage == uf::renderer::enums::Shader::COMPUTE ) { + bindPoint = GL_PIPELINE_BIND_POINT_COMPUTE; + } + size_t offset = 0; + for ( auto& pushConstant : shader.pushConstants ) { + // + if ( ext::json::isObject( shader.metadata["definitions"]["pushConstants"]["PushConstant"] ) ) { + if ( shader.descriptor.stage == uf::renderer::enums::Shader::VERTEX ) { + struct PushConstant { + uint32_t pass; + uint32_t draw; + } pushConstant = { pass, draw }; + vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, sizeof(pushConstant), &pushConstant ); + } + } else { + size_t len = pushConstant.data().len; + void* pointer = pushConstant.data().data; + if ( len > 0 && pointer ) { + vkCmdPushConstants( commandBuffer, pipelineLayout, shader.descriptor.stage, 0, len, pointer ); + } + } + } + } + // Bind descriptor sets describing shader binding points + vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + // Bind the rendering pipeline + // The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time + vkCmdBindPipeline(commandBuffer, bindPoint, pipeline); +#endif } void ext::opengl::Pipeline::update( Graphic& graphic ) { return this->update( graphic, graphic.descriptor ); } void ext::opengl::Pipeline::update( Graphic& graphic, GraphicDescriptor& descriptor ) { +#if 0 + // + if ( descriptorSet == GL_NULL_HANDLE ) return; + //descriptor = d; + // generate fallback empty texture + auto& emptyTexture = Texture2D::empty; + + RenderMode& renderMode = ext::opengl::getRenderMode(descriptor.renderMode, true); + auto& renderTarget = renderMode.getRenderTarget(descriptor.renderTarget ); + + std::vector descriptorSetLayoutBindings; + for ( auto& shader : graphic.material.shaders ) { + descriptorSetLayoutBindings.insert( descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.begin(), shader.descriptorSetLayoutBindings.end() ); + } + + struct { + std::vector uniform; + std::vector storage; + std::vector image; + std::vector sampler; + std::vector input; + } infos; + + if ( descriptor.subpass < renderTarget.passes.size() ) { + auto& subpass = renderTarget.passes[descriptor.subpass]; + for ( auto& input : subpass.inputs ) { + infos.input.push_back(ext::opengl::initializers::descriptorImageInfo( + renderTarget.attachments[input.attachment].view, + // input.layout + input.layout == GL_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? GL_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout + )); + } + } + + { + for ( auto& texture : graphic.material.textures ) { + infos.image.emplace_back(texture.descriptor); + } + for ( auto& sampler : graphic.material.samplers ) { + infos.sampler.emplace_back(sampler.descriptor.info); + } + } + + for ( auto& shader : graphic.material.shaders ) { + #define PARSE_BUFFER( buffers ) for ( auto& buffer : buffers ) {\ + if ( buffer.usageFlags & uf::renderer::enums::Buffer::UNIFORM ) {\ + infos.uniform.emplace_back(buffer.descriptor);\ + }\ + if ( buffer.usageFlags & uf::renderer::enums::Buffer::STORAGE ) {\ + infos.storage.emplace_back(buffer.descriptor);\ + }\ + } + + PARSE_BUFFER(shader.buffers) + PARSE_BUFFER(graphic.buffers) + + // check if we can even consume that many infos + size_t consumes = 0; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + switch ( layout.descriptorType ) { + // consume an texture image info + case GL_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case GL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case GL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + consumes += layout.descriptorCount; + } break; + } + } + for ( size_t i = infos.image.size(); i < consumes; ++i ) { + infos.image.push_back(emptyTexture.descriptor); + } + } + + auto uniformBufferInfo = infos.uniform.begin(); + auto storageBufferInfo = infos.storage.begin(); + auto imageInfo = infos.image.begin(); + auto samplerInfo = infos.sampler.begin(); + auto inputInfo = infos.input.begin(); + + #define BREAK_ASSERT(condition, ...) if ( condition ) { GL_VALIDATION_MESSAGE(#condition << "\t" << __VA_ARGS__); break; } + std::vector writeDescriptorSets; + for ( auto& shader : graphic.material.shaders ) { + // std::cout << shader.filename << ": " << std::endl; + // std::cout << "\tAVAILABLE UNIFORM BUFFERS: " << infos.uniform.size() << std::endl; + // std::cout << "\tAVAILABLE STORAGE BUFFERS: " << infos.storage.size() << std::endl; + // std::cout << "\tCONSUMING : " << shader.descriptorSetLayoutBindings.size() << std::endl; + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + // GL_VALIDATION_MESSAGE(shader.filename << "\tType: " << layout.descriptorType << "\tConsuming: " << layout.descriptorCount); + switch ( layout.descriptorType ) { + // consume an texture image info + case GL_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: + case GL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + case GL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + // std::cout << "\tINSERTING IMAGE" << std::endl; + BREAK_ASSERT( imageInfo == infos.image.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::opengl::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*imageInfo), + layout.descriptorCount + )); + imageInfo += layout.descriptorCount; + } break; + case GL_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { + // std::cout << "\tINSERTING INPUT_ATTACHMENT" << std::endl; + BREAK_ASSERT( inputInfo == infos.input.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::opengl::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*inputInfo), + layout.descriptorCount + )); + inputInfo += layout.descriptorCount; + } break; + case GL_DESCRIPTOR_TYPE_SAMPLER: { + // std::cout << "\tINSERTING SAMPLER" << std::endl; + BREAK_ASSERT( samplerInfo == infos.sampler.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::opengl::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*samplerInfo), + layout.descriptorCount + )); + samplerInfo += layout.descriptorCount; + } break; + case GL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + // std::cout << "\tINSERTING UNIFORM_BUFFER" << std::endl; + BREAK_ASSERT( uniformBufferInfo == infos.uniform.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::opengl::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*uniformBufferInfo), + layout.descriptorCount + )); + uniformBufferInfo += layout.descriptorCount; + } break; + case GL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + // std::cout << "\tINSERTING STORAGE_BUFFER" << std::endl; + BREAK_ASSERT( storageBufferInfo == infos.storage.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::opengl::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*storageBufferInfo), + layout.descriptorCount + )); + storageBufferInfo += layout.descriptorCount; + } break; + } + + } + } + + for ( auto& descriptor : writeDescriptorSets ) { + for ( size_t i = 0; i < descriptor.descriptorCount; ++i ) { + if ( descriptor.pBufferInfo ) { + if ( descriptor.pBufferInfo[i].offset % device->properties.limits.minUniformBufferOffsetAlignment != 0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Invalid descriptor for buffer: " << descriptor.pBufferInfo[i].buffer << " (Offset: " << descriptor.pBufferInfo[i].offset << ", Range: " << descriptor.pBufferInfo[i].range << "), invalidating..."); + goto PIPELINE_UPDATE_INVALID; + } + } + if ( descriptor.pImageInfo ) { + if ( descriptor.pImageInfo[i].imageView == 0x0 ) { + GL_DEBUG_VALIDATION_MESSAGE("Null image view, replacing with fallback texture..."); + auto pointer = const_cast(&descriptor.pImageInfo[i]); + *pointer = emptyTexture.descriptor; + } + if ( descriptor.pImageInfo[i].imageLayout == GL_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ) { + GL_DEBUG_VALIDATION_MESSAGE("Image layout is GL_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, fixing to GL_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL"); + auto pointer = const_cast(&descriptor.pImageInfo[i]); + pointer->imageLayout = GL_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + if ( descriptor.descriptorType == GL_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER && !descriptor.pImageInfo[i].sampler ) { + GL_DEBUG_VALIDATION_MESSAGE("Image descriptor type is GL_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, yet lacks a sampler, adding default sampler..."); + auto pointer = const_cast(&descriptor.pImageInfo[i]); + pointer->sampler = emptyTexture.sampler.sampler; + } + } + } + } + renderMode.rebuild = true; + graphic.process = true; + + vkUpdateDescriptorSets( + *device, + writeDescriptorSets.size(), + writeDescriptorSets.data(), + 0, + NULL + ); + return; + +PIPELINE_UPDATE_INVALID: + graphic.process = false; + GL_DEBUG_VALIDATION_MESSAGE("Pipeline update invalid, updating next tick..."); + uf::thread::add( uf::thread::get("Main"), [&]() -> int { + this->update( graphic, descriptor ); + return 0;}, true ); + return; +#endif } void ext::opengl::Pipeline::destroy() { +#if 0 if ( aliased ) return; + + if ( descriptorPool != GL_NULL_HANDLE) { + vkDestroyDescriptorPool( *device, descriptorPool, nullptr ); + descriptorPool = GL_NULL_HANDLE; + } + if ( pipelineLayout != GL_NULL_HANDLE ) { + vkDestroyPipelineLayout( *device, pipelineLayout, nullptr ); + pipelineLayout = GL_NULL_HANDLE; + } + if ( pipeline != GL_NULL_HANDLE ) { + vkDestroyPipeline( *device, pipeline, nullptr ); + pipeline = GL_NULL_HANDLE; + } + if ( descriptorSetLayout != GL_NULL_HANDLE ) { + vkDestroyDescriptorSetLayout( *device, descriptorSetLayout, nullptr ); + descriptorSetLayout = GL_NULL_HANDLE; + } +#endif } void ext::opengl::Material::initialize( Device& device ) { @@ -389,7 +1350,39 @@ void ext::opengl::Material::destroy() { samplers.clear(); } void ext::opengl::Material::attachShader( const std::string& filename, GLhandle(VkShaderStageFlagBits) stage ) { + auto& shader = shaders.emplace_back(); + shader.initialize( *device, filename, stage ); + // check how many samplers requested +#if 0 + for ( auto& layout : shader.descriptorSetLayoutBindings ) { + if ( layout.descriptorType != GL_DESCRIPTOR_TYPE_SAMPLER ) continue; + Sampler& sampler = samplers.emplace_back(); + sampler.initialize( *device ); + } +#endif + + std::string type = "unknown"; + switch ( stage ) { + case uf::renderer::enums::Shader::VERTEX: type = "vertex"; break; + case uf::renderer::enums::Shader::FRAGMENT: type = "fragment"; break; + case uf::renderer::enums::Shader::COMPUTE: type = "compute"; break; + /* + case uf::renderer::enums::Shader::TESSELLATION_CONTROL: type = "tessellation_control"; break; + case uf::renderer::enums::Shader::TESSELLATION_EVALUATION: type = "tessellation_evaluation"; break; + case uf::renderer::enums::Shader::GEOMETRY: type = "geometry"; break; + case uf::renderer::enums::Shader::ALL_GRAPHICS: type = "all_graphics"; break; + case uf::renderer::enums::Shader::ALL: type = "all"; break; + case uf::renderer::enums::Shader::RAYGEN_KHR: type = "raygen"; break; + case uf::renderer::enums::Shader::ANY_HIT_KHR: type = "any_hit"; break; + case uf::renderer::enums::Shader::CLOSEST_HIT_KHR: type = "closest_hit"; break; + case uf::renderer::enums::Shader::MISS_KHR: type = "miss"; break; + case uf::renderer::enums::Shader::INTERSECTION_KHR: type = "intersection"; break; + case uf::renderer::enums::Shader::CALLABLE_KHR: type = "callable"; break; + */ + } + metadata["shaders"][type]["index"] = shaders.size() - 1; + metadata["shaders"][type]["filename"] = filename; } void ext::opengl::Material::initializeShaders( const std::vector>& layout ) { shaders.clear(); shaders.reserve( layout.size() ); @@ -401,11 +1394,18 @@ bool ext::opengl::Material::hasShader( const std::string& type ) { return !ext::json::isNull( metadata["shaders"][type] ); } ext::opengl::Shader& ext::opengl::Material::getShader( const std::string& type ) { - static ext::opengl::Shader null; - return null; + if ( !hasShader(type) ) { + static ext::opengl::Shader null; + return null; + } + size_t index = metadata["shaders"][type]["index"].as(); + return shaders.at(index); } bool ext::opengl::Material::validate() { bool was = true; + for ( auto& shader : shaders ) { + if ( !shader.validate() ) was = false; + } return was; } ext::opengl::Graphic::~Graphic() { @@ -454,10 +1454,133 @@ void ext::opengl::Graphic::updatePipelines() { pair.second.update( *this ); } } -void ext::opengl::Graphic::record( GLhandle(VkCommandBuffer) commandBuffer, size_t pass, size_t draw ) { +void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, size_t pass, size_t draw ) { return this->record( commandBuffer, descriptor, pass, draw ); } -void ext::opengl::Graphic::record( GLhandle(VkCommandBuffer) commandBuffer, GraphicDescriptor& descriptor, size_t pass, size_t draw ) { +void ext::opengl::Graphic::record( CommandBuffer& commandBuffer, GraphicDescriptor& descriptor, size_t pass, size_t draw ) { + if ( !process ) return; +/* + if ( !this->hasPipeline( descriptor ) ) { + GL_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline"); + return; + } + auto& pipeline = this->getPipeline( descriptor ); + if ( pipeline.descriptorSet == GL_NULL_HANDLE ) { + GL_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline descriptor set"); + return; + } + pipeline.record(*this, commandBuffer, pass, draw); +*/ + + Buffer* vertexBuffer = NULL; + Buffer* indexBuffer = NULL; + for ( auto& buffer : buffers ) { + if ( buffer.usageFlags & uf::renderer::enums::Buffer::VERTEX ) vertexBuffer = &buffer; + if ( buffer.usageFlags & uf::renderer::enums::Buffer::INDEX ) indexBuffer = &buffer; + } + if ( !vertexBuffer || !indexBuffer ) return; + + size_t vertexStride = this->descriptor.geometry.sizes.vertex; + + size_t vertices = vertexBuffer->size / vertexStride; + size_t indices = this->descriptor.indices; //indexBuffer->size / this->descriptor.geometry.sizes.indices; + + uint32_t* indicesPointer = (uint32_t*) indexBuffer->buffer; + uint32_t* indicesPointerEnd = indicesPointer + indices; + uint8_t* vertexPointer = (uint8_t*) vertexBuffer->buffer; + + uf::renderer::VertexDescriptor vertexAttributePosition, vertexAttributeNormal, vertexAttributeColor, vertexAttributeUv; + for ( auto& attribute : descriptor.geometry.attributes ) { + if ( attribute.name == "position" ) vertexAttributePosition = attribute; + else if ( attribute.name == "normal" ) vertexAttributeNormal = attribute; + else if ( attribute.name == "color" ) vertexAttributeColor = attribute; + else if ( attribute.name == "uv" ) vertexAttributeUv = attribute; + } + + struct GLvertex { + pod::Vector3f position = {}; + pod::Vector3f normal = {}; + pod::Vector3f color = {}; + pod::Vector2f uv = {}; + }; + std::vector glMesh; + + size_t vertexColorState = 0; + while ( indicesPointer < indicesPointerEnd ) { + auto& glVertex = glMesh.emplace_back(); + + uint32_t index = *(indicesPointer++); + uint8_t* vertex = vertexPointer + (index * vertexStride); + + if ( vertexAttributePosition.name != "" ) { + /*float positionX*/ glVertex.position[0]= *((float*) (vertex + vertexAttributePosition.offset + sizeof(float) * 0)); + /*float positionY*/ glVertex.position[1]= *((float*) (vertex + vertexAttributePosition.offset + sizeof(float) * 1)); + /*float positionZ*/ glVertex.position[2]= *((float*) (vertex + vertexAttributePosition.offset + sizeof(float) * 2)); + } + if ( vertexAttributeNormal.name != "" ) { + /*float normalX*/ glVertex.normal[0]= *((float*) (vertex + vertexAttributeNormal.offset + sizeof(float) * 0)); + /*float normalY*/ glVertex.normal[1]= *((float*) (vertex + vertexAttributeNormal.offset + sizeof(float) * 1)); + /*float normalZ*/ glVertex.normal[2]= *((float*) (vertex + vertexAttributeNormal.offset + sizeof(float) * 2)); + } + if ( vertexAttributeColor.name != "" ) { + /*float colorR*/ glVertex.color[0] = *((float*) (vertex + vertexAttributeColor.offset + sizeof(float) * 0)); + /*float colorG*/ glVertex.color[1] = *((float*) (vertex + vertexAttributeColor.offset + sizeof(float) * 1)); + /*float colorB*/ glVertex.color[2] = *((float*) (vertex + vertexAttributeColor.offset + sizeof(float) * 2)); + } else { + switch ( vertexColorState ) { + case 0: glVertex.color = {1, 0, 0}; break; + case 1: glVertex.color = {0, 1, 0}; break; + case 2: glVertex.color = {0, 0, 1}; break; + } + if ( ++vertexColorState > 2 ) vertexColorState = 0; + } + if ( vertexAttributeUv.name != "" ) { + /*float uvU*/ glVertex.uv[0] = *((float*) (vertex + vertexAttributeUv.offset + sizeof(float) * 0)); + /*float uvV*/ glVertex.uv[1] = *((float*) (vertex + vertexAttributeUv.offset + sizeof(float) * 1)); + } + } +#if 0 + commandBuffer.record([=]{ + glBegin(GL_POLYGON); + for ( auto& glVertex : glMesh ) { + glVertex3f(glVertex.position[0], glVertex.position[1], glVertex.position[2]); + glNormal3f(glVertex.normal[0], glVertex.normal[1], glVertex.normal[2]); + glColor3f(glVertex.color[0], glVertex.color[1], glVertex.color[2]); + glTexCoord2f(glVertex.uv[0], glVertex.uv[1]); + } + glEnd(); + }); +#else + commandBuffer.record([=]{ + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + }); +#endif +#if 0 + // Bind triangle vertex buffer (contains position and colors) + GLhandle(VkDeviceSize) offsets[1] = { descriptor.offsets.vertex }; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertexBuffer->buffer, offsets); + // Bind triangle index buffer + GLhandle(VkIndexType) indicesType = GL_INDEX_TYPE_UINT32; + switch ( descriptor.geometry.sizes.indices * 8 ) { + case 8: indicesType = GL_INDEX_TYPE_UINT8_EXT; break; + case 16: indicesType = GL_INDEX_TYPE_UINT16; break; + case 32: indicesType = GL_INDEX_TYPE_UINT32; break; + default: + throw std::runtime_error("invalid indices size of " + std::to_string((int) descriptor.geometry.sizes.indices)); + break; + } + vkCmdBindIndexBuffer(commandBuffer, indexBuffer->buffer, descriptor.offsets.index, indicesType); + // Draw indexed triangle + vkCmdDrawIndexed(commandBuffer, descriptor.indices, 1, 0, 0, 1); + //std::cout << (int) descriptor.indices << "\t" << (int) descriptor.offsets.index << std::endl; +#endif } void ext::opengl::Graphic::destroy() { for ( auto& pair : pipelines ) pair.second.destroy(); @@ -471,15 +1594,37 @@ void ext::opengl::Graphic::destroy() { } bool ext::opengl::Graphic::hasStorage( const std::string& name ) { + for ( auto& shader : material.shaders ) { + if ( shader.hasStorage(name) ) return true; + } return false; } ext::opengl::Buffer* ext::opengl::Graphic::getStorageBuffer( const std::string& name ) { + size_t storageIndex = -1; + for ( auto& shader : material.shaders ) { + if ( !shader.hasStorage(name) ) continue; + storageIndex = shader.metadata["definitions"]["storage"][name]["index"].as(); + break; + } + for ( size_t bufferIndex = 0, storageCounter = 0; bufferIndex < buffers.size(); ++bufferIndex ) { + if ( !(buffers[bufferIndex].usageFlags & uf::renderer::enums::Buffer::STORAGE) ) continue; + if ( storageCounter++ != storageIndex ) continue; + return &buffers[bufferIndex]; + } return NULL; } uf::Serializer ext::opengl::Graphic::getStorageJson( const std::string& name, bool cache ) { + for ( auto& shader : material.shaders ) { + if ( !shader.hasStorage(name) ) continue; + return shader.getStorageJson(name, cache); + } return ext::json::null(); } ext::opengl::userdata_t ext::opengl::Graphic::getStorageUserdata( const std::string& name, const ext::json::Value& payload ) { + for ( auto& shader : material.shaders ) { + if ( !shader.hasStorage(name) ) continue; + return shader.getStorageUserdata(name, payload); + } return ext::opengl::userdata_t(); } diff --git a/engine/src/ext/opengl/opengl.cpp b/engine/src/ext/opengl/opengl.cpp index 6d5db7a8..064743b0 100644 --- a/engine/src/ext/opengl/opengl.cpp +++ b/engine/src/ext/opengl/opengl.cpp @@ -55,51 +55,15 @@ std::vector ext::opengl::renderModes = { new ext::opengl::BaseRenderMode, }; -void UF_API ext::opengl::initialize() { - glewExperimental = GL_TRUE; - if ( glewInit() != GLEW_OK ) { - return; - } -/* - device.initialize(); - swapchain.initialize( device ); -*/ - 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 ); - } - { - 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 = uf::renderer::enums::Filter::NEAREST; - Texture2D::empty.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; - Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, 2, 2 ); - } -} std::string UF_API ext::opengl::errorString() { +#if UF_ENV_DREAMCAST +#else GLenum error; const GLubyte* bytes = NULL; if ((error = glGetError()) != GL_NO_ERROR) bytes = gluErrorString(error); std::string str = (const char*) bytes; return str; +#endif } ///// @@ -161,6 +125,40 @@ 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 ); + 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 ); + } + { + 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 = uf::renderer::enums::Filter::NEAREST; + Texture2D::empty.sampler.descriptor.filter.mag = uf::renderer::enums::Filter::NEAREST; + Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, 2, 2 ); + } +} void UF_API ext::opengl::tick(){ ext::opengl::mutex.lock(); if ( ext::opengl::states::resized || ext::opengl::settings::experimental::rebuildOnTickBegin ) { @@ -235,11 +233,13 @@ void UF_API ext::opengl::render(){ if ( ext::opengl::settings::experimental::waitOnRenderEnd ) { synchronize(); } +#if UF_USE_OPENVR /* if ( ext::openvr::context ) { ext::openvr::postSubmit(); } */ +#endif ext::opengl::mutex.unlock(); } void UF_API ext::opengl::destroy() { @@ -263,11 +263,9 @@ void UF_API ext::opengl::destroy() { renderMode->destroy(); renderMode = NULL; } -/* - swapchain.destroy(); +// swapchain.destroy(); device.destroy(); -*/ - ext::opengl::mutex.unlock(); + ext::opengl::mutex.unlock(); } void UF_API ext::opengl::synchronize( uint8_t flag ) { if ( flag & 0b01 ) { diff --git a/engine/src/ext/opengl/rendermode.cpp b/engine/src/ext/opengl/rendermode.cpp index 9bded4d8..21c5ddd3 100644 --- a/engine/src/ext/opengl/rendermode.cpp +++ b/engine/src/ext/opengl/rendermode.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include @@ -51,23 +53,144 @@ void ext::opengl::RenderMode::bindGraphicPushConstants( ext::opengl::Graphic* po } void ext::opengl::RenderMode::createCommandBuffers() { + if ( this->getName() != "" ) return; this->execute = true; - std::vector graphics; + this->synchronize(); + + float width = this->width > 0 ? this->width : ext::opengl::settings::width; + float height = this->height > 0 ? this->height : ext::opengl::settings::height; + +#if 0 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, ext::opengl::settings::width, ext::opengl::settings::height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(-1.5f,0.0f,-6.0f); + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + glTranslatef(3.0f,0.0f,0.0f); + glBegin(GL_QUADS); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); +#endif +#if 1 + auto& commands = getCommands(); + commands.flush(); + commands.record([]{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + }); + commands.record([]{ + glViewport(0, 0, ext::opengl::settings::width, ext::opengl::settings::height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + }); + commands.record([]{ + glTranslatef(-1.5f,0.0f,-6.0f); + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + }); + commands.record([]{ + glTranslatef(3.0f,0.0f,0.0f); + glBegin(GL_QUADS); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f, 1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.5f,0.5f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + }); +#endif +#if 0 + auto& commands = getCommands(); + commands.flush(); + std::vector entities; std::function filter = [&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; ext::opengl::Graphic& graphic = entity->getComponent(); - if ( !graphic.initialized || !graphic.process ) return; - graphics.push_back(&graphic); + if ( !graphic.initialized || !graphic.process || graphic.descriptor.renderMode != this->getName() ) return; + entities.emplace_back(entity); }; + size_t currentDraw = 0; + size_t currentPass = 0; + size_t currentSubpass = 0; for ( uf::Scene* scene : uf::scene::scenes ) { if ( !scene ) continue; scene->process(filter); - } + + auto& controller = scene->getController(); + auto& camera = controller.getComponent(); + auto& sceneMetadata = scene->getComponent(); + if ( !ext::json::isNull( sceneMetadata["system"]["renderer"]["clear values"][0] ) ) { + auto& v = sceneMetadata["system"]["renderer"]["clear values"][0]; + commands.record([=](){ + glClearColor(v[0].as(), v[1].as(), v[2].as(), v[3].as()); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + }); + } - this->synchronize(); + auto& view = camera.getView(); + auto& projection = camera.getProjection(); + + commands.record([=](){ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glLoadMatrixf( &projection[0] ); + }); + + for ( auto* pointer : entities ) { + uf::Object& entity = pointer->as(); + auto& graphic = entity.getComponent(); + + auto& transform = entity.getComponent>(); + auto model = view * uf::transform::model( transform ); + commands.record([=](){ + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glLoadMatrixf( &model[0] ); + }); + + auto descriptor = bindGraphicDescriptor(graphic.descriptor, currentSubpass); + graphic.record( commands, descriptor, currentPass, currentDraw++ ); + } + entities.clear(); + } +#endif +// std::cout << "Recording | " << this->getName() << ": " << this->getType() << " | Commands: " << commands.size() << std::endl; // bindPipelines( graphics ); - createCommandBuffers( graphics ); +// createCommandBuffers( graphics ); this->mostRecentCommandPoolId = std::this_thread::get_id(); this->rebuild = false; } @@ -117,6 +240,15 @@ void ext::opengl::RenderMode::bindPipelines( const std::vectormostRecentCommandPoolId ); + commands.submit(); + if (device && device->context && device->context->setActive(true)) { + device->context->display(); + } +#endif } void ext::opengl::RenderMode::initialize( Device& device ) { @@ -136,7 +268,9 @@ void ext::opengl::RenderMode::tick() { void ext::opengl::RenderMode::destroy() { this->synchronize(); - + for ( auto& pair : this->commands.container() ) { + pair.second.flush(); + } renderTarget.destroy(); } void ext::opengl::RenderMode::synchronize( uint64_t timeout ) { diff --git a/engine/src/ext/opengl/rendermodes/base.cpp b/engine/src/ext/opengl/rendermodes/base.cpp index 76a4c8ec..ac1b5464 100644 --- a/engine/src/ext/opengl/rendermodes/base.cpp +++ b/engine/src/ext/opengl/rendermodes/base.cpp @@ -14,16 +14,76 @@ const std::string ext::opengl::BaseRenderMode::getType() const { void ext::opengl::BaseRenderMode::createCommandBuffers( const std::vector& graphics ) { } +void ext::opengl::BaseRenderMode::initialize( Device& device ) { + this->metadata["name"] = "Swapchain"; + auto windowSize = device.window->getSize(); + this->width = windowSize.x; + this->height = windowSize.y; + + ext::opengl::RenderMode::initialize( device ); + +#if 1 + { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0); + glDepthFunc(GL_LESS); + glEnable(GL_DEPTH_TEST); + glShadeModel(GL_SMOOTH); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(90.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); // Calculate The Aspect Ratio Of The Window + glMatrixMode(GL_MODELVIEW); + } +#endif +} + void ext::opengl::BaseRenderMode::tick() { + ext::opengl::RenderMode::tick(); +#if 0 + if ( ext::opengl::states::resized ) { + if ( ext::opengl::settings::height <= 0 ) ext::opengl::settings::height = 1; + + glViewport(0, 0, ext::opengl::settings::width, ext::opengl::settings::height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0f,(GLfloat) ext::opengl::settings::width / (GLfloat) ext::opengl::settings::height, 0.1f, 100.0f); // Calculate The Aspect Ratio Of The Window + glMatrixMode(GL_MODELVIEW); + } +#endif } void ext::opengl::BaseRenderMode::render() { +#if 0 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); -} + glTranslatef(-1.5f,0.0f,-6.0f); -void ext::opengl::BaseRenderMode::initialize( Device& device ) { + glBegin(GL_POLYGON); + glColor3f(1.0f,0.0f,0.0f); + glVertex3f( 0.0f, 1.0f, 0.0f); + glColor3f(0.0f,1.0f,0.0f); + glVertex3f( 1.0f,-1.0f, 0.0f); + glColor3f(0.0f,0.0f,1.0f); + glVertex3f(-1.0f,-1.0f, 0.0f); + glEnd(); + + glTranslatef(3.0f,0.0f,0.0f); + + glColor3f(0.5f,0.5f,1.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(); +#endif + if ( ext::opengl::renderModes.size() > 1 ) return; + ext::opengl::RenderMode::render(); } void ext::opengl::BaseRenderMode::destroy() { + ext::opengl::RenderMode::destroy(); } #endif \ No newline at end of file diff --git a/engine/src/ext/opengl/rendermodes/deferred.cpp b/engine/src/ext/opengl/rendermodes/deferred.cpp index 581bfdf0..5683767a 100644 --- a/engine/src/ext/opengl/rendermodes/deferred.cpp +++ b/engine/src/ext/opengl/rendermodes/deferred.cpp @@ -28,6 +28,11 @@ std::vector ext::opengl::DeferredRenderMode::getBlitters( } void ext::opengl::DeferredRenderMode::initialize( Device& device ) { + auto windowSize = device.window->getSize(); + this->width = windowSize.x; + this->height = windowSize.y; + + ext::opengl::RenderMode::initialize( device ); } void ext::opengl::DeferredRenderMode::tick() { ext::opengl::RenderMode::tick(); diff --git a/engine/src/ext/openvr/openvr.cpp b/engine/src/ext/openvr/openvr.cpp index e259c784..301c3867 100644 --- a/engine/src/ext/openvr/openvr.cpp +++ b/engine/src/ext/openvr/openvr.cpp @@ -1,4 +1,6 @@ #include + +#if UF_USE_OPENVR #include #include #include @@ -723,4 +725,5 @@ uf::Graphic& ext::openvr::controllerRenderModel( vr::Controller_Hand hand ) { if ( hand == vr::Controller_Hand::Hand_Left ) return renderModels["{indexcontroller}valve_controller_knu_1_0_left"]; //return ::devices.controllers.left.mesh; else if ( hand == vr::Controller_Hand::Hand_Right ) return renderModels["{indexcontroller}valve_controller_knu_1_0_right"]; //return ::devices.controllers.right.mesh; throw false; //std::exception("error"); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/ultralight/ultralight.cpp b/engine/src/ext/ultralight/ultralight.cpp index cc6249a2..632dab47 100644 --- a/engine/src/ext/ultralight/ultralight.cpp +++ b/engine/src/ext/ultralight/ultralight.cpp @@ -1,10 +1,10 @@ #include - +#if UF_USE_ULTRALIGHT #include #include #include -// std::string ext::ultralight::resourcesDir = "./data/resources/"; +// std::string ext::ultralight::resourcesDir = uf::io::root + "/resources/"; namespace { size_t uids = 0; @@ -181,11 +181,11 @@ void ext::ultralight::initialize() { ulConfigSetDeviceScale(config, ext::ultralight::scale); ulConfigSetFontFamilyStandard(config, UL::String("Arial")); - ulConfigSetResourcePath(config, UL::String("./data/html/resources/")); + ulConfigSetResourcePath(config, UL::String(uf::io::root + "/html/resources/")); ulConfigSetUseGPURenderer(config, false); ulEnablePlatformFontLoader(); - ulEnablePlatformFileSystem(UL::String("./data/html/assets/")); - ulEnableDefaultLogger(UL::String("./data/logs/ultralight.log")); + ulEnablePlatformFileSystem(UL::String(uf::io::root + "/html/assets/")); + ulEnableDefaultLogger(UL::String(uf::io::root + "/logs/ultralight.log")); ::renderer = ulCreateRenderer(config); @@ -266,4 +266,5 @@ uf::Image ext::ultralight::capture( pod::HTML& container ) { ulBitmapUnlockPixels(bitmap); ulBitmapSwapRedBlueChannels(bitmap); return image; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/ext/vorbis/vorbis.cpp b/engine/src/ext/vorbis/vorbis.cpp index 1a96ef3a..b30f6b02 100644 --- a/engine/src/ext/vorbis/vorbis.cpp +++ b/engine/src/ext/vorbis/vorbis.cpp @@ -1,7 +1,10 @@ #include -#if defined(UF_USE_VORBIS) +#if UF_USE_VORBIS +#if UF_USE_OPENAL #include +#endif + #include #include #include @@ -28,7 +31,9 @@ void UF_API_CALL ext::Vorbis::load( const std::string& filename ) { } vorbis_info* info = ov_info(&file, -1); - this->m_format = info->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + #if UF_USE_OPENAL + this->m_format = info->channels == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; + #endif this->m_frequency = info->rate; do { diff --git a/engine/src/ext/vulkan/rendermodes/compute.cpp b/engine/src/ext/vulkan/rendermodes/compute.cpp index 68d31bd4..1cae4fa6 100644 --- a/engine/src/ext/vulkan/rendermodes/compute.cpp +++ b/engine/src/ext/vulkan/rendermodes/compute.cpp @@ -42,7 +42,7 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { compute.material.device = &device; compute.descriptor.renderMode = this->getName(); compute.material.initializeShaders({ - {"./data/shaders/raytracing.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT}, + {uf::io::root+"/shaders/raytracing.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT}, }); for ( size_t i = 0; i < (ext::openvr::context ? 2 : 1); ++i ) { @@ -96,8 +96,8 @@ void ext::vulkan::ComputeRenderMode::initialize( Device& device ) { blitter.initializeGeometry( mesh ); blitter.material.initializeShaders({ - {"./data/shaders/display.blit.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {"./data/shaders/display.blit.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} + {uf::io::root+"/shaders/display.blit.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, + {uf::io::root+"/shaders/display.blit.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} }); for ( auto& computeTexture : compute.material.textures ) { Texture2D& texture = blitter.material.textures.emplace_back(); diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 3b0300c3..8d4a4b02 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -191,8 +191,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { blitter.initializeGeometry( mesh ); blitter.material.initializeShaders({ - {"./data/shaders/display.subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {"./data/shaders/display.subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} + {uf::io::root+"/shaders/display.subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, + {uf::io::root+"/shaders/display.subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} }); { auto& scene = uf::scene::getCurrentScene(); diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index f8c35e0e..2765d90a 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -251,8 +251,8 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { blitter.material.device = &device; blitter.initializeGeometry( mesh ); blitter.material.initializeShaders({ - {"./data/shaders/display.renderTarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, - {"./data/shaders/display.renderTarget.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} + {uf::io::root+"/shaders/display.renderTarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT}, + {uf::io::root+"/shaders/display.renderTarget.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT} }); for ( auto& attachment : renderTarget.attachments ) { diff --git a/engine/src/spec/context/universal.cpp b/engine/src/spec/context/universal.cpp index d4f81dc9..a684f729 100644 --- a/engine/src/spec/context/universal.cpp +++ b/engine/src/spec/context/universal.cpp @@ -4,7 +4,6 @@ #include #include -#if defined(UF_USE_OPENGL) && UF_USE_OPENGL == 1 namespace { // This per-thread variable holds the current context for each thread // sf::ThreadLocalPtr currentContext(NULL); @@ -138,6 +137,4 @@ int UF_API_CALL spec::uni::Context::evaluateFormat( const spec::uni::Context::Se std::abs(int(settings.depthBits - depthBits)) + std::abs(int(settings.stencilBits - stencilBits)) + std::abs(int(settings.antialiasingLevel - antialiasing)); -} -#else -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/engine/src/spec/context/windows.cpp b/engine/src/spec/context/windows.cpp index 25a27ea2..5d612286 100644 --- a/engine/src/spec/context/windows.cpp +++ b/engine/src/spec/context/windows.cpp @@ -2,7 +2,7 @@ #include -#if defined(UF_ENV_WINDOWS) && (!defined(UF_USE_SFML) || (defined(UF_USE_SFML) && UF_USE_SFML == 0)) && (defined(UF_USE_OPENGL) && UF_USE_OPENGL == 1) +#if UF_ENV_WINDOWS && !UF_USE_SFML UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings ) : uni::Context( NULL, true, settings ), m_deviceContext (NULL), @@ -11,19 +11,21 @@ UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context:: // Creating a dummy window is mandatory: we could create a memory DC but then // its pixel format wouldn't match the regular contexts' format, and thus // wglShareLists would always fail. Too bad... - +#if UF_USE_OPENGL // Create a dummy window (disabled and hidden) this->m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL); ShowWindow(this->m_window, SW_HIDE); this->m_deviceContext = GetDC(this->m_window); if ( this->m_deviceContext ) this->create(shared); +#endif } UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings, const Context::window_t& window ) : uni::Context( NULL, false, settings ), m_deviceContext (NULL), m_context (NULL) { +#if UF_USE_OPENGL // Get the owner window and its device context this->m_window = window.getHandle(); this->m_deviceContext = GetDC(this->m_window); @@ -31,6 +33,7 @@ UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context:: // Create the context if ( this->m_deviceContext ) this->create(shared); +#endif } UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings, unsigned int width, unsigned int height ) : Context( shared, settings ) { @@ -40,128 +43,9 @@ spec::win32::Context::~Context() { } void UF_API_CALL spec::win32::Context::create( uni::Context* shared ) { +#if UF_USE_OPENGL // this->m_settings = settings; - Context::Settings l_settings(24, 4, 0, 3, 3); - - int bestFormat = 0; - - // Find a pixel format with no antialiasing, if not needed or not supported - if (bestFormat == 0) { - // Setup a pixel format descriptor from the rendering settings - PIXELFORMATDESCRIPTOR descriptor; - ZeroMemory(&descriptor, sizeof(descriptor)); - descriptor.nSize = sizeof(descriptor); - descriptor.nVersion = 1; - descriptor.iLayerType = PFD_MAIN_PLANE; - descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - descriptor.iPixelType = PFD_TYPE_RGBA; - descriptor.cColorBits = (BYTE) l_settings.bitsPerPixel; - descriptor.cDepthBits = (BYTE) l_settings.depthBits; - descriptor.cStencilBits = (BYTE) l_settings.stencilBits; - descriptor.cAlphaBits = l_settings.bitsPerPixel == 32 ? 8 : 0; - - // Get the pixel format that best matches our requirements - bestFormat = ChoosePixelFormat(this->m_deviceContext, &descriptor); - if (bestFormat == 0) { - uf::iostream << "[" << uf::IoStream::Color()("Red") << "ERROR" << "]" << "Failed to find a suitable pixel format for device context -- cannot create OpenGL context" << "\n"; - return; - } - } - - // Extract the depth and stencil bits from the chosen format - PIXELFORMATDESCRIPTOR actualFormat; - actualFormat.nSize = sizeof(actualFormat); - actualFormat.nVersion = 1; - DescribePixelFormat(this->m_deviceContext, bestFormat, sizeof(actualFormat), &actualFormat); - l_settings.depthBits = actualFormat.cDepthBits; - l_settings.stencilBits = actualFormat.cStencilBits; - - // Set the chosen pixel format - if (!SetPixelFormat(this->m_deviceContext, bestFormat, &actualFormat)) { - uf::iostream << "[" << uf::IoStream::Color()("Red") << "ERROR" << "]" << "Failed to set pixel format for device context -- cannot create OpenGL context" << "\n"; - return; - } - - // Get the context to share display lists with - HGLRC sharedContext = shared ? ((win32::Context*) shared)->m_context : NULL; - - // If the OpenGL >= 3.0 context failed or if we don't want one, create a regular OpenGL 1.x/2.x context - if (!this->m_context) { - // set the context version to 2.0 (arbitrary) - l_settings.majorVersion = 2; - l_settings.minorVersion = 0; - - // Share this context with others - if (sharedContext) { - - } - } -} -void UF_API_CALL spec::win32::Context::terminate() { - // Destroy the OpenGL context - if ( this->m_context ) { - - } - - // Destroy the device context - if ( this->m_deviceContext ) ReleaseDC(this->m_window, this->m_deviceContext); - - // Destroy the window if we own it - if ( this->m_window && this->m_ownsWindow ) DestroyWindow(this->m_window); -} - -bool spec::win32::Context::makeCurrent() { - return true; -} - -void spec::win32::Context::display() { - if (this->m_deviceContext && this->m_context) - SwapBuffers(this->m_deviceContext); -} - -void spec::win32::Context::setVerticalSyncEnabled(bool enabled) { - -} -# elif defined(UF_USE_OPENGL) && UF_USE_OPENGL == 0 -UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings ) : - uni::Context( NULL, true, settings ), - m_deviceContext (NULL), - m_context (NULL) -{ - // Creating a dummy window is mandatory: we could create a memory DC but then - // its pixel format wouldn't match the regular contexts' format, and thus - // wglShareLists would always fail. Too bad... - - // Create a dummy window (disabled and hidden) - this->m_window = CreateWindowA("STATIC", "", WS_POPUP | WS_DISABLED, 0, 0, 1, 1, NULL, NULL, GetModuleHandle(NULL), NULL); - ShowWindow(this->m_window, SW_HIDE); - this->m_deviceContext = GetDC(this->m_window); - - if ( this->m_deviceContext ) this->create(shared); -} -UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings, const Context::window_t& window ) : - uni::Context( NULL, false, settings ), - m_deviceContext (NULL), - m_context (NULL) -{ - // Get the owner window and its device context - this->m_window = window.getHandle(); - this->m_deviceContext = GetDC(this->m_window); - - // Create the context - if ( this->m_deviceContext ) - this->create(shared); -} -UF_API_CALL spec::win32::Context::Context( uni::Context* shared, const Context::Settings& settings, unsigned int width, unsigned int height ) : Context( shared, settings ) { - -} -spec::win32::Context::~Context() { - this->terminate(); -} - -void UF_API_CALL spec::win32::Context::create( uni::Context* shared ) { -// this->m_settings = settings; - Context::Settings l_settings(24, 4, 0, 3, 3); + Context::Settings l_settings{24, 4, 8, 0, 3, 3}; int bestFormat = 0; if ( l_settings.antialiasingLevel > 0 ) { @@ -322,8 +206,10 @@ void UF_API_CALL spec::win32::Context::create( uni::Context* shared ) { } } } +#endif } void UF_API_CALL spec::win32::Context::terminate() { +#if UF_USE_OPENGL // Destroy the OpenGL context if ( this->m_context ) { if ( wglGetCurrentContext() == this->m_context) wglMakeCurrent(NULL, NULL); @@ -335,19 +221,28 @@ void UF_API_CALL spec::win32::Context::terminate() { // Destroy the window if we own it if ( this->m_window && this->m_ownsWindow ) DestroyWindow(this->m_window); +#endif } bool spec::win32::Context::makeCurrent() { +#if UF_USE_OPENGL return this->m_deviceContext && this->m_context && wglMakeCurrent(this->m_deviceContext, this->m_context); +#else + return true; +#endif } void spec::win32::Context::display() { +#if UF_USE_OPENGL if (this->m_deviceContext && this->m_context) SwapBuffers(this->m_deviceContext); +#endif } void spec::win32::Context::setVerticalSyncEnabled(bool enabled) { +#if UF_USE_OPENGL PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = reinterpret_cast(wglGetProcAddress("wglSwapIntervalEXT")); if (wglSwapIntervalEXT) wglSwapIntervalEXT(enabled ? 1 : 0); +#endif } #endif \ No newline at end of file diff --git a/engine/src/spec/terminal/dreamcast.cpp b/engine/src/spec/terminal/dreamcast.cpp new file mode 100644 index 00000000..321a444a --- /dev/null +++ b/engine/src/spec/terminal/dreamcast.cpp @@ -0,0 +1,17 @@ +#include + +#ifdef UF_ENV_DREAMCAST + +void UF_API_CALL spec::Terminal::clear() { + spec::uni::Terminal::clear(); +} +void UF_API_CALL spec::Terminal::setLocale() { + spec::uni::Terminal::setLocale(); +} + +void UF_API_CALL spec::Terminal::hide() { +} +void UF_API_CALL spec::Terminal::show() { +} + +#endif \ No newline at end of file diff --git a/engine/src/spec/terminal/universal.cpp b/engine/src/spec/terminal/universal.cpp index a3bdfff7..02d65d3c 100644 --- a/engine/src/spec/terminal/universal.cpp +++ b/engine/src/spec/terminal/universal.cpp @@ -18,6 +18,8 @@ void UF_API_CALL spec::uni::Terminal::hide() { void UF_API_CALL spec::uni::Terminal::show() { } void UF_API_CALL spec::uni::Terminal::setLocale() { +#if UF_ENV_DREAMCAST +#else const char* locales[4] = { "", "C.utf8", "C", "POSIX" }; @@ -33,4 +35,5 @@ void UF_API_CALL spec::uni::Terminal::setLocale() { continue; } } +#endif } \ No newline at end of file diff --git a/engine/src/spec/terminal/unknown.cpp b/engine/src/spec/terminal/unknown.cpp index 569c7278..3586ab11 100644 --- a/engine/src/spec/terminal/unknown.cpp +++ b/engine/src/spec/terminal/unknown.cpp @@ -1,6 +1,6 @@ #include -#ifdef UF_ENV_UNKNOWN +#if UF_ENV_UNKNOWN void UF_API_CALL spec::Terminal::clear() { spec::uni::Terminal::clear(); diff --git a/engine/src/spec/time/dreamcast.cpp b/engine/src/spec/time/dreamcast.cpp new file mode 100644 index 00000000..3a998719 --- /dev/null +++ b/engine/src/spec/time/dreamcast.cpp @@ -0,0 +1,7 @@ +#include + +#ifdef UF_ENV_DREAMCAST + +spec::dreamcast::Time spec::time; +spec::dreamcast::Time::exp_t spec::dreamcast::Time::unit = -6; +#endif \ No newline at end of file diff --git a/engine/src/spec/window/dreamcast.cpp b/engine/src/spec/window/dreamcast.cpp new file mode 100644 index 00000000..37bedbd0 --- /dev/null +++ b/engine/src/spec/window/dreamcast.cpp @@ -0,0 +1,216 @@ +#include +#include +#include + +#if UF_ENV_DREAMCAST + +/* + +INIT_NONE -- don't do any auto init +INIT_IRQ -- Enable IRQs +INIT_THD_PREEMPT -- Enable pre-emptive threading +INIT_NET -- Enable networking (including sockets) +INIT_MALLOCSTATS -- Enable a call to malloc_stats() right before shutdown + +*/ + +extern uint8 romdisk[]; +KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS); +KOS_INIT_ROMDISK(romdisk); + +namespace { + struct { + maple_device_t* device = NULL; + cont_state_t* state = NULL; + } controller, keyboard; +} + +UF_API_CALL spec::dreamcast::Window::Window() : + m_handle (NULL), +// m_callback (0), +// m_cursor (NULL), +// m_icon (NULL), + m_lastSize ({}), + m_keyRepeatEnabled (true), + m_resizing (false), + m_mouseInside (false), + m_mouseGrabbed (false), + m_syncParse (true), + m_asyncParse (false) +{ +} +UF_API_CALL spec::dreamcast::Window::Window( spec::dreamcast::Window::handle_t handle ) : + m_handle (handle), +// m_callback (0), +// m_cursor (NULL), +// m_icon (NULL), + m_lastSize ({}), + m_keyRepeatEnabled (true), + m_resizing (false), + m_mouseInside (false), + m_mouseGrabbed (false), + m_syncParse (true), + m_asyncParse (false) +{ + +} +UF_API_CALL spec::dreamcast::Window::Window( const spec::dreamcast::Window::vector_t& size, const spec::dreamcast::Window::title_t& title ) : + m_handle (NULL), +// m_callback (0), +// m_cursor (NULL), +// m_icon (NULL), + m_keyRepeatEnabled (true), + m_resizing (false), + m_mouseInside (false), + m_mouseGrabbed (false), + m_syncParse (true), + m_asyncParse (false) +{ + 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); +} + +spec::dreamcast::Window::~Window() { +} +void UF_API_CALL spec::dreamcast::Window::terminate() { +} + +spec::dreamcast::Window::handle_t UF_API_CALL spec::dreamcast::Window::getHandle() const { + return this->m_handle; +} +spec::dreamcast::Window::vector_t UF_API_CALL spec::dreamcast::Window::getPosition() const { + return { 0, 0 }; +} +spec::dreamcast::Window::vector_t UF_API_CALL spec::dreamcast::Window::getSize() const { + return { 0, 0 }; +} +size_t UF_API_CALL spec::dreamcast::Window::getRefreshRate() const { + return 60; +} + +void UF_API_CALL spec::dreamcast::Window::centerWindow() { +} +void UF_API_CALL spec::dreamcast::Window::setPosition( const spec::dreamcast::Window::vector_t& position ) { +} +void UF_API_CALL spec::dreamcast::Window::setMousePosition( const spec::dreamcast::Window::vector_t& position ) { +} +spec::dreamcast::Window::vector_t UF_API_CALL spec::dreamcast::Window::getMousePosition( ) { + return { 0, 0 }; +} +void UF_API_CALL spec::dreamcast::Window::setSize( const spec::dreamcast::Window::vector_t& size ) { +} + +void UF_API_CALL spec::dreamcast::Window::setTitle( const spec::dreamcast::Window::title_t& title ) { +} +void UF_API_CALL spec::dreamcast::Window::setIcon( const spec::dreamcast::Window::vector_t& size, uint8_t* pixels ) { +} +void UF_API_CALL spec::dreamcast::Window::setVisible( bool visibility ) { +} +void UF_API_CALL spec::dreamcast::Window::setCursorVisible( bool visibility ) { +} +void UF_API_CALL spec::dreamcast::Window::setKeyRepeatEnabled( bool state ) { + this->m_keyRepeatEnabled = state; +} + +void UF_API_CALL spec::dreamcast::Window::requestFocus() { +} +bool UF_API_CALL spec::dreamcast::Window::hasFocus() const { + return true; +} + + +#include +void UF_API_CALL spec::dreamcast::Window::processEvents() { + if ( !::controller.device ) ::controller.device = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if ( !::keyboard.device ) ::keyboard.device = maple_enum_type(0, MAPLE_FUNC_KEYBOARD); + + 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); + + if ( ::controller.state ) { + if ( ::controller.state->buttons & CONT_START ) { + + } + } +} +bool UF_API_CALL spec::dreamcast::Window::pollEvents( bool block ) { + if ( this->m_events.empty() ) { + do { + this->processEvents(); + } while ( block && this->m_events.empty() ); + } + + while ( !this->m_events.empty() ) { + auto& event = this->m_events.front(); + if ( event.payload.is() ) { + ext::json::Value payload = uf::Serializer( event.payload.as() ); + // std::cout << event.name << " (string)\t" << payload << std::endl; + uf::hooks.call( "window:Event", payload ); + uf::hooks.call( event.name, payload ); + } else if ( event.payload.is() ) { + uf::Serializer& payload = event.payload.as(); + // std::cout << event.name << " (serializer)\t" << payload << std::endl; + uf::hooks.call( "window:Event", payload ); + uf::hooks.call( event.name, payload ); + } else if ( event.payload.is() ) { + ext::json::Value& payload = event.payload.as(); + // std::cout << event.name << " (json)\t" << payload << std::endl; + uf::hooks.call( "window:Event", payload ); + uf::hooks.call( event.name, payload ); + } else { + // std::cout << event.name << "(???)" << std::endl; + uf::hooks.call( "window:Event", event.payload ); + uf::hooks.call( event.name, event.payload ); + } + /* + try { + uf::hooks.call( "window:Event", payload ); + uf::hooks.call( event.name, payload ); + } catch ( ... ) { + // Let the hook handler handle the exceptions + } + */ + this->m_events.pop(); + } + return true; +} + +void UF_API_CALL spec::dreamcast::Window::registerWindowClass() { +} +void UF_API_CALL spec::dreamcast::Window::processEvent(/*UINT message, WPARAM wParam, LPARAM lParam*/) { +} + +void UF_API_CALL spec::dreamcast::Window::setTracking(bool state) { +} +void UF_API_CALL spec::dreamcast::Window::setMouseGrabbed(bool state) { + this->m_mouseGrabbed = state; + this->grabMouse(state); +} +void UF_API_CALL spec::dreamcast::Window::grabMouse(bool state) { +} +pod::Vector2ui UF_API_CALL spec::dreamcast::Window::getResolution() { + return { 0, 0 }; +} +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 == "Left") && (::controller.state->buttons & CONT_DPAD_LEFT) ) return true; + if ( (key == "Right") && (::controller.state->buttons & CONT_DPAD_RIGHT) ) return true; + if ( (key == "Up") && (::controller.state->buttons & CONT_DPAD_UP) ) return true; + if ( (key == "Down") && (::controller.state->buttons & CONT_DPAD_DOWN) ) return true; + if ( (key == "Start") && (::controller.state->buttons & CONT_START) ) return true; + if ( (key == "A") && (::controller.state->buttons & CONT_A) ) 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/utils/audio/audio.cpp b/engine/src/utils/audio/audio.cpp index 2f815cb8..2617d967 100644 --- a/engine/src/utils/audio/audio.cpp +++ b/engine/src/utils/audio/audio.cpp @@ -28,20 +28,31 @@ uf::Audio::~Audio() { } bool UF_API uf::Audio::initialized() { +#if UF_USE_OPENAL if ( !this->m_source.getIndex() ) return false; if ( !this->m_buffer.getIndex() ) return false; return true; +#else + return false; +#endif } void UF_API uf::Audio::destroy() { +#if UF_USE_OPENAL this->m_source.destroy(); this->m_buffer.destroy(); +#endif } bool UF_API uf::Audio::playing() { +#if UF_USE_OPENAL if ( !this->initialized() ) return false; if ( !this->m_source.playing() ) return false; return true; +#else + return false; +#endif } void UF_API uf::Audio::load( const std::string& filename ) { +#if UF_USE_OPENAL if ( uf::Audio::mute ) return; if ( this->initialized() ) this->destroy(); if ( filename != "" ) this->m_filename = filename; @@ -69,15 +80,20 @@ void UF_API uf::Audio::load( const std::string& filename ) { AL_CHECK_ERROR(this->m_source.source( "PITCH", std::vector{ 1 } )); AL_CHECK_ERROR(this->m_source.source( "GAIN", std::vector{ 1 } )); AL_CHECK_ERROR(this->m_source.source( "LOOPING", std::vector{ AL_FALSE } )); +#endif } void UF_API uf::Audio::play() { +#if UF_USE_OPENAL if ( !this->initialized() ) return; this->m_source.play(); +#endif } void UF_API uf::Audio::stop() { +#if UF_USE_OPENAL if ( !this->initialized() ) return; this->m_source.stop(); +#endif } const std::string& UF_API uf::Audio::getFilename() const { return this->m_filename; @@ -93,75 +109,111 @@ float uf::Audio::getDuration() const { } ALfloat UF_API uf::Audio::getTime() { +#if UF_USE_OPENAL if ( !this->playing() ) return 0; ALfloat pos; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_SEC_OFFSET, &pos )); return pos; +#else + return 0; +#endif } void UF_API uf::Audio::setTime( ALfloat pos ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; - this->m_source.source("SEC_OFFSET", std::vector{ pos } ); + this->m_source.source("SEC_OFFSET", std::vector{ pos } ); +#endif } ALfloat UF_API uf::Audio::getPitch() { +#if UF_USE_OPENAL if ( !this->initialized() ) return 0; ALfloat pitch; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_PITCH, &pitch )); return pitch; +#else + return 0; +#endif } void UF_API uf::Audio::setPitch( ALfloat pitch ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; - this->m_source.source("PITCH", std::vector{ pitch } ); + this->m_source.source("PITCH", std::vector{ pitch } ); +#endif } ALfloat UF_API uf::Audio::getGain() { +#if UF_USE_OPENAL if ( !this->initialized() ) return 0; ALfloat gain; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_GAIN, &gain )); return gain; +#else + return 0; +#endif } void UF_API uf::Audio::setGain( ALfloat gain ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; - this->m_source.source("GAIN", std::vector{ gain } ); + this->m_source.source("GAIN", std::vector{ gain } ); +#endif } ALfloat UF_API uf::Audio::getRolloffFactor() { +#if UF_USE_OPENAL if ( !this->initialized() ) return 0; ALfloat rolloffFactor; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_ROLLOFF_FACTOR, &rolloffFactor )); return rolloffFactor; +#else + return 0; +#endif } void UF_API uf::Audio::setRolloffFactor( ALfloat rolloffFactor ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; - this->m_source.source("ROLLOFF_FACTOR", std::vector{ rolloffFactor } ); + this->m_source.source("ROLLOFF_FACTOR", std::vector{ rolloffFactor } ); +#endif } ALfloat UF_API uf::Audio::getMaxDistance() { +#if UF_USE_OPENAL if ( !this->initialized() ) return 0; ALfloat maxDistance; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_MAX_DISTANCE, &maxDistance )); return maxDistance; +#else + return 0; +#endif } void UF_API uf::Audio::setMaxDistance( ALfloat maxDistance ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; - this->m_source.source("MAX_DISTANCE", std::vector{ maxDistance } ); + this->m_source.source("MAX_DISTANCE", std::vector{ maxDistance } ); +#endif } void UF_API uf::Audio::setPosition( const pod::Vector3& position ) { +#if UF_USE_OPENAL if ( !this->initialized() ) return; this->m_source.source("POSITION", std::vector{position.x, position.y, position.z} ); +#endif } void UF_API uf::Audio::setOrientation( const pod::Quaternion<>& orientation ) { } void UF_API uf::Audio::setVolume( float volume ) { +#if UF_USE_OPENAL this->m_source.source("GAIN", std::vector{volume} ); +#endif } float UF_API uf::Audio::getVolume() const { +#if UF_USE_OPENAL ALfloat pos; AL_CHECK_ERROR(alGetSourcef(this->m_source.getIndex(), AL_GAIN, &pos )); return pos; +#endif } // diff --git a/engine/src/utils/camera/camera.cpp b/engine/src/utils/camera/camera.cpp index 072e62fa..f021a42e 100644 --- a/engine/src/utils/camera/camera.cpp +++ b/engine/src/utils/camera/camera.cpp @@ -3,7 +3,11 @@ #include #include -bool uf::Camera::USE_REVERSE_INFINITE_PROJECTION = true;\ +#if UF_USE_VULKAN + bool uf::Camera::USE_REVERSE_INFINITE_PROJECTION = true; +#else + bool uf::Camera::USE_REVERSE_INFINITE_PROJECTION = false; +#endif uf::Camera::Camera() : m_modified(false) { this->m_settings.perspective.fov = 100; @@ -239,6 +243,7 @@ void uf::Camera::update(bool override) { } void uf::Camera::updateView() { auto& transform = this->getTransform(); +#if UF_USE_OPENVR if ( this->m_settings.stereoscopic && ext::openvr::context ) { transform.orientation = uf::quaternion::identity(); pod::Matrix4t<> view = uf::matrix::inverse( uf::transform::model( transform, false, 1 ) ); @@ -247,17 +252,21 @@ void uf::Camera::updateView() { this->setView( ext::openvr::hmdViewMatrix(vr::Eye_Left, view ), 0 ); this->setView( ext::openvr::hmdViewMatrix(vr::Eye_Right, view ), 1 ); } else { +#else + { +#endif pod::Matrix4t<> view = uf::matrix::inverse( uf::transform::model( transform, false, 1 ) ); this->setView( view ); } } void uf::Camera::updateProjection() { +#if UF_USE_OPENVR if ( this->m_settings.stereoscopic && ext::openvr::context ) { this->setProjection( ext::openvr::hmdProjectionMatrix( vr::Eye_Left, this->m_settings.perspective.bounds.x, this->m_settings.perspective.bounds.y ), 0 ); this->setProjection( ext::openvr::hmdProjectionMatrix( vr::Eye_Right, this->m_settings.perspective.bounds.x, this->m_settings.perspective.bounds.y ), 1 ); return; } - +#endif if ( this->m_settings.mode < 0 ) { // Maintain aspect ratio if ( this->m_settings.ortho.lr.x == this->m_settings.ortho.bt.x && this->m_settings.ortho.lr.y == this->m_settings.ortho.bt.y && this->m_settings.ortho.bt.x == -this->m_settings.ortho.bt.y ) { @@ -280,12 +289,34 @@ void uf::Camera::updateProjection() { } float fov = this->m_settings.perspective.fov * (3.14159265358f / 180.0f); float raidou = (float) this->m_settings.perspective.size.x / (float) this->m_settings.perspective.size.y; - float f = 1.0f / tan( 0.5f * fov ); - - this->setProjection({ - f / raidou, 0.0f, 0.0f, 0.0f, - 0.0f, -f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, this->m_settings.perspective.bounds.x, 0.0f - }); + if ( USE_REVERSE_INFINITE_PROJECTION ) { + float f = 1.0f / tan( 0.5f * fov ); + + this->setProjection({ + f / raidou, 0.0f, 0.0f, 0.0f, + 0.0f, -f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, this->m_settings.perspective.bounds.x, 0.0f + }); + } else { + pod::Vector2& size = this->m_settings.perspective.size; + float lower = this->m_settings.perspective.bounds.x; + float upper = this->m_settings.perspective.bounds.y; + float raidou = (float) size.x / (float) size.y; + float fov = this->m_settings.perspective.fov * (3.14159265358 / 180.0); + float range = lower - upper; + float f = tanf( fov / 2.0 ); + + float Sx = 1.0 / (f * raidou); + float Sy = 1.0 / f; + float Sz = (-lower - upper) / range; + float Pz = 2.0 * upper * lower / range; + + this->setProjection({ + Sx, 0, 0, 0, + 0, Sy, 0, 0, + 0, 0, Sz, 1, + 0, 0, Pz, 0 + }); + } } \ No newline at end of file diff --git a/engine/src/utils/graphic/mesh.cpp b/engine/src/utils/graphic/mesh.cpp index 08fc716f..042eef87 100644 --- a/engine/src/utils/graphic/mesh.cpp +++ b/engine/src/utils/graphic/mesh.cpp @@ -1,258 +1,47 @@ #include // Used for per-vertex colors -std::vector pod::Vertex_3F2F3F4F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F4F, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_3F2F3F4F, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F4F, normal) - }, - { - uf::renderer::enums::Format::R32_UINT, - offsetof(pod::Vertex_3F2F3F4F, color) - } -}; +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F4F, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F4F, R32_UINT, color) +) // Used for terrain -std::vector pod::Vertex_3F2F3F32B::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F32B, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_3F2F3F32B, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F32B, normal) - }, - { - uf::renderer::enums::Format::R32_UINT, - offsetof(pod::Vertex_3F2F3F32B, color) - } -}; +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F32B, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F32B, R32_UINT, color) +) // Used for normal meshses -std::vector pod::Vertex_3F2F3F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_3F2F3F, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F, normal) - } -}; +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F, R32G32B32_SFLOAT, normal) +) // (Typically) used for displaying textures -std::vector pod::Vertex_3F2F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_3F2F, uv) - } -}; -std::vector pod::Vertex_2F2F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_2F2F, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_2F2F, uv) - } -}; +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F, R32G32_SFLOAT, uv) +) +UF_VERTEX_DESCRIPTOR(pod::Vertex_2F2F, + UF_VERTEX_DESCRIPTION(pod::Vertex_2F2F, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_2F2F, R32G32_SFLOAT, uv) +) // used for texture arrays -std::vector pod::Vertex_3F3F3F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F3F3F, position) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F3F3F, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F3F3F, normal) - } -}; -std::vector pod::Vertex_3F2F3F1UI::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F1UI, position) - }, - { - uf::renderer::enums::Format::R32G32_SFLOAT, - offsetof(pod::Vertex_3F2F3F1UI, uv) - }, - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F2F3F1UI, normal) - }, - { - uf::renderer::enums::Format::R32_UINT, - offsetof(pod::Vertex_3F2F3F1UI, id) - } -}; +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F3F3F, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F3F3F, R32G32B32_SFLOAT, normal) +) +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F2F3F1UI, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32B32_SFLOAT, position) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32_SFLOAT, uv) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32G32B32_SFLOAT, normal) + UF_VERTEX_DESCRIPTION(pod::Vertex_3F2F3F1UI, R32_UINT, id) +) // Basic -std::vector pod::Vertex_3F::descriptor = { - { - uf::renderer::enums::Format::R32G32B32_SFLOAT, - offsetof(pod::Vertex_3F, position) - } -}; -/* -#include -#include -#include - -#include - -void uf::Mesh::initialize( bool compress ) { - if ( this->graphic ) this->destroy(false); - if ( compress ) { - std::unordered_map unique; - std::vector _vertices = std::move( this->vertices ); - - this->indices.clear(); - this->vertices.clear(); - this->indices.reserve(_vertices.size()); - this->vertices.reserve(_vertices.size()); - - for ( vertex_t& vertex : _vertices ) { - if ( unique.count(vertex) == 0 ) { - unique[vertex] = static_cast(this->vertices.size()); - this->vertices.push_back( vertex ); - } - this->indices.push_back( unique[vertex] ); - } - } else { - this->indices.clear(); - this->indices.reserve(vertices.size()); - for ( size_t i = 0; i < vertices.size(); ++i ) { - this->indices.push_back(i); - } - } - - uf::renderer::MeshGraphic* graphic = new uf::renderer::BaseGraphic; - this->graphic = (void*) graphic; - - graphic->device = &uf::renderer::device; - // graphic->describe - - graphic->initializeBuffer( - (void*) vertices.data(), - vertices.size() * sizeof(vertex_t), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - false - ); - graphic->initializeBuffer( - (void*) indices.data(), - indices.size() * sizeof(uint32_t), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - false - ); - graphic->indices = indices.size(); - // wait for shaders and unifors -} -void uf::Mesh::destroy( bool clear ) { - if ( this->graphic ) { - uf::renderer::MeshGraphic* graphic = (uf::renderer::MeshGraphic*) this->graphic; - if ( graphic ) { - graphic->destroy(); - delete graphic; - this->graphic = nullptr; - } - } - if ( clear ) { - this->indices.clear(); - this->vertices.clear(); - } -} -uf::Mesh::~Mesh() { - this->destroy(); -} - - - -void uf::GuiMesh::initialize( bool compress ) { - if ( this->graphic ) this->destroy(false); - if ( compress ) { - std::unordered_map unique; - std::vector _vertices = std::move( this->vertices ); - - this->indices.clear(); - this->vertices.clear(); - this->indices.reserve(_vertices.size()); - this->vertices.reserve(_vertices.size()); - - for ( pod::Vertex2f2f& vertex : _vertices ) { - if ( unique.count(vertex) == 0 ) { - unique[vertex] = static_cast(this->vertices.size()); - this->vertices.push_back( vertex ); - } - this->indices.push_back( unique[vertex] ); - } - } else { - this->indices.clear(); - this->indices.reserve(vertices.size()); - for ( size_t i = 0; i < vertices.size(); ++i ) { - this->indices.push_back(i); - } - } - - uf::renderer::GuiGraphic* graphic = new uf::renderer::GuiGraphic; - this->graphic = (void*) graphic; - - graphic->device = &uf::renderer::device; - graphic->initializeBuffer( - (void*) vertices.data(), - vertices.size() * sizeof(pod::Vertex2f2f), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - false - ); - graphic->initializeBuffer( - (void*) indices.data(), - indices.size() * sizeof(uint32_t), - VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, //VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - false - ); - graphic->indices = indices.size(); - // wait for shaders -} -void uf::GuiMesh::destroy( bool clear ) { - if ( this->graphic ) { - uf::renderer::GuiGraphic* graphic = (uf::renderer::GuiGraphic*) this->graphic; - if ( graphic ) { - graphic->destroy(); - delete graphic; - this->graphic = nullptr; - } - } - if ( clear ) { - this->indices.clear(); - this->vertices.clear(); - } -} -uf::GuiMesh::~GuiMesh() { - this->destroy(); -} - -*/ \ No newline at end of file +UF_VERTEX_DESCRIPTOR(pod::Vertex_3F, + UF_VERTEX_DESCRIPTION(pod::Vertex_3F, R32G32B32_SFLOAT, position) +) \ No newline at end of file diff --git a/engine/src/utils/http/http.cpp b/engine/src/utils/http/http.cpp index b894a9a3..4b64c7e1 100644 --- a/engine/src/utils/http/http.cpp +++ b/engine/src/utils/http/http.cpp @@ -1,5 +1,7 @@ #include +#if UF_USE_CURL #include +#endif #include namespace { @@ -12,6 +14,7 @@ namespace { uf::Http UF_API uf::http::get( const std::string& url ) { uf::Http http; +#if UF_USE_CURL auto curl = curl_easy_init(); if ( !curl ) return http; @@ -35,6 +38,6 @@ uf::Http UF_API uf::http::get( const std::string& url ) { curl_easy_cleanup(curl); curl = NULL; - +#endif return http; } \ No newline at end of file diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index 0f57e1a4..399aec56 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -71,7 +71,12 @@ std::string uf::Image::getFilename() const { // from file bool uf::Image::open( const std::string& filename, bool flip ) { - if ( !uf::io::exists(filename) ) throw std::runtime_error("does not exist: " + filename); + if ( !uf::io::exists(filename) ) { + #if UF_NO_EXCEPTIONS + #else + throw std::runtime_error("does not exist: " + filename); + #endif + } this->m_filename = filename; this->m_pixels.clear(); std::string extension = uf::io::extension(filename); diff --git a/engine/src/utils/io/iostream.cpp b/engine/src/utils/io/iostream.cpp index 22fc5cf6..04c6e49f 100644 --- a/engine/src/utils/io/iostream.cpp +++ b/engine/src/utils/io/iostream.cpp @@ -1,8 +1,10 @@ #define _X_OPEN_SOURCE_EXTENDED - #include + +#if UF_USE_NCURSES #include #include +#endif #include #include @@ -64,6 +66,7 @@ uf::IoStream::~IoStream() { } void UF_API_CALL uf::IoStream::initialize() { +#if UF_USE_NCURSES if ( !uf::IoStream::ncurses ) return; ext::ncurses.initialize(); if ( ext::ncurses.hasColors() ) { @@ -88,17 +91,23 @@ void UF_API_CALL uf::IoStream::initialize() { this->readChar(); this->terminate(); } +#endif } void UF_API_CALL uf::IoStream::terminate() { +#if UF_USE_NCURSES if (uf::IoStream::ncurses) ext::ncurses.terminate(); +#endif } void UF_API_CALL uf::IoStream::clear(bool all) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); +#endif if ( !uf::IoStream::ncurses ) { if ( all ) { spec::terminal.clear(); } } +#if UF_USE_NCURSES if ( all ) { ext::ncurses.move(0,0); ext::ncurses.clear(true); @@ -108,6 +117,7 @@ void UF_API_CALL uf::IoStream::clear(bool all) { ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column); ext::ncurses.move(::info.cursor.row, 0); ext::ncurses.clear(); +#endif } std::string uf::IoStream::getBuffer() { return ::info.output.buffer; @@ -116,6 +126,7 @@ std::vector uf::IoStream::getHistory() { return ::info.output.history; } void UF_API_CALL uf::IoStream::back() { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) return; if ( !uf::IoStream::ncurses ) return; /* @@ -141,28 +152,35 @@ void UF_API_CALL uf::IoStream::back() { ext::ncurses.move(::info.cursor.row - 1, ::info.output.buffer.size(), ::info.cursor.row, ::info.cursor.column); } ext::ncurses.refresh(); +#endif } char UF_API_CALL uf::IoStream::readChar(const bool& loop) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); +#endif if ( !uf::IoStream::ncurses ) { return std::cin.get(); } +#if UF_USE_NCURSES while ( loop ) { ::info.character = ext::ncurses.getCh(); if ( ::info.character == ERR ) continue; if ( ::info.character > 0 && ::info.character < 128 ) return ::info.character; } return 0; +#endif } std::string UF_API_CALL uf::IoStream::readString(const bool& loop) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); // static std::vector history; - +#endif if ( !uf::IoStream::ncurses ) { std::string in; std::getline(std::cin, in); return in; } +#if UF_USE_NCURSES /*std::string ::info.input.buffer; int ch; struct { @@ -242,16 +260,19 @@ std::string UF_API_CALL uf::IoStream::readString(const bool& loop) { uf::iostream << "\n"; ::info.input.history.push_back(::info.input.buffer); return ::info.input.buffer; +#endif } uf::String UF_API_CALL uf::IoStream::readUString(const bool& loop) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); // static std::vector history; - +#endif if ( !uf::IoStream::ncurses ) { std::string in; std::getline(std::cin, in); return in; } +#if UF_USE_NCURSES /*std::string ::info.input.buffer; int ch; struct { @@ -357,9 +378,12 @@ uf::String UF_API_CALL uf::IoStream::readUString(const bool& loop) { uf::iostream << "\n"; ::info.input.history.push_back(::info.input.buffer); return ::info.input.buffer; +#endif } char UF_API_CALL uf::IoStream::writeChar( char ch ) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); +#endif addCh(ch); /* if ( ch == '\r' ) ch = '\n'; @@ -376,12 +400,16 @@ char UF_API_CALL uf::IoStream::writeChar( char ch ) { else std::cout << ch; return ch; } +#if UF_USE_NCURSES ext::ncurses.addChar(ch); ext::ncurses.refresh(); return ch; +#endif } const std::string& UF_API_CALL uf::IoStream::writeString( const std::string& str ) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); +#endif addStr(str); /* std::size_t needle; @@ -399,12 +427,16 @@ const std::string& UF_API_CALL uf::IoStream::writeString( const std::string& str else std::cout << str; return str; } +#if UF_USE_NCURSES ext::ncurses.addStr(str.c_str()); ext::ncurses.refresh(); return str; +#endif } const uf::String& UF_API_CALL uf::IoStream::writeUString( const uf::String& str ) { +#if UF_USE_NCURSES if ( !ext::ncurses.initialized() ) this->initialize(); +#endif addUStr(str); /* std::size_t needle; @@ -420,9 +452,11 @@ const uf::String& UF_API_CALL uf::IoStream::writeUString( const uf::String& str std::cout << (const char*) str.getString().c_str(); return str; } +#if UF_USE_NCURSES ext::ncurses.addStr((const char*) str.getString().c_str()); ext::ncurses.refresh(); return str; +#endif } void UF_API_CALL uf::IoStream::operator>> (bool& val) { @@ -628,6 +662,7 @@ std::string uf::IoStream::getColor() { return this->m_currentColor; } void UF_API_CALL uf::IoStream::setColor( const std::string& str ) { +#if UF_USE_NCURSES if ( !uf::IoStream::ncurses ) return; if ( !ext::ncurses.initialized() ) this->initialize(); @@ -639,6 +674,7 @@ void UF_API_CALL uf::IoStream::setColor( const std::string& str ) { ::info.color.last = id; this->m_currentColor = str; +#endif } // manip via stream manipulator diff --git a/engine/src/utils/mempool/mempool.cpp b/engine/src/utils/mempool/mempool.cpp index be4ac1f6..b0d1d942 100644 --- a/engine/src/utils/mempool/mempool.cpp +++ b/engine/src/utils/mempool/mempool.cpp @@ -169,7 +169,10 @@ MANUAL_MALLOC: allocation.size = size; allocation.pointer = malloc(size); } else { + #if UF_NO_EXCEPTIONS + #else throw; + #endif } RETURN: if ( UF_MEMORYPOOL_MUTEX ) this->m_mutex.unlock(); diff --git a/engine/src/utils/serialize/serializer.cpp b/engine/src/utils/serialize/serializer.cpp index fc7cf06b..cc6eaac1 100644 --- a/engine/src/utils/serialize/serializer.cpp +++ b/engine/src/utils/serialize/serializer.cpp @@ -11,9 +11,11 @@ uf::Serializer::Serializer( const std::string& str ) { //: sol::table(ext::lua::state, sol::create) { this->deserialize(str); } +#if UF_USE_LUA uf::Serializer::Serializer( const sol::table& table ) { //: sol::table(ext::lua::state, sol::create) { this->deserialize( ext::json::encode( table ) ); } +#endif uf::Serializer::Serializer( const ext::json::Value& json ) { //: sol::table(ext::lua::state, sol::create) { // this->deserialize( ext::json::encode( json ) ); *this = json; @@ -146,10 +148,12 @@ uf::Serializer& uf::Serializer::operator=( const std::string& str ) { this->deserialize(str); return *this; } +#if UF_USE_LUA uf::Serializer& uf::Serializer::operator=( const sol::table& table ) { this->deserialize( ext::json::encode( table ) ); return *this; } +#endif uf::Serializer& uf::Serializer::operator=( const ext::json::Value& json ) { // this->deserialize( ext::json::encode( json ) ); ext::json::Value::operator=(json); diff --git a/engine/src/utils/singletons/pre_main.cpp b/engine/src/utils/singletons/pre_main.cpp index 20c2877c..3b15ff61 100644 --- a/engine/src/utils/singletons/pre_main.cpp +++ b/engine/src/utils/singletons/pre_main.cpp @@ -1,5 +1,8 @@ #include uf::StaticInitialization::StaticInitialization( std::function fun ) { +#if UF_ENV_DREAMCAST +#else fun(); +#endif } \ No newline at end of file diff --git a/engine/src/utils/string/io.cpp b/engine/src/utils/string/io.cpp index 97a4632a..6f17d7c3 100644 --- a/engine/src/utils/string/io.cpp +++ b/engine/src/utils/string/io.cpp @@ -16,6 +16,8 @@ #define GetCurrentDir getcwd #endif +const std::string uf::io::root = UF_IO_ROOT; + std::string UF_API uf::io::absolute( const std::string& path ) { char buff[FILENAME_MAX]; GetCurrentDir( buff, FILENAME_MAX ); @@ -101,18 +103,18 @@ std::string UF_API uf::io::resolveURI( const std::string& filename, const std::s if ( filename.substr(0,8) == "https://" ) return filename; std::string extension = uf::io::extension(filename); // just sanitize - if ( filename.find("./data/") == 0 ) + if ( filename.find(uf::io::root) == 0 ) return uf::io::sanitize( uf::io::filename( filename ), uf::io::directory( filename ) ); // if the filename contains an absolute path or if no root is provided if ( filename[0] == '/' || root == "" ) { - if ( filename.substr(0,9) == "/smtsamo/" ) root = "./data/"; - else if ( extension == "json" ) root = "./data/entities/"; - else if ( extension == "png" ) root = "./data/textures/"; - else if ( extension == "glb" ) root = "./data/models/"; - else if ( extension == "gltf" ) root = "./data/models/"; - else if ( extension == "ogg" ) root = "./data/audio/"; - else if ( extension == "spv" ) root = "./data/shaders/"; - else if ( extension == "lua" ) root = "./data/scripts/"; + if ( filename.substr(0,9) == "/smtsamo/" ) root = uf::io::root; + else if ( extension == "json" ) root = uf::io::root + "/entities/"; + else if ( extension == "png" ) root = uf::io::root + "/textures/"; + else if ( extension == "glb" ) root = uf::io::root + "/models/"; + else if ( extension == "gltf" ) root = uf::io::root + "/models/"; + else if ( extension == "ogg" ) root = uf::io::root + "/audio/"; + else if ( extension == "spv" ) root = uf::io::root + "/shaders/"; + else if ( extension == "lua" ) root = uf::io::root + "/scripts/"; } return uf::io::sanitize(filename, root); } \ No newline at end of file diff --git a/engine/src/utils/text/glyph.cpp b/engine/src/utils/text/glyph.cpp index 24e0d37a..9915e0f2 100644 --- a/engine/src/utils/text/glyph.cpp +++ b/engine/src/utils/text/glyph.cpp @@ -1,6 +1,6 @@ #include #include - +#if UF_USE_FREETYPE uf::Glyph::~Glyph() { delete[] this->m_buffer; } @@ -237,4 +237,5 @@ void uf::Glyph::setSpread( int spread ) { } void uf::Glyph::useSdf( bool b ) { this->m_sdf = b; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/engine/src/utils/thread/thread.cpp b/engine/src/utils/thread/thread.cpp index e44b1f21..3a8f550d 100644 --- a/engine/src/utils/thread/thread.cpp +++ b/engine/src/utils/thread/thread.cpp @@ -6,7 +6,8 @@ uf::thread::container_t uf::thread::threads; double uf::thread::limiter = 1.0f / 120.0f; uint uf::thread::workers = 1; -#define UF_THREAD_ANNOUNCE 0 +#define UF_THREAD_ANNOUNCE(x)\ + //uf::iostream << x << "\n"; void UF_API uf::thread::start( pod::Thread& thread ) { if ( thread.running ) return; thread.thread = std::thread( uf::thread::tick, std::ref(thread) ); @@ -23,13 +24,14 @@ void UF_API uf::thread::quit( pod::Thread& thread ) { // if ( !thread.running ) void UF_API uf::thread::tick( pod::Thread& thread ) { /* bool res = SetThreadAffinityMask(GetCurrentThread(), (1u << thread.affinity)); - if ( !res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n"; + if ( !res ) UF_THREAD_ANNOUNCE("Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")"); if ( !thread.timer.running() ) thread.timer.start(); */ +#if !UF_ENV_DREAMCAST bool res = SetThreadAffinityMask(GetCurrentThread(), (1u << thread.affinity)); - if ( !res ) if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")" << "\n"; - if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Starting Thread #" << thread.uid << " (" << thread.name << " on ID " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)" << "\n"; - + if ( !res ) UF_THREAD_ANNOUNCE("Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")"); +#endif + UF_THREAD_ANNOUNCE("Starting Thread #" << thread.uid << " (" << thread.name << " on ID " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"); thread.timer.start(); while ( thread.running ) { @@ -91,7 +93,7 @@ void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& temporary ? thread.temps.push( function ) : thread.consts.push_back( function ); if ( thread.mutex != NULL ) thread.mutex->unlock(); } -void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Bad Thread: " << thread.uid << " " << thread.name << "\n"; return; } //ops +void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { UF_THREAD_ANNOUNCE("Bad Thread: " << thread.uid << " " << thread.name); return; } //ops /* std::function temps = [&] { int i = 0; @@ -120,20 +122,28 @@ void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(u size_t consts = 0; while ( !thread.temps.empty() ) { auto& function = thread.temps.front(); + #if UF_NO_EXCEPTIONS + if ( function ) function(); + #else if ( function ) try { function(); } catch ( std::exception& e ) { uf::iostream << "Thread " << thread.name << " (UID: " << thread.uid << ") caught exception: " << e.what() << "\n"; } + #endif thread.temps.pop(); ++temps; } for ( auto function : thread.consts ) { + #if UF_NO_EXCEPTIONS + if ( function ) function(); + #else if ( function ) try { function(); } catch ( std::exception& e ) { uf::iostream << "Thread " << thread.name << " (UID: " << thread.uid << ") caught exception: " << e.what() << "\n"; } + #endif ++consts; } thread.condition.notify_one(); @@ -188,7 +198,7 @@ pod::Thread& UF_API uf::thread::create( const std::string& name, bool start, boo thread.limiter = uf::thread::limiter; thread.affinity = (thread.uid % limit) + 1; - if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"<< "\n"; + UF_THREAD_ANNOUNCE("Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)"); if ( start ) uf::thread::start( thread ); @@ -197,9 +207,9 @@ pod::Thread& UF_API uf::thread::create( const std::string& name, bool start, boo void UF_API uf::thread::destroy( pod::Thread& thread ) { if ( !uf::thread::has( uf::thread::uid(thread) ) ) return; // oops - if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Quitting Thread #" << thread.uid << " (" << thread.name << ")" << "\n"; + UF_THREAD_ANNOUNCE("Quitting Thread #" << thread.uid << " (" << thread.name << ")"); uf::thread::quit( thread ); - if ( UF_THREAD_ANNOUNCE ) uf::iostream << "Quitted Thread #" << thread.uid << " (" << thread.name << ")" << "\n"; + UF_THREAD_ANNOUNCE("Quitted Thread #" << thread.uid << " (" << thread.name << ")"); if ( thread.mutex != NULL ) delete thread.mutex; @@ -220,9 +230,13 @@ bool UF_API uf::thread::has( const std::string& name ) { } pod::Thread& UF_API uf::thread::get( uint uid ) { for ( pod::Thread* thread : uf::thread::threads ) if ( uf::thread::uid(*thread) == uid ) return *thread; +#if !UF_NO_EXCEPTIONS throw std::string("invalid call to uf::thread::get"); +#endif } pod::Thread& UF_API uf::thread::get( const std::string& name ) { for ( pod::Thread* thread : uf::thread::threads ) if ( uf::thread::name(*thread) == name ) return *thread; +#if !UF_NO_EXCEPTIONS throw std::string("invalid call to uf::thread::get"); +#endif } \ No newline at end of file diff --git a/engine/src/utils/window/window.cpp b/engine/src/utils/window/window.cpp index bd8f5d9e..e7575918 100644 --- a/engine/src/utils/window/window.cpp +++ b/engine/src/utils/window/window.cpp @@ -1,6 +1,6 @@ #include -#if !defined(UF_USE_SFML) || (defined(UF_USE_SFML) && UF_USE_SFML == 0) - +#if !UF_USE_SFML +#define UF_OPENGL_CONTEXT_IN_WINDOW 0 #include #include bool uf::Window::focused = false; @@ -18,8 +18,7 @@ UF_API_CALL uf::Window::Window( const spec::uni::Window::vector_t& size, const s void UF_API_CALL uf::Window::create( const spec::uni::Window::vector_t& size, const spec::uni::Window::title_t& title, const spec::Context::Settings& settings ) { this->m_window = new uf::Window::window_t; this->m_window->create( size, title ); -#if defined(UF_USE_VULKAN) && UF_USE_VULKAN == 1 -#else +#if UF_USE_OPENGL && UF_OPENGL_CONTEXT_IN_WINDOW this->m_context = (spec::Context*) spec::uni::Context::create( settings, *this->m_window ); #endif } @@ -28,11 +27,13 @@ uf::Window::~Window() { this->terminate(); } void UF_API_CALL uf::Window::terminate() { +#if UF_OPENGL_CONTEXT_IN_WINDOW if ( this->m_context ) { this->m_context->terminate(); delete this->m_context; this->m_context = NULL; } +#endif if ( this->m_window ) { this->m_window->terminate(); delete this->m_window; @@ -111,8 +112,7 @@ bool UF_API_CALL uf::Window::isKeyPressed( const std::string& key ) { return uf::Window::focused && uf::Window::window_t::isKeyPressed(key); } bool UF_API_CALL uf::Window::setActive(bool active) { -#if defined(UF_USE_VULKAN) && UF_USE_VULKAN == 1 -#else +#if UF_USE_OPENGL && UF_OPENGL_CONTEXT_IN_WINDOW if (this->m_context) { if (this->m_context->setActive(active)) return true; uf::iostream << "[" << uf::IoStream::Color()("Red") << "ERROR" << "]" << "Failed to activate the window's context" << "\n"; @@ -121,7 +121,7 @@ bool UF_API_CALL uf::Window::setActive(bool active) { #endif return false; } -#if defined(UF_USE_VULKAN) && UF_USE_VULKAN == 1 +#if UF_USE_VULKAN std::vector UF_API_CALL uf::Window::getExtensions( bool x ) { return this->m_window->getExtensions( x ); } @@ -130,6 +130,13 @@ void UF_API_CALL uf::Window::createSurface( VkInstance instance, VkSurfaceKHR& s } #endif +/*virtual*/ uf::Window::window_t* UF_API_CALL uf::Window::getHandle() { + return this->m_window; +} +/*virtual*/ const uf::Window::window_t* UF_API_CALL uf::Window::getHandle() const { + return this->m_window; +} + //////////////////////////////////////////////////////////// @@ -138,8 +145,9 @@ void UF_API_CALL uf::Window::createSurface( VkInstance instance, VkSurfaceKHR& s #include void UF_API_CALL uf::Window::display() { // Display the backbuffer on screen +#if UF_USE_OPENGL && UF_OPENGL_CONTEXT_IN_WINDOW if (this->m_context && this->setActive()) this->m_context->display(); - +#endif /* FPS */ if ( false ) { static double limit = 1.0 / 60; static uf::Timer timer(false); diff --git a/ext/behaviors/craeture/behavior.cpp b/ext/behaviors/craeture/behavior.cpp index a06c35c6..6596ea3b 100644 --- a/ext/behaviors/craeture/behavior.cpp +++ b/ext/behaviors/craeture/behavior.cpp @@ -125,7 +125,7 @@ void ext::CraetureBehavior::initialize( uf::Object& self ) { metadata["timers"]["hurt"] = timer.elapsed().asDouble() + 1.0f; uf::Scene& scene = uf::scene::getCurrentScene(); uf::Asset& assetLoader = scene.getComponent(); - assetLoader.cache("./data/audio/battle/hurt.ogg", "asset:Cache.Sound." + std::to_string(this->getUid())); + assetLoader.cache(uf::io::root+"/audio/battle/hurt.ogg", "asset:Cache.Sound." + std::to_string(this->getUid())); } }); this->addHook( "world:Craeture.Hurt.%UID%", [&](ext::json::Value& json){ diff --git a/ext/behaviors/hands/behavior.cpp b/ext/behaviors/hands/behavior.cpp index 91458424..36be6776 100644 --- a/ext/behaviors/hands/behavior.cpp +++ b/ext/behaviors/hands/behavior.cpp @@ -28,8 +28,8 @@ namespace { UF_BEHAVIOR_REGISTER_CPP(ext::PlayerHandBehavior) #define this (&self) void ext::PlayerHandBehavior::initialize( uf::Object& self ) { +#if UF_USE_OPENVR uf::Serializer& metadata = this->getComponent(); - { ::hands.left = (uf::Object*) &uf::instantiator::instantiate("Object"); ::hands.right = (uf::Object*) &uf::instantiator::instantiate("Object"); @@ -68,8 +68,8 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { graphic.process = true; graphic.descriptor.frontFace = uf::renderer::enums::Face::CCW; - graphic.material.attachShader("./data/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader("./data/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); uf::instantiator::bind( "EntityBehavior", hand ); uf::instantiator::bind( "ObjectBehavior", hand ); @@ -103,8 +103,8 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { graphic.initialize(); graphic.initializeGeometry(mesh); - graphic.material.attachShader("./data/shaders/line.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader("./data/shaders/line.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/line.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/line.frag.spv", uf::renderer::enums::Shader::FRAGMENT); graphic.descriptor.topology = uf::renderer::enums::PrimitiveTopology::LINE_STRIP; graphic.descriptor.fill = uf::renderer::enums::PolygonMode::LINE; graphic.descriptor.lineWidth = metadata["hands"][side]["pointer"]["width"].as(); @@ -196,8 +196,10 @@ void ext::PlayerHandBehavior::initialize( uf::Object& self ) { // collider.add(box); } } +#endif } void ext::PlayerHandBehavior::tick( uf::Object& self ) { +#if UF_USE_OPENVR auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); auto& controllerCamera = controller.getComponent(); @@ -351,9 +353,11 @@ void ext::PlayerHandBehavior::tick( uf::Object& self ) { } } } +#endif } void ext::PlayerHandBehavior::render( uf::Object& self ){ +#if UF_USE_OPENVR uf::Serializer& metadata = this->getComponent(); auto& scene = uf::scene::getCurrentScene(); auto& controller = scene.getController(); @@ -469,6 +473,7 @@ void ext::PlayerHandBehavior::render( uf::Object& self ){ graphic.material.shaders.front().updateBuffer( uniforms, 0, false ); } } +#endif } void ext::PlayerHandBehavior::destroy( uf::Object& self ){ diff --git a/ext/behaviors/noise/behavior.cpp b/ext/behaviors/noise/behavior.cpp index 0e81186c..4c2d0013 100644 --- a/ext/behaviors/noise/behavior.cpp +++ b/ext/behaviors/noise/behavior.cpp @@ -79,8 +79,8 @@ void ext::NoiseBehavior::initialize( uf::Object& self ) { this->callHook("entity:TextureUpdate.%UID%"); - graphic.material.attachShader("./data/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader("./data/shaders/noise.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/noise.frag.spv", uf::renderer::enums::Shader::FRAGMENT); } void ext::NoiseBehavior::tick( uf::Object& self ) { auto& metadata = this->getComponent(); diff --git a/ext/behaviors/player/behavior.cpp b/ext/behaviors/player/behavior.cpp index 550e20e5..8289b517 100644 --- a/ext/behaviors/player/behavior.cpp +++ b/ext/behaviors/player/behavior.cpp @@ -149,7 +149,9 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { current += relta.x; if ( current != current || ( current < maxima && current > minima ) ) { if ( collider.body && !collider.shared ) { + #if UF_USE_BULLET ext::bullet::applyRotation( collider, transform.up, relta.x ); + #endif } else { uf::transform::rotate( transform, transform.up, relta.x ), updateCamera = true; } @@ -293,6 +295,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { bool walk = uf::Window::isKeyPressed("LAlt"); } keys; +#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; @@ -308,7 +311,8 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { 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; } - +#endif + struct { bool updateCamera = true; bool deltaCrouch = false; @@ -359,9 +363,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { metadata["system"]["control"] = false; } metadata["system"]["menu"] = stats.menu; - auto& collider = this->getComponent(); - if ( metadata["system"]["control"].as() ) { { TIMER(0.25, keys.vee && ) { @@ -371,18 +373,22 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { std::cout << "Toggling noclip: " << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; if ( state ) { std::cout << "Enabled noclip" << std::endl; + #if UF_USE_BULLET if ( collider.body ) { collider.body->setGravity(btVector3(0,0.0,0)); collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); collider.body->setActivationState(DISABLE_SIMULATION); } + #endif } else { std::cout << "Disabled noclip" << std::endl; + #if UF_USE_BULLET if ( collider.body ) { collider.body->setGravity(btVector3(0,-9.81,0)); collider.body->setCollisionFlags(collider.body->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE); collider.body->setActivationState(DISABLE_DEACTIVATION); } + #endif } stats.noclipped = state; } @@ -390,6 +396,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.floored ) { pod::Transform<> translator = transform; + #if UF_USE_OPENVR 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() ); @@ -401,6 +408,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { translator.forward = uf::vector::normalize( translator.forward ); translator.right = uf::vector::normalize( translator.right ); } + #endif pod::Vector3f queued = {}; if ( keys.forward || keys.backwards ) { int polarity = keys.forward ? 1 : -1; @@ -460,14 +468,18 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( collider.body && !collider.shared ) { physics.linear.velocity.x = queued.x; physics.linear.velocity.z = queued.z; + #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); + #endif } } if ( !keys.forward && !keys.backwards && !keys.left && !keys.right ) { if ( collider.body && !collider.shared ) { physics.linear.velocity.x = 0; physics.linear.velocity.z = 0; + #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); + #endif } } if ( keys.jump ) { @@ -476,7 +488,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { 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; + #if UF_USE_BULLET 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; @@ -487,7 +501,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( keys.lookLeft ) { if ( collider.body && !collider.shared ) { + #if UF_USE_BULLET ext::bullet::applyRotation( collider, transform.up, -speed.rotate ); + #endif } else { uf::transform::rotate( transform, transform.up, -speed.rotate ), stats.updateCamera = true; } @@ -495,7 +511,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } if ( keys.lookRight ) { if ( collider.body && !collider.shared ) { + #if UF_USE_BULLET ext::bullet::applyRotation( collider, transform.up, speed.rotate ); + #endif } else { uf::transform::rotate( transform, transform.up, speed.rotate ), stats.updateCamera = true; } @@ -508,7 +526,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { 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; + #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); + #endif } } else { if ( !metadata["system"]["physics"]["collision"].as() ) { @@ -528,7 +548,9 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { if ( stats.noclipped && !keys.forward && !keys.backwards && !keys.left && !keys.right && !keys.jump && !keys.crouch ) { if ( collider.body && !collider.shared ) { physics.linear.velocity = {}; + #if UF_USE_BULLET ext::bullet::move( collider, physics.linear.velocity ); + #endif } } if ( stats.deltaCrouch ) { diff --git a/ext/behaviors/portal/behavior.cpp b/ext/behaviors/portal/behavior.cpp index b042a4b9..789405d4 100644 --- a/ext/behaviors/portal/behavior.cpp +++ b/ext/behaviors/portal/behavior.cpp @@ -60,6 +60,7 @@ void ext::PortalBehavior::initialize( uf::Object& self ) { auto& renderMode = this->getComponent(); std::string name = "RT:" + std::to_string((int) this->getUid()); uf::renderer::addRenderMode( &renderMode, name ); + #if UF_USE_OPENVR if ( ext::openvr::enabled ) { ext::openvr::initialize(); @@ -69,6 +70,7 @@ void ext::PortalBehavior::initialize( uf::Object& self ) { renderMode.width = width; renderMode.height = height; } + #endif } } void ext::PortalBehavior::tick( uf::Object& self ) { diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index bdd5f1cf..7e05737f 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -61,7 +61,11 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { if ( uf::io::extension(filename) != "ogg" ) return; const uf::Audio* audioPointer = NULL; + #if UF_NO_EXCEPTIONS + audioPointer = &assetLoader.get(filename); + #else try { audioPointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !audioPointer ) return; uf::Audio& audio = this->getComponent(); @@ -177,12 +181,12 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { // initialize cubemap { std::vector filenames = { - "./data/textures/skybox/front.png", - "./data/textures/skybox/back.png", - "./data/textures/skybox/up.png", - "./data/textures/skybox/down.png", - "./data/textures/skybox/right.png", - "./data/textures/skybox/left.png", + uf::io::root+"/textures/skybox/front.png", + uf::io::root+"/textures/skybox/back.png", + uf::io::root+"/textures/skybox/up.png", + uf::io::root+"/textures/skybox/down.png", + uf::io::root+"/textures/skybox/right.png", + uf::io::root+"/textures/skybox/left.png", }; uf::Image::container_t pixels; std::vector images(filenames.size()); @@ -309,9 +313,11 @@ 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 } /* Update lights */ if ( metadata["light"]["should"].as() ) { diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index 7fb44c7f..076f7aaa 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -69,7 +69,11 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { if ( uf::io::extension(filename) != "ogg" ) return; const uf::Audio* audioPointer = NULL; + #if UF_NO_EXCEPTIONS + audioPointer = &assetLoader.get(filename); + #else try { audioPointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !audioPointer ) return; uf::Serializer payload = metadata["audio"]; diff --git a/ext/behaviors/sprite/behavior.cpp b/ext/behaviors/sprite/behavior.cpp index fce25a60..ba21c310 100644 --- a/ext/behaviors/sprite/behavior.cpp +++ b/ext/behaviors/sprite/behavior.cpp @@ -50,7 +50,11 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { uf::Scene& scene = this->getRootParent(); uf::Asset& assetLoader = scene.getComponent(); const uf::Image* imagePointer = NULL; + #if UF_NO_EXCEPTIONS + imagePointer = &assetLoader.get(filename); + #else try { imagePointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !imagePointer ) return; uf::Image image = *imagePointer; @@ -78,8 +82,8 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { auto& texture = graphic.material.textures.emplace_back(); texture.loadFromImage( image ); - graphic.material.attachShader("./data/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); - graphic.material.attachShader("./data/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); + graphic.material.attachShader(uf::io::root+"/shaders/base.vert.spv", uf::renderer::enums::Shader::VERTEX); + graphic.material.attachShader(uf::io::root+"/shaders/base.frag.spv", uf::renderer::enums::Shader::FRAGMENT); metadata["system"]["control"] = true; metadata["system"]["loaded"] = true; @@ -96,7 +100,7 @@ void ext::HousamoSpriteBehavior::initialize( uf::Object& self ) { if ( member["skin"].is() ) name += "_" + member["skin"].as(); std::string filename = "https://cdn..xyz//unity/Android/fg/fg_" + name + ".png"; if ( cardData["internal"].as() ) { - filename = "./data/smtsamo/fg/fg_" + name + ".png"; + filename = uf::io::root+"/smtsamo/fg/fg_" + name + ".png"; } metadata["orientation"] = cardData["orientation"].as() == "" ? "portrait" : "landscape"; diff --git a/ext/gui/behavior.cpp b/ext/gui/behavior.cpp index 944b9a21..c5003d20 100644 --- a/ext/gui/behavior.cpp +++ b/ext/gui/behavior.cpp @@ -32,10 +32,12 @@ #include namespace { +#if UF_USE_FREETYPE struct { ext::freetype::Glyph glyph; std::unordered_map> cache; } glyphs; +#endif uf::Serializer defaultSettings; } @@ -45,10 +47,12 @@ ext::Gui::Gui(){ } std::vector ext::Gui::generateGlyphs( const std::string& _string ) { + std::vector gs; +#if UF_USE_FREETYPE uf::Object& gui = *this; std::string string = _string; uf::Serializer& metadata = gui.getComponent(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); + std::string font = uf::io::root+"/fonts/" + metadata["text settings"]["font"].as(); if ( ::glyphs.cache[font].empty() ) { ext::freetype::initialize( ::glyphs.glyph, font ); } @@ -56,7 +60,6 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string string = metadata["text settings"]["string"].as(); } pod::Transform<>& transform = gui.getComponent>(); - std::vector gs; struct { struct { float x = 0; @@ -271,6 +274,9 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string stat.cursor.x += (glyph.getAdvance().x); + #if UF_NO_EXCEPTIONS + g.color = stat.colors.container.at(stat.colors.index); + #else try { g.color = stat.colors.container.at(stat.colors.index); } catch ( ... ) { @@ -281,9 +287,11 @@ std::vector ext::Gui::generateGlyphs( const std::string& _string metadata["text settings"]["color"][2].as(), }; } + #endif gs.push_back(g); } +#endif return gs; } @@ -402,8 +410,8 @@ void ext::Gui::load( const uf::Image& _image ) { } graphic.initializeGeometry( mesh ); struct { - std::string vertex = "./data/shaders/gui.vert.spv"; - std::string fragment = "./data/shaders/gui.frag.spv"; + std::string vertex = uf::io::root+"/shaders/gui.vert.spv"; + std::string fragment = uf::io::root+"/shaders/gui.frag.spv"; } filenames; std::string suffix = ""; { std::string _ = scene.getComponent()["shaders"]["gui"]["suffix"].as(); @@ -411,7 +419,7 @@ void ext::Gui::load( const uf::Image& _image ) { } if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); - else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui."+suffix+"frag.spv"; + else if ( suffix != "" ) filenames.fragment = uf::io::root+"/shaders/gui."+suffix+"frag.spv"; graphic.material.initializeShaders({ {filenames.vertex, uf::renderer::enums::Shader::VERTEX}, @@ -437,10 +445,10 @@ UF_OBJECT_REGISTER_END() #define this (&self) void ext::GuiBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); - +#if UF_USE_FREETYPE this->addHook( "glyph:Load.%UID%", [&](ext::json::Value& json){ unsigned long c = json["glyph"].as(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); + std::string font = uf::io::root+"/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { key += std::to_string(c) + ";"; key += metadata["text settings"]["padding"][0].as() + ","; @@ -461,6 +469,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } this->as().load( image ); }); +#endif this->addHook( "asset:Load.%UID%", [&](ext::json::Value& json){ std::string filename = json["filename"].as(); @@ -469,7 +478,11 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { uf::Scene& scene = uf::scene::getCurrentScene(); uf::Asset& assetLoader = scene.getComponent(); const uf::Image* imagePointer = NULL; + #if UF_NO_EXCEPTIONS + imagePointer = &assetLoader.get(filename); + #else try { imagePointer = &assetLoader.get(filename); } catch ( ... ) {} + #endif if ( !imagePointer ) return; // uf::Image image = *imagePointer; @@ -625,7 +638,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } if ( metadata["text settings"]["string"].is() ) { if ( ext::json::isNull( ::defaultSettings["metadata"] ) ) { - ::defaultSettings.readFromFile("./data/entities/gui/text/string.json"); + ::defaultSettings.readFromFile(uf::io::root+"/entities/gui/text/string.json"); } for ( auto it = ::defaultSettings["metadata"]["text settings"].begin(); it != ::defaultSettings["metadata"]["text settings"].end(); ++it ) { std::string key = it.key(); @@ -634,6 +647,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } } + #if UF_USE_FREETYPE if ( false ) { uf::Serializer payload; payload["first"] = true; @@ -642,7 +656,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { } else { std::vector glyphs = this->as().generateGlyphs(); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); + std::string font = uf::io::root+"/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { key += metadata["text settings"]["padding"][0].as() + ","; key += metadata["text settings"]["padding"][1].as() + ";"; @@ -705,24 +719,26 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if ( _ != "" ) suffix = _ + "."; } struct { - std::string vertex = "./data/shaders/gui.text.vert.spv"; - std::string fragment = "./data/shaders/gui.text.frag.spv"; + std::string vertex = uf::io::root+"/shaders/gui.text.vert.spv"; + std::string fragment = uf::io::root+"/shaders/gui.text.frag.spv"; } filenames; if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); - else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui.text."+suffix+"frag.spv"; + else if ( suffix != "" ) filenames.fragment = uf::io::root+"/shaders/gui.text."+suffix+"frag.spv"; graphic.material.initializeShaders({ {filenames.vertex, uf::renderer::enums::Shader::VERTEX}, {filenames.fragment, uf::renderer::enums::Shader::FRAGMENT}, }); } + #endif this->addHook( "object:Reload.%UID%", [&](ext::json::Value& json){ if ( json["old"]["text settings"]["string"] == json["new"]["text settings"]["string"] ) return; this->queueHook( "gui:UpdateString.%UID%"); }); + #if UF_USE_FREETYPE this->addHook( "gui:UpdateString.%UID%", [&](ext::json::Value& json){ for ( auto it = ::defaultSettings["metadata"]["text settings"].begin(); it != ::defaultSettings["metadata"]["text settings"].end(); ++it ) { std::string key = it.key(); @@ -737,7 +753,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { std::vector glyphs = this->as().generateGlyphs( string ); - std::string font = "./data/fonts/" + metadata["text settings"]["font"].as(); + std::string font = uf::io::root+"/fonts/" + metadata["text settings"]["font"].as(); std::string key = ""; { key += metadata["text settings"]["padding"][0].as() + ","; key += metadata["text settings"]["padding"][1].as() + ";"; @@ -810,12 +826,12 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { if ( _ != "" ) suffix = _ + "."; } struct { - std::string vertex = "./data/shaders/gui.text.vert.spv"; - std::string fragment = "./data/shaders/gui.text.frag.spv"; + std::string vertex = uf::io::root+"/shaders/gui.text.vert.spv"; + std::string fragment = uf::io::root+"/shaders/gui.text.frag.spv"; } filenames; if ( metadata["shaders"]["vertex"].is() ) filenames.vertex = metadata["shaders"]["vertex"].as(); if ( metadata["shaders"]["fragment"].is() ) filenames.fragment = metadata["shaders"]["fragment"].as(); - else if ( suffix != "" ) filenames.fragment = "./data/shaders/gui.text."+suffix+"frag.spv"; + else if ( suffix != "" ) filenames.fragment = uf::io::root+"/shaders/gui.text."+suffix+"frag.spv"; graphic.material.initializeShaders({ {filenames.vertex, uf::renderer::enums::Shader::VERTEX}, @@ -826,6 +842,7 @@ void ext::GuiBehavior::initialize( uf::Object& self ) { graphic.getPipeline().update( graphic ); } }); + #endif } } void ext::GuiBehavior::tick( uf::Object& self ) { diff --git a/ext/gui/html/behavior.cpp b/ext/gui/html/behavior.cpp index fca2abde..6f324c43 100644 --- a/ext/gui/html/behavior.cpp +++ b/ext/gui/html/behavior.cpp @@ -34,6 +34,7 @@ UF_BEHAVIOR_REGISTER_CPP(ext::GuiHtmlBehavior) #define this ((uf::Object*) &self) void ext::GuiHtmlBehavior::initialize( uf::Object& self ) { +#if UF_USE_ULTRALIGHT auto& page = this->getComponent(); auto& metadata = this->getComponent(); pod::Vector2ui size = { 1, 1 }; @@ -97,8 +98,10 @@ void ext::GuiHtmlBehavior::initialize( uf::Object& self ) { if ( metadata["ignore inputs"].as() ) return; ext::ultralight::input( page, json ); }); +#endif } void ext::GuiHtmlBehavior::tick( uf::Object& self ) { +#if UF_USE_ULTRALIGHT auto& metadata = this->getComponent(); auto& page = this->getComponent(); @@ -109,6 +112,7 @@ void ext::GuiHtmlBehavior::tick( uf::Object& self ) { auto image = ext::ultralight::capture( page ); texture.update( image ); // page.pending = false; +#endif } void ext::GuiHtmlBehavior::render( uf::Object& self ){ } diff --git a/ext/gui/manager/behavior.cpp b/ext/gui/manager/behavior.cpp index 10dde39f..33281bc4 100644 --- a/ext/gui/manager/behavior.cpp +++ b/ext/gui/manager/behavior.cpp @@ -156,6 +156,7 @@ void ext::GuiManagerBehavior::render( uf::Object& self ){ metadata["overlay"]["orientation"][2].as(), metadata["overlay"]["orientation"][3].as(), }; + #if UF_USE_OPENVR if ( ext::openvr::enabled && (metadata["overlay"]["enabled"].as() || uf::renderer::getRenderMode("Stereoscopic Deferred", true).getType() == "Stereoscopic Deferred" )) { if ( metadata["overlay"]["floating"].as() ) { pod::Matrix4f model = uf::transform::model( transform ); @@ -168,6 +169,9 @@ void ext::GuiManagerBehavior::render( uf::Object& self ){ uniforms.matrices.models[i] = camera.getProjection(i) * camera.getView(i) * model; } } else { + #else + { + #endif pod::Matrix4t<> model = uf::matrix::translate( uf::matrix::identity(), { 0, 0, 1 } ); uniforms.matrices.models[i] = model; } diff --git a/ext/inits/persistence.inl b/ext/inits/persistence.inl index d9fa53eb..ef9c7264 100644 --- a/ext/inits/persistence.inl +++ b/ext/inits/persistence.inl @@ -3,7 +3,7 @@ /* Read persistent data */ if ( false ) { struct { bool exists = false; - std::string filename = "./data/persistent.json"; + std::string filename = uf::io::root+"/persistent.json"; } file; struct { uf::Serializer file; diff --git a/ext/main.cpp b/ext/main.cpp index 500ef169..0bc20dc9 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -54,7 +54,7 @@ namespace { std::ofstream output; struct { - std::string output = "./data/logs/output.txt"; + std::string output = uf::io::root+"/logs/output.txt"; } filenames; } io; @@ -84,7 +84,7 @@ namespace { struct { bool exists = false; - std::string filename = "./data/config.json"; + std::string filename = uf::io::root+"/config.json"; } file; /* Read from file */ { file.exists = config.file.readFromFile(file.filename); @@ -174,6 +174,7 @@ void EXT_API ext::initialize() { /* Read persistent data */ { // #include "./inits/persistence.inl" } +#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 ) { @@ -182,10 +183,12 @@ void EXT_API ext::initialize() { } ext::lua::initialize(); } +#endif +#if UF_USE_BULLET /* Bullet */ { ext::bullet::initialize(); } - +#endif /* Parse config */ { /* Set memory pool sizes */ { auto deduceSize = []( const ext::json::Value& value )->size_t{ @@ -273,7 +276,7 @@ void EXT_API ext::initialize() { ::config["engine"]["threads"]["workers"] = threads; uf::iostream << "Using " << threads << " worker threads" << "\n"; } - +#if UF_USE_BULLET // set bullet parameters ext::bullet::debugDrawEnabled = ::config["engine"]["ext"]["bullet"]["debug draw"]["enabled"].as(); ext::bullet::debugDrawRate = ::config["engine"]["ext"]["bullet"]["debug draw"]["rate"].as(); @@ -286,7 +289,7 @@ void EXT_API ext::initialize() { if ( ::config["engine"]["ext"]["bullet"]["timescale"].as() ) { ext::bullet::timescale = ::config["engine"]["ext"]["bullet"]["timescale"].as(); } - +#endif uf::thread::workers = ::config["engine"]["threads"]["workers"].as(); // Enable valiation layer uf::renderer::settings::validation = ::config["engine"]["ext"]["vulkan"]["validation"]["enabled"].as(); @@ -341,9 +344,8 @@ void EXT_API ext::initialize() { JSON_TO_VKFORMAT(normal); JSON_TO_VKFORMAT(position); - + #if UF_USE_OPENVR ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].as(); - ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].as(); @@ -358,6 +360,7 @@ void EXT_API ext::initialize() { if ( ext::openvr::enabled ) { ::config["engine"]["render modes"]["stereo deferred"] = true; } + #endif } @@ -393,6 +396,7 @@ void EXT_API ext::initialize() { renderMode.metadata["eyes"] = 2; } } + #if UF_USE_OPENVR if ( ext::openvr::enabled ) { ext::openvr::initialize(); @@ -413,7 +417,7 @@ void EXT_API ext::initialize() { uf::iostream << "VR Resolution: " << renderMode.width << ", " << renderMode.height << "\n"; } } - + #endif #if UF_USE_VULKAN /* Callbacks for 2KHR stuffs */ if ( false ) { uf::hooks.addHook("vulkan:Instance.ExtensionsEnabled", []( const ext::json::Value& json ) { @@ -460,10 +464,12 @@ void EXT_API ext::initialize() { pod::Thread& threadPhysics = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true ); } +#if UF_USE_DISCORD /* Discord */ if ( ::config["engine"]["ext"]["discord"]["enabled"].as() ) { ext::discord::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(); @@ -473,7 +479,7 @@ void EXT_API ext::initialize() { } ext::ultralight::initialize(); } - +#endif // #define DEBUG_PRINT() std::cout << __FILE__ << ":" __FUNCTION__ << "@" << __LINE__ << std::endl; /* Add hooks */ { uf::hooks.addHook( "game:Scene.Load", [&](ext::json::Value& json){ @@ -532,10 +538,11 @@ void EXT_API ext::tick() { times.deltaTime = times.curTime - times.prevTime; } +#if UF_USE_OPENVR /* OpenVR */ if ( ext::openvr::context ) { ext::openvr::tick(); } - +#endif /* Print Entity Information */ { TIMER(1, uf::Window::isKeyPressed("P") && ) { // uf::iostream << uf::renderer::allocatorStats() << "\n"; @@ -582,6 +589,8 @@ void EXT_API ext::tick() { /* Update physics timer */ { uf::physics::tick(); } + +#if UF_USE_BULLET /* Update bullet */ { if ( ::config["engine"]["ext"]["bullet"]["multithreaded"].as() ) { uf::thread::add( bulletThread, [&]() -> int { ext::bullet::tick(); return 0;}, true ); @@ -589,7 +598,7 @@ void EXT_API ext::tick() { ext::bullet::tick(); } } - +#endif /* Update entities */ { uf::scene::tick(); } @@ -610,18 +619,19 @@ void EXT_API ext::tick() { } } } - +#if UF_USE_ULTRALIGHT /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { ext::ultralight::tick(); } - +#endif /* Update vulkan */ { uf::renderer::tick(); } +#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(); @@ -652,39 +662,45 @@ void EXT_API ext::tick() { } void EXT_API ext::render() { +#if UF_USE_ULTRALIGHT /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { ext::ultralight::render(); } +#endif +#if UF_USE_OPENVR if ( ext::openvr::context ) { vr::VRCompositor()->SubmitExplicitTimingData(); } - +#endif /* Render scene */ { uf::renderer::render(); } - +#if UF_USE_OPENVR if ( ext::openvr::context ) { ext::openvr::synchronize(); ext::openvr::submit(); } +#endif } void EXT_API ext::terminate() { /* Kill threads */ { uf::thread::terminate(); } - +#if UF_USE_BULLET /* Kill bullet */ { ext::bullet::terminate(); } - +#endif +#if UF_USE_ULTRALIGHT /* Ultralight-UX */ if ( ::config["engine"]["ext"]["ultralight"]["enabled"].as() ) { ext::ultralight::terminate(); } - +#endif +#if UF_USE_OPENVR /* OpenVR */ if ( ext::openvr::context ) { ext::openvr::terminate(); } - +#endif uf::scene::destroy(); /* Garbage collection */ if ( false ) { @@ -710,7 +726,7 @@ void EXT_API ext::terminate() { /* Write persistent data */ if ( false ) { struct { bool exists = false; - std::string filename = "./data/persistent.json"; + std::string filename = uf::io::root+"/persistent.json"; } file; struct { uf::Serializer file; @@ -736,7 +752,7 @@ std::string EXT_API ext::getConfig() { struct { bool exists = false; - std::string filename = "./data/config.json"; + std::string filename = uf::io::root+"/config.json"; } file; /* Read from file */ { file.exists = config.file.readFromFile(file.filename); diff --git a/ext/scenes/worldscape/gui/battle.cpp b/ext/scenes/worldscape/gui/battle.cpp index facfab99..963bb666 100644 --- a/ext/scenes/worldscape/gui/battle.cpp +++ b/ext/scenes/worldscape/gui/battle.cpp @@ -94,7 +94,7 @@ namespace { uf::Serializer& metadata = entity.getComponent(); uf::Serializer& masterdata = scene.getComponent(); - std::string url = "./data/audio/ui/" + key + ".ogg"; + std::string url = uf::io::root+"/audio/ui/" + key + ".ogg"; uf::Asset& assetLoader = scene.getComponent(); assetLoader.cache(url, "asset:Cache.SFX." + std::to_string(entity.getUid())); @@ -925,7 +925,7 @@ void ext::GuiBattle::tick() { if ( metadata["system"]["closing"].as() ) { if ( alpha >= 1.0f ) { uf::Asset assetLoader; - std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg"); + std::string canonical = assetLoader.load(uf::io::root+"/audio/ui/menu close.ogg"); uf::Audio& sfx = assetLoader.get(canonical); sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); @@ -1095,7 +1095,10 @@ void ext::GuiBattle::tick() { // state 1 // std::cout << particle << ": " << metadata["system"]["percent"] << ": " << metadata["text settings"]["string"] << std::endl; // std::cout << transform.position.x << ", " << transform.position.y << ", " << transform.position.z << std::endl; - try { + #if !UF_NO_EXCEPTIONS + try + #endif + { if ( !ext::json::isObject( metadata["system"] ) ) { this->removeChild(*particle); particle->destroy(); @@ -1116,7 +1119,9 @@ void ext::GuiBattle::tick() { continue; } metadata["system"]["percent"] = metadata["system"]["percent"].as() + uf::physics::time::delta; - } catch ( ... ) { + } + #if !UF_NO_EXCEPTIONS + catch ( ... ) { if ( particle ) { this->removeChild(*particle); particle->destroy(); @@ -1124,6 +1129,7 @@ void ext::GuiBattle::tick() { *it = NULL; } } + #endif } for ( auto* pointer : partyMemberButtons ) { diff --git a/ext/scenes/worldscape/gui/dialogue.cpp b/ext/scenes/worldscape/gui/dialogue.cpp index 8427e9cb..0f335c17 100644 --- a/ext/scenes/worldscape/gui/dialogue.cpp +++ b/ext/scenes/worldscape/gui/dialogue.cpp @@ -75,7 +75,7 @@ namespace { uf::Serializer& metadata = entity.getComponent(); uf::Serializer& masterdata = scene.getComponent(); - std::string url = "./data/audio/ui/" + key + ".ogg"; + std::string url = uf::io::root+"/audio/ui/" + key + ".ogg"; uf::Asset& assetLoader = scene.getComponent(); assetLoader.cache(url, "asset:Cache.SFX." + std::to_string(entity.getUid())); @@ -280,7 +280,7 @@ void ext::GuiDialogue::tick() { if ( metadata["system"]["closing"].as() ) { if ( alpha >= 1.0f ) { uf::Asset assetLoader; - std::string canonical = assetLoader.load("./data/audio/ui/menu close.ogg"); + std::string canonical = assetLoader.load(uf::io::root+"/audio/ui/menu close.ogg"); uf::Audio& sfx = assetLoader.get(canonical); sfx.setVolume(masterdata["volumes"]["sfx"].as()); sfx.play(); diff --git a/ext/scenes/worldscape/housamo/battle.cpp b/ext/scenes/worldscape/housamo/battle.cpp index 5f436d24..0e185f0c 100644 --- a/ext/scenes/worldscape/housamo/battle.cpp +++ b/ext/scenes/worldscape/housamo/battle.cpp @@ -55,7 +55,7 @@ namespace { std::string url = "https://cdn..xyz//unity/Android/voice/voice_" + name + "_"+key+".ogg"; if ( charaData["internal"].as() ) { - url = "./data/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; + url = uf::io::root+"/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } uf::Asset& assetLoader = scene.getComponent(); @@ -77,7 +77,7 @@ namespace { uf::Serializer& metadata = entity.getComponent(); uf::Serializer& masterdata = scene.getComponent(); - std::string url = "./data/audio/ui/" + key + ".ogg"; + std::string url = uf::io::root+"/audio/ui/" + key + ".ogg"; uf::Asset& assetLoader = scene.getComponent(); assetLoader.cache(url, "asset:Cache.SFX." + std::to_string(entity.getUid())); @@ -178,7 +178,7 @@ void ext::HousamoBattle::initialize() { // generate battle data - uf::Serializer actions; actions.readFromFile("./data/entities/gui/battle/actions.json"); + uf::Serializer actions; actions.readFromFile(uf::io::root+"/entities/gui/battle/actions.json"); metadata["actions"] = actions; if ( ext::json::isNull( metadata["actions"] ) ) { metadata["actions"]["00.member-attack"] = "攻撃"; diff --git a/ext/scenes/worldscape/housamo/dialogue.cpp b/ext/scenes/worldscape/housamo/dialogue.cpp index 33575fbd..8da01c43 100644 --- a/ext/scenes/worldscape/housamo/dialogue.cpp +++ b/ext/scenes/worldscape/housamo/dialogue.cpp @@ -48,7 +48,7 @@ namespace { std::cout << url << std::endl; if ( charaData["internal"].as() ) { - url = "./data/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; + url = uf::io::root+"/smtsamo/voice/voice_" + name + "_" + key + ".ogg"; } uf::Asset& assetLoader = scene.getComponent(); diff --git a/ext/scenes/worldscape/terrain/behavior.cpp b/ext/scenes/worldscape/terrain/behavior.cpp index 84412d5f..61950458 100644 --- a/ext/scenes/worldscape/terrain/behavior.cpp +++ b/ext/scenes/worldscape/terrain/behavior.cpp @@ -46,19 +46,20 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { modifiers["region"]["modulus"] = metadata["region"]["modulus"]; std::string input = modifiers; metadata["system"]["hash"] = uf::string::sha256( input ); - + #if !UF_ENV_DREAMCAST try { - std::string save = "./data/save/" + metadata["system"]["hash"].as() + "/"; + std::string save = uf::io::root+"/save/" + metadata["system"]["hash"].as() + "/"; int status = mkdir(save.c_str()); } catch ( ... ) { } try { - std::string save = "./data/save/" + metadata["system"]["hash"].as() + "/regions/"; + std::string save = uf::io::root+"/save/" + metadata["system"]["hash"].as() + "/regions/"; int status = mkdir(save.c_str()); } catch ( ... ) { } + #endif } // setup maze @@ -113,8 +114,8 @@ void ext::TerrainBehavior::initialize( uf::Object& self ) { if ( _ != "" ) suffix = _ + "."; } graphic.material.initializeShaders({ - {"./data/shaders/terrain.vert.spv", uf::renderer::enums::Shader::VERTEX}, - {"./data/shaders/terrain.frag.spv", uf::renderer::enums::Shader::FRAGMENT} + {uf::io::root+"/shaders/terrain.vert.spv", uf::renderer::enums::Shader::VERTEX}, + {uf::io::root+"/shaders/terrain.frag.spv", uf::renderer::enums::Shader::FRAGMENT} }); // uf::renderer::rebuildOnTickStart = false; } diff --git a/ext/scenes/worldscape/terrain/generator.cpp b/ext/scenes/worldscape/terrain/generator.cpp index 2a4aace6..eaaa2ba4 100644 --- a/ext/scenes/worldscape/terrain/generator.cpp +++ b/ext/scenes/worldscape/terrain/generator.cpp @@ -95,7 +95,7 @@ void ext::TerrainGenerator::generate( uf::Object& region ){ } */ std::string base = region.getParent().getComponent()["system"]["hash"].as(); - std::string filename = "./data/save/" + base + "/regions/" + std::to_string(location.x) + "." + std::to_string(location.y) + "." + std::to_string(location.z) + ".json"; + std::string filename = uf::io::root+"/save/" + base + "/regions/" + std::to_string(location.x) + "." + std::to_string(location.y) + "." + std::to_string(location.z) + ".json"; // old region, load save if ( uf::io::exists( filename ) ) { uf::Serializer save; save.readFromFile(filename); @@ -330,7 +330,7 @@ void ext::TerrainGenerator::writeToFile() { uf::Serializer serializer; std::string base = this->m_terrain ? this->m_terrain->getComponent()["system"]["hash"].as() : "UNKNOWN"; - std::string filename = "./data/save/" + base + "/regions/" + std::to_string(this->m_location.x) + "." + std::to_string(this->m_location.y) + "." + std::to_string(this->m_location.z) + ".json"; + std::string filename = uf::io::root+"/save/" + base + "/regions/" + std::to_string(this->m_location.x) + "." + std::to_string(this->m_location.y) + "." + std::to_string(this->m_location.z) + ".json"; { // encode as base64, json safe serializer["voxels"]["id"]["base64"] = uf::base64::encode( this->m_voxels.id.rle ); diff --git a/ext/scenes/worldscape/terrain/maze.cpp b/ext/scenes/worldscape/terrain/maze.cpp index 9cbf675c..452476f9 100644 --- a/ext/scenes/worldscape/terrain/maze.cpp +++ b/ext/scenes/worldscape/terrain/maze.cpp @@ -28,7 +28,9 @@ void ext::Maze::initialize(int columns, int rows, int floors, double horizontal_ */ if (rows < 1 || columns < 1 || floors < 1){ std::cout << "A maze must have dimensions greater than zero.\n"; + #if !UF_NO_EXCEPTIONS throw std::invalid_argument("A maze must have dimensions greater than zero.\n"); + #endif } LENGTH = columns; WIDTH = rows; @@ -36,7 +38,9 @@ void ext::Maze::initialize(int columns, int rows, int floors, double horizontal_ if (horizontal_bias <= 0 || horizontal_bias >= 1 || vertical_bias <= 0 || vertical_bias >= 1){ std::cout << "Biases must be between 0 and 1 exclusive.\n"; + #if !UF_NO_EXCEPTIONS throw std::invalid_argument("Biases must be between 0 and 1 exclusive.\n"); + #endif } EAST_WALL_THRESHOLD = horizontal_bias; SOUTH_WALL_THRESHOLD = vertical_bias; diff --git a/ext/scenes/worldscape/terrain/region.cpp b/ext/scenes/worldscape/terrain/region.cpp index 4467e089..25c6d8e6 100644 --- a/ext/scenes/worldscape/terrain/region.cpp +++ b/ext/scenes/worldscape/terrain/region.cpp @@ -53,8 +53,8 @@ void ext::RegionBehavior::initialize( uf::Object& self ) { } graphic.material.initializeShaders({ - {"./data/shaders/terrain.vert.spv", uf::renderer::enums::Shader::VERTEX}, - {"./data/shaders/terrain.frag.spv", uf::renderer::enums::Shader::FRAGMENT} + {uf::io::root+"/shaders/terrain.vert.spv", uf::renderer::enums::Shader::VERTEX}, + {uf::io::root+"/shaders/terrain.frag.spv", uf::renderer::enums::Shader::FRAGMENT} }); } diff --git a/makefiles/dreamcast.gcc.make b/makefiles/dreamcast.gcc.make new file mode 100644 index 00000000..a704f592 --- /dev/null +++ b/makefiles/dreamcast.gcc.make @@ -0,0 +1,5 @@ +ARCH = dreamcast +PREFIX = gcc +CC = $(KOS_CCPLUS) +FLAGS = -Wno-attributes -Wno-conversion-null -fdiagnostics-color=always -DUF_DISABLE_ALIGNAS -Og +TARGET_EXTENSION = elf \ No newline at end of file