#!/bin/bash
set -eu

for arg in "$@"; do declare $arg="1"; done
if [ ! -v clang ]; 												then gcc=1; fi
if [ ! -v release ]; 											then debug=1; fi
if [ -v debug ]; 													then echo "[debug mode]"; fi
if [ -v release ];												then echo "[release mode]"; fi
if [ -v gcc ]; 														then compiler="${CC:-gcc}"; cpp_compiler="g++"; echo "[gcc compiler]"; fi
if [ -v clang ]; 													then compiler="${CC:-clang}"; cpp_compiler="clang++"; echo "[clang compiler]"; fi
if [ ! -v vulkan ];												then vulkan=1; fi
if [ -v vulkan ]; 												then render_flag="-DSTG_VULKAN_RENDERER"; fi
if [ -v vulkan ]; 												then render_link="-lvulkan -l:libvma.a"; echo "[vulkan renderer]"; fi
if [ ! -v render_flag ];									then render_flag="-DSTG_VULKAN_RENDERER"; vulkan="vulkan"; echo "[default renderer - vulkan]"; fi
if [ -v test ];														then test_build=1; echo "[test build]"; fi

# source files
source_files="../src/entry_linux.c"
packer_source_files="../src/packer.c"

# includes
include_flags="-I../src/ -I../external/ -L. -I../external/dxvk/include/ -L../external/dxvk/lib/"
packer_include_flags="-I../src/ -I../external/"

# executable name
out_name="Gears"
packer_out_name="Packer"

# vma flags
vma_source_files="../external/vma/vma.cpp"
vma_compile_flags="-std=c++20 -D_USE_MATH_DEFINES -I../external/vma -c -Wno-everything -static"
vma_out="-o"
vma_obj="vma.o"

# glslc
glsl_compile="glslc"
glsl_flags="--target-spv=spv1.6 -std=460"
glsl_stage_vert="-fshader-stage=vert"
glsl_stage_frag="-fshader-stage=frag"
glsl_stage_tesc="-fshader-stage=tesc"
glsl_stage_tese="-fshader-stage=tese"
glsl_stage_geom="-fshader-stage=geom"
glsl_stage_comp="-fshader-stage=comp"
glsl_out="-o./shaders/glsl/"

# clang
clang_common="${include_flags} ${render_flag} -DCOMPILER_CLANG -std=c23 -fuse-ld=mold -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0 -ferror-limit=60"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}"
clang_release="$compiler -O2 ${clang_common}"
clang_test="$compiler -O2 -DBUILD_TEST=1 ${clang_common}"
clang_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++"
clang_out="-o"

# gcc
gcc_common="${include_flags} ${render_flag} -DCOMPILER_GCC -std=c23 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0 -fzero-init-padding-bits=unions"
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}"
gcc_release="$compiler -O2 ${gcc_common} ${render_flag}"
gcc_test="$compiler -O0 -DBUILD_TEST=1 ${gcc_common} ${render_flag}"
gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++"
gcc_out="-o"

# linking
link_dll="-fPIC"
link_os_gfx="-lxcb -lX11 -lX11-xcb -lvulkan"

if [ -v gcc ]; 			then compile_debug="$gcc_debug"; fi
if [ -v gcc ]; 			then compile_release="$gcc_release"; fi
if [ -v gcc ];			then compile_test="$gcc_test"; fi
if [ -v gcc ];			then compile_link="$gcc_link"; fi
if [ -v gcc ]; 			then out="$gcc_out"; fi

if [ -v clang ]; 		then compile_debug="$clang_debug"; fi
if [ -v clang ]; 		then compile_release="$clang_release"; fi
if [ -v clang ];		then compile_test="$clang_debug"; fi
if [ -v clang ]; 		then compile_link="$clang_link"; fi
if [ -v clang ]; 		then out="$clang_out"; fi

if [ -v debug ]; 		then compile="$compile_debug"; fi
if [ -v release ];	then compile="$compile_release"; fi
if [ -v test ]; 		then compile="$compile_test"; fi

mkdir -p build

cd build

if [ ! -v packer ]; then

if [ -v vulkan ]; then
	mkdir -p ./shaders/glsl
	
	for file in ../src/shaders/glsl/*.glsl; do
		base_name=$(basename -- "$file" .glsl)

		case "$base_name" in 
			*.vert) glsl_stage="${glsl_stage_vert}" ;;
			*.frag) glsl_stage="${glsl_stage_frag}" ;;
			*.tesc) glsl_stage="${glsl_stage_tesc}" ;;
			*.tese) glsl_stage="${glsl_stage_tese}" ;;
			*.geom) glsl_stage="${glsl_stage_geom}" ;;
			*.comp) glsl_stage="${glsl_stage_comp}" ;;
			*) continue ;;
		esac

		$glsl_compile $glsl_flags $glsl_stage $file "${glsl_out}${base_name}.spv"
	done
fi

if ! [ -f libvma.a ]; then
	$cpp_compiler $vma_compile_flags $vma_source_files $vma_out $vma_obj
	ar rcs libvma.a vma.o
fi

elif [ -v packer ] || ! [ -f Packer ]; then
	$compile $packer_source_files $compile_link $link_os_gfx $packer_include_flags $out $packer_out_name
fi

if [ -v pack ]; then
	cd ..
	./build/Packer
	cd build
fi

if  ! [ -v packer ]; then
	$compile $source_files $compile_link $link_os_gfx $out $out_name
fi

