Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1234debf38 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -13,7 +13,4 @@ vgcore.*
|
||||
*_TEMPLATE.png
|
||||
/out
|
||||
GRAPH*.gv
|
||||
GRAPH*.png
|
||||
SICK_JOKE*
|
||||
*.hi
|
||||
*_stub.h
|
||||
GRAPH*.png
|
||||
@ -17,50 +17,46 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
message(INFO ${LIBPIPEWIRE_CFLAGS})
|
||||
#add_compile_options("-I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 -I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBPIPEWIRE_CFLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \
|
||||
-I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 \
|
||||
-I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2 ")
|
||||
|
||||
add_compile_definitions(_POSIX_C_SOURCE=200112L)
|
||||
add_compile_definitions(_GNU_SOURCE)
|
||||
add_compile_options(-fno-trapping-math)
|
||||
|
||||
add_executable(codegen_l1 src/l1/anne/codegen.c)
|
||||
target_compile_definitions(codegen_l1
|
||||
PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8)
|
||||
add_executable(A src/l2/tests/hse/A/A.c)
|
||||
|
||||
#add_executable(codegen_l1 src/l1/anne/codegen.c)
|
||||
#target_compile_definitions(codegen_l1
|
||||
# PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8)
|
||||
|
||||
#add_executable(0_test src/l1_4/tests/t0.c)
|
||||
#add_executable(1_test src/l1_4/tests/t1.c)
|
||||
add_executable(3_test src/l1_4/tests/t3.c)
|
||||
target_link_libraries(3_test -lm)
|
||||
#
|
||||
|
||||
#add_executable(l1_4_t2 src/l1_4/tests/t2.c)
|
||||
|
||||
add_executable(codegen_l1_5 src/l1_5/anne/codegen.c)
|
||||
#add_executable(codegen_l1_5 src/l1_5/anne/codegen.c)
|
||||
|
||||
#add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c
|
||||
# src/l1/core/rb_tree_node.h)
|
||||
#target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng)
|
||||
|
||||
#add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c)
|
||||
#target_link_libraries(0r_tex_init_prep -lm -lpng)
|
||||
|
||||
#add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
#target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon)
|
||||
#
|
||||
add_executable(r2a src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
target_link_libraries(r2a ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon)
|
||||
|
||||
add_executable(r2c src/l2/tests/r2/r2c.c)
|
||||
target_link_libraries(r2c -lm)
|
||||
#add_executable(2a_render_test src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
#target_link_libraries(2a_render_test ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon)
|
||||
|
||||
#
|
||||
#add_executable(3_render_test src/l2/tests/r3/r3.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
#target_link_libraries(3_render_test -lwayland-client -lm -lvulkan -lxkbcommon)
|
||||
|
||||
#add_executable(l2t0_2 src/l2/tests/data_structures/t0_2.c) // todo: I will get back
|
||||
#add_executable(l2t0 src/l2/tests/data_structures/t0.c)
|
||||
#add_executable(l2t0_3 src/l2/tests/data_structures/t0_3.c)
|
||||
#add_executable(l2t2 src/l2/tests/data_structures/t2.c)
|
||||
#add_executable(0_play_test src/l3/tests/p0.c)
|
||||
#target_link_libraries(0_play_test -lncurses)
|
||||
|
||||
#add_executable(l2t0 src/l2/tests/data_structures/t0.c)
|
||||
#add_executable(l2t1 src/l2/tests/data_structures/t1.c)
|
||||
|
||||
add_executable(l2_tex_gen src/l2/anne/codegen.c)
|
||||
target_link_libraries(l2_tex_gen -lm -lpng)
|
||||
|
||||
add_executable(l2_r4 src/l3/r4/r4.c gen/l_wl_protocols/xdg-shell-private.c)
|
||||
target_link_libraries(l2_r4 -lvulkan -lwayland-client -lm -lxkbcommon -lpng -lfreetype)
|
||||
|
||||
94
Makefile
94
Makefile
@ -1,20 +1,13 @@
|
||||
find_headers = $(shell find src/$(1) -type f -name '*.h' )
|
||||
find_assets = $(shell find src/$(1) -type f \( -name "*.vert" -o -name "*.frag" -o -name "*.geom" -o -name "*.comp" \) )
|
||||
find_headers = $(shell find src/$(1) -type f -name '*.h')
|
||||
|
||||
HEADERS_src_l1 := $(call find_headers,l1)
|
||||
#HEADERS_gen_l1 := $(HEADERS_src_l1) gen/l1/dorothy.txt
|
||||
HEADERS_gen_l1 := gen/l1/dorothy.txt
|
||||
HEADERS_gen_l1 := $(HEADERS_src_l1) gen/l1/dorothy.txt
|
||||
|
||||
HEADERS_src_l1_5 = $(HEADERS_gen_l1) $(call find_headers,l1_5)
|
||||
#HEADERS_gen_l1_5 := $(HEADERS_src_l1_5) gen/l1_5/dorothy.txt
|
||||
HEADERS_gen_l1_5 := gen/l1_5/dorothy.txt
|
||||
|
||||
ASSETS_src_l_adele = $($call find_assets,l_adele)
|
||||
ASSETS_gen_l_adele = gen/l_adele/dorothy.txt
|
||||
HEADERS_gen_l1_5 := $(HEADERS_src_l1_5) gen/l1_5/dorothy.txt
|
||||
|
||||
HEADERS_src_l2 := $(HEADERS_gen_l1_5) $(call find_headers,l2)
|
||||
#HEADERS_gen_l2 := $(HEADERS_src_l2) gen/l2/dorothy.txt
|
||||
HEADERS_gen_l2 := gen/l2/dorothy.txt
|
||||
HEADERS_gen_l2 := $(HEADERS_src_l2) gen/l2/dorothy.txt
|
||||
|
||||
cflags := -Wall -Wextra -Werror=implicit-function-declaration -Werror=return-type -Wno-unused-parameter \
|
||||
--std=c99 -g -ggdb -O0 \
|
||||
@ -24,16 +17,6 @@ cc := gcc
|
||||
wl_protocols := $(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
||||
libpipewire_flags := $(shell pkg-config --cflags --libs libpipewire-0.3)
|
||||
|
||||
xdg_shell_private_c := gen/l_wl_protocols/xdg-shell-private.c
|
||||
xdg_shell_client_h := gen/l_wl_protocols/xdg-shell-client.h
|
||||
xdg_shell_private_o := out/l_wl_protocols/xdg-shell-private.o
|
||||
|
||||
l_wl_protocols := $(xdg_shell_client_h) $(xdg_shell_private_c)
|
||||
|
||||
$(xdg_shell_private_o): $(l_wl_protocols)
|
||||
mkdir -p out/l_wl_protocols
|
||||
$(cc) $(cflags) -o $@ -c $(xdg_shell_private_c) -lwayland-client
|
||||
|
||||
out/l1/codegen: src/l1/anne/codegen.c $(HEADERS_src_l1)
|
||||
mkdir -p out/l1
|
||||
$(cc) $(cflags) -D PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8 -o $@ $<
|
||||
@ -67,33 +50,9 @@ gen/l_wl_protocols/xdg-shell-private.c: $(wl_protocols)/stable/xdg-shell/xdg-she
|
||||
mkdir -p gen/l_wl_protocols
|
||||
wayland-scanner private-code $< $@
|
||||
|
||||
.PHONY: gen/l_wl_protocols
|
||||
gen/l_wl_protocols : $(l_wl_protocols)
|
||||
xdg_shell_private := gen/l_wl_protocols/xdg-shell-private.c
|
||||
l_wl_protocols := gen/l_wl_protocols/xdg-shell-client.h $(xdg_shell_private)
|
||||
|
||||
out/l2/codegen: src/l2/anne/codegen.c $(HEADERS_src_l2)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< -lm -lpng
|
||||
|
||||
gen/l2/dorothy.txt: out/l2/codegen
|
||||
mkdir -p gen
|
||||
cd gen && ../out/l2/codegen
|
||||
|
||||
# First argument is path (relative to src/l_adele), second argument is a name of shader files in shader folder
|
||||
compile_vert_shader = glslc -o gen/l_adele/$(1)/vert.spv src/l_adele/$(1)/$(2).vert
|
||||
compile_frag_shader = glslc -o gen/l_adele/$(1)/frag.spv src/l_adele/$(1)/$(2).frag
|
||||
|
||||
define compile_shader
|
||||
mkdir -p gen/l_adele/$(1)
|
||||
$(call compile_vert_shader,$(1),$(2))
|
||||
$(call compile_frag_shader,$(1),$(2))
|
||||
endef
|
||||
|
||||
gen/l_adele/dorothy.txt: $(ASSETS_src_l_adele)
|
||||
$(call compile_shader,lucy,lucy)
|
||||
$(call compile_shader,alice/0gen,0gen)
|
||||
$(call compile_shader,alice/0sh,0sh)
|
||||
$(call compile_shader,alice/1,1)
|
||||
touch gen/l_adele/dorothy.txt
|
||||
|
||||
out/l2/t0: src/l2/tests/data_structures/t0.c $(HEADERS_gen_l1_5)
|
||||
mkdir -p out/l2
|
||||
@ -101,12 +60,29 @@ out/l2/t0: src/l2/tests/data_structures/t0.c $(HEADERS_gen_l1_5)
|
||||
|
||||
.PHONY: run_l2_t0
|
||||
run_l2_t0: out/l2/t0
|
||||
mkdir -p src/l2/tests/data_structures/GRAPHS
|
||||
cd src/l2/tests/data_structures && ../../../../out/l2/t0
|
||||
|
||||
out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS_src_l2) $(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private) -lvulkan -lm -lxkbcommon -lwayland-client -lpng
|
||||
|
||||
out/l2/r0_tex_init_prep: src/l2/tests/r0/r0_tex_init_prep.c $(HEADERS_src_l2)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< -lm -lpng
|
||||
|
||||
.PHONY: run_r0
|
||||
run_r0: out/l2/r0
|
||||
cd src/l2/tests/r0 && ../../../../out/l2/r0
|
||||
|
||||
.PHONY: run_r0_tex_init_prep
|
||||
run_r0_tex_init_prep: out/l2/r0_tex_init_prep
|
||||
cd src/l2/tests/r0 && ../../../../out/l2/r0_tex_init_prep
|
||||
|
||||
|
||||
out/l2/r1: src/l2/tests/r1/r1.c $(HEADERS_src_l2) $(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private_c) -lwayland-client -lrt -lxkbcommon -lm
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private) -lwayland-client -lrt -lxkbcommon -lm
|
||||
|
||||
.PHONY: run_r1
|
||||
run_r1: out/l2/r1
|
||||
@ -115,36 +91,22 @@ run_r1: out/l2/r1
|
||||
|
||||
out/l2/r2: src/l2/tests/r2/r2a.c $(HEADERS_src_l2) $(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private_c) -lwayland-client -lrt -lxkbcommon -lm $(libpipewire_flags)
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private) -lwayland-client -lrt -lxkbcommon -lm $(libpipewire_flags)
|
||||
|
||||
.PHONY: run_r2
|
||||
run_r2: out/l2/r2
|
||||
./out/l2/r2
|
||||
|
||||
|
||||
out/l2/r3: src/l2/tests/r3/r3.c $(HEADERS_src_l2) $(l_wl_protocols)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private_c) -lwayland-client -lrt -lxkbcommon -lm -lvulkan
|
||||
$(cc) $(cflags) -o $@ $< $(xdg_shell_private) -lwayland-client -lrt -lxkbcommon -lm -lvulkan
|
||||
|
||||
.PHONY: run_r3
|
||||
run_r3: out/l2/r3
|
||||
./out/l2/r3
|
||||
|
||||
# Whoever needs this will also need out/l_wl_protocols
|
||||
out/l2/allie.o: src/l2/allie/allie.c $(HEADERS_src_l2) $(xdg_shell_client_h) gen/l_adele/dorothy.txt $(HEADERS_gen_l2)
|
||||
mkdir -p out/l2
|
||||
$(cc) $(cflags) -o $@ -c $< -lvulkan -lm -lxkbcommon -lwayland-client -lpng -lfreetype
|
||||
|
||||
full_allie_obj := out/l2/allie.o $(xdg_shell_private_o)
|
||||
|
||||
out/l3/r4: src/l3/r4/R4.hs src/l2/allie/Allie.hs $(full_allie_obj)
|
||||
mkdir -p out/l3
|
||||
ghc -isrc/l2/allie -hidir out/l3/ -odir out/l3 -o $@ $< $(full_allie_obj) \
|
||||
-lvulkan -lm -lxkbcommon -lwayland-client -lpng -lfreetype
|
||||
|
||||
.PHONY: run_r4
|
||||
run_r4: out/l3/r4
|
||||
./out/l3/r4
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf gen out
|
||||
rm -rf gen out
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
Fonts used:
|
||||
DM Serif Text made by Colophon Foundry
|
||||
Roboto made by Christian Robertson, Paratype, Font Bureau
|
||||
Great Vibes made by Robert Leuschke
|
||||
@ -1,13 +1,10 @@
|
||||
#import "../head.typ": *
|
||||
|
||||
#set page(margin: (top: 1.5cm, left: 2cm, right: 2cm), footer: context {align(center, counter(page).display("1"))})
|
||||
#set page(footer: context {align(center, counter(page).display("1"))})
|
||||
#set text(size: 1.2em)
|
||||
#set par(first-line-indent: 16pt)
|
||||
|
||||
#align(center, heading(depth: 1)[Архитектура и стиль
|
||||
кода в Дарье (prototype1)])
|
||||
|
||||
#heading(depth: 2)[Структура репозитория]
|
||||
#align(center, heading(depth: 1)[Архитектура и стиль кода в prototype1 (Дарье)])
|
||||
|
||||
Для компиляции используется только сборочная система make.
|
||||
Генерировать makefile с помощью shell-скрипта разрешено, просто в данный момент это не
|
||||
@ -75,116 +72,18 @@ haskell и rust. Самые высшие уровни Дарьи это те, ч
|
||||
Код с более высокого уровня может использовать код с более низкого уровня.
|
||||
Сгенерированный код с какого-то уровня может использовать исходный код
|
||||
с этого же уровня, но исходный код не может использовать генерированный
|
||||
код своего уровня. Тем не менее код из `src/lX`,
|
||||
код своего уровня. Тем не менее код,
|
||||
генерирующий другой код, может быть осведомлён о существовании и содердании
|
||||
более высоких слоёв, но только если он находится в специальной папке
|
||||
`src/lX/anne`. Цель (функция `main`), что генерирует код `gen/lX` находится в
|
||||
c-файле `src/lX/anne/codegen.c`. Вместе с ним в `src/lX/anne` помещены
|
||||
h-файлы, которые содержат 'под-процедуры' от `src/lX/anne/codegen.c`,
|
||||
каждый файл использует доступные в `src/lX` методы для нужд своего более высокого
|
||||
уровня. В `src/lX/codegen` содержатся исключительно методы для генерации кода,
|
||||
которые используются в `src/lX/anne`, но сам `src/lX/anne` не
|
||||
осведомлён о высших уровнях. Больше нигде код, нужный непосредственно для генерации
|
||||
кода, не помещается.
|
||||
|
||||
Из этого правила есть ОДНО исключение:
|
||||
Файл `src/l1/core/VecU8_as_str.h` при компиляции цели `src/l1/anne/codegen.h`
|
||||
использует, как ему и положено, только исходный код с первого уровня, но
|
||||
при компиляции любых другиц целей он инклюдит `gen/l1/VecAndSpan_U8.h`.
|
||||
Казалось бы, это нарушение, ведь именно `src/l1` отвечает за генерацию `gen/l1`,
|
||||
но это самый первый уровень, и если `gen/l1/VecAndSpan_U8.h` ещё не существует - значит
|
||||
наше цель это и есть `src/l1/anne/codegen.c`. В этом случае вместо
|
||||
`gen/l1/VecAndSpan_U8.h` инклюдится `src/l1/core/chicken_VecU8.h`.
|
||||
Файл `src/l1/core/chicken_VecU8.h` содержит копию некоторых самых полезных методов из
|
||||
`gen/l1/VecAndSpan_U8.h`, что позволяет писать и `l1` и все другие уровни с
|
||||
одним и тем же определение строки. Это грязный трюк, но он сэкономил мне
|
||||
сотни нервных клеток.
|
||||
|
||||
_Не спрашивай как я написал `src/l1/core/chicken_VecU8.h` без
|
||||
`gen/l1/VecAndSpan_U8.h`_...
|
||||
`gen/l1vi`
|
||||
|
||||
Разберём что делает каждый уровень, что есть в данный момент в Дарье:
|
||||
|
||||
- `l_wl_protocols` -- из-за странного способа дистрибуции wayland-lib мы должны сами
|
||||
генерировать код для неё.
|
||||
- `l1` -- самый первый уровень.
|
||||
- - Тут определены все утилиты, которые не
|
||||
потребовали кодгена.
|
||||
- - Исходный код `l` определяет типы и функции,
|
||||
полезные при любой генерации кода.
|
||||
- - В утилитах `l1` есть
|
||||
обёртки над базовыми обёртками над системными вызовами линукса.
|
||||
- - Шаблоны: `Vec<T>`, `Option<T>`, `Span<T>`, `MutSpan<T>`, `Result<O>Or<E>`.
|
||||
Ну а раз на нём эти шаблоны определены,
|
||||
то в этом же уровне код из папки `src/l1/anne` инстанциирует их для
|
||||
ВСЕХ будущих целей.
|
||||
- - `gen/l1/geom.h` -- файл со структурами
|
||||
векторов и матриц, их методами для операций из линейной алгебры.
|
||||
|
||||
- - В `gen/l1/pixel_masses.h` инстанциированы матрицы пикселей,
|
||||
или же проще - текстуры,
|
||||
хранящиеся в памяти максимально тривиальным способом.
|
||||
|
||||
#block(width: 100%, inset: 5pt, fill: luma(90%), radius: 4pt)[#par()[
|
||||
В `gen/l1` лежат
|
||||
много много крутых заголовков, но `geom.h` и `pixel_masses.h` особенны тем,
|
||||
что они не содержат в себе осведомление о высших уровнях, они пришли от самого `l1`,
|
||||
а не просто зашли в `l1`, поскольку здесь впервые стали доступны методы для их
|
||||
генерации.
|
||||
]]
|
||||
|
||||
- `l1_4` -- Тут просто лежат тесты для шаблонов `l1`.
|
||||
|
||||
- `l1_5`
|
||||
- - Инстанциация `Box`, `Ref`, `RefMut` для трейта (инстанциация
|
||||
'громадных' ссылок).
|
||||
- - `gen/l1_5/marie/clipping.h` - дурацкий бесполезный файл для
|
||||
пересечения треугольников. Даже не тестил его. Удалю его когда-нибудь.
|
||||
- - Шаблоны `BuffRBTree_Set<T>`, `BuffRBTree_Map<K, V>`
|
||||
|
||||
- `l2`
|
||||
- - Тесты для `l1_5`.
|
||||
- - `src/l2/liza` -- пространство имён для обёрток над `pipewire` и работы со звуком.
|
||||
- - `src/l2/margaret/time_utils.h` -- утилиты для замерки времени с использованием
|
||||
системных часов.
|
||||
- - `src/l2/margaret/vulkan_utils.h` -- утилиты для использования Vulkan.
|
||||
- - `src/l2/marie/graphics_geom.h`, `src/l2/marie/shape_geom.h` -- больше
|
||||
алгебраических утилит, более специализированных.
|
||||
- - `src/l2/marie/rasterization.h` -- Растеризация треугольников на процессоре.
|
||||
- - `src/l2/marie/texture_processing.h` -- Утилиты для обработки текстур
|
||||
на процессоре. Как и код, куча текстур генерируется автоматически, для этих целей
|
||||
создан этот файл.
|
||||
- - Тесты к `l1_5`
|
||||
- - Особые тесты, названные `r` + `<число>`. Они не строгие их просто надо
|
||||
запустить и проверить, что они запускаются.
|
||||
|
||||
Этот список не полный.
|
||||
|
||||
#heading(depth: 2)[Утилиты и классификация типов]
|
||||
|
||||
Весь код в Дарье сильно отличается от привычного кода на C из-за многочисленных
|
||||
утилит, использующихся повсеместно. Тот, кто не знает всех утилит, определяемых в
|
||||
`l1`, не сможет дальше понять ничего.
|
||||
|
||||
Нигде в Дарье я не принимаю во внимание случай Out of Memory. Когда `malloc`
|
||||
возвращает `NULL` я немедленно завершаю программу. Поэтому я ввёл
|
||||
функции `safe_malloc`, `safe_calloc`, `safe_realloc`. Они работают как и их
|
||||
аналоги из стандартной библиотеки, но тебе не нужно беспокоиться о том что они вернут
|
||||
ошибку. Хочешь понять код Дарьи - начни читать `src/l1/core/int_primitives.h`, там
|
||||
определены слиасы для имён числовых типов. Вместо `uint32_t` надо писать
|
||||
`U32`, дабы уподобиться `Holy C`. Дальше читай `src/l1/core/util.h` чтобы понять
|
||||
все утилиты ничего незнакомого. Не всё здесь уникально для Дарьи, например,
|
||||
```c #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) ```
|
||||
здесь определён как и во многих других проектах на C.
|
||||
Дальше логически идёт `src/l1/core/VecU8_as_str.h`. Но у этого файла есть одна
|
||||
"движущаяся" зависимость - откуда он берёт `VecU8`. Первоначально он берёт
|
||||
часть методов `VecU8` из `src/l1/core/chicken_VecU8.h`. Прочитай его дабы понять какие
|
||||
методы будут у вектора. `src/l1/core/VecU8_as_str.h`
|
||||
инклюдит `src/l1/core/chicken_VecU8.h` когда определён "флаг"
|
||||
`PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8`. Поти всегда, когда что-то будет
|
||||
иметь дело строками, он будет инклюдить `VecU8_as_str.h`
|
||||
Теперь можешь заглянуть в `Makfile` и убедиться, что его структура совпадает с той,
|
||||
что я описал. Для некоторых тестов есть своя отдельная Makefile-цель `run_` +
|
||||
`<имя теста>`.
|
||||
|
||||
Определяются следуюущие трейты для типов
|
||||
- `l1` -- самый первый уровень. Тут определены все утилиты, которые не
|
||||
потребовали кодгена. Так же исходный код `l` определяет типы и функции,
|
||||
полезные при любой генерации кода. В утилитах `l1` так же есть
|
||||
обёртки над базовыми обёртками над системными вызовами линукса.
|
||||
Первый уроведь определяет самые главные шаблоны: `Vec<T>`, `Option<T>`,
|
||||
`Span<T>`, `MutSpan<T>`, `Result<O>Or<E>`,
|
||||
56
earth_doc/eng_FunMachine_description.typ
Normal file
56
earth_doc/eng_FunMachine_description.typ
Normal file
@ -0,0 +1,56 @@
|
||||
#align(center)[= JSM-3 (Fun Machine) ]
|
||||
|
||||
*This is not an official documentation. To get an official
|
||||
technical documentation of JSM-3 you need to contact Dakah
|
||||
representatives. * This is an unofficial review,
|
||||
that includes both detailed detailed guide on writing in JSM-3 machine
|
||||
code and a historical background on Fun Machine.
|
||||
|
||||
This is the 15th issue of Scratchtip journal.
|
||||
|
||||
*JSM-3* (or simply *Fun Machine*) is a computer manufactured by Dakah#sym.trademark
|
||||
corporation. It was first manufactured in a run of 100 items
|
||||
on $#[50]#sym.star.op#[233]$. It was designed for digital entertainment.
|
||||
Failed immediately, because nobody really needed a gaming
|
||||
computer with 32x32 resolution. Up to that point it is only remembered because
|
||||
it was the first publically available model from JSM series.
|
||||
|
||||
== Review of external qualities
|
||||
|
||||
Fun Machine a nefarious 32x32 led display on a 30x30 cm panel, wielded to the
|
||||
main body of the computer. It has 1 set of 16 levers on it and a
|
||||
power button with a led power indicator. Keyboard is not wielded to the main
|
||||
corpus. It is connected to it by a 1 meter cable. Keyboard contains
|
||||
50 same size keys. Keyboard is 40x25 cm in size. JSM-3 features 2^17 bytes (2^16
|
||||
words) of RAM and a JSM-3-Core CPU. JSM-3-Core is capable of running at
|
||||
80'000 tps. It should be noted, that operations that access high memory
|
||||
addresses can take seveal ticks to execute. The "bootstick reader" is located on the
|
||||
back of Fun Machine's frame. It is a long slide, that can read bootsticks t boot.
|
||||
Bootstick is a rom storage of a program that gets copied into the beginning of
|
||||
JSM-3 memory during boot. Different models of bootsticks were available for JSM-3,
|
||||
with different models providing different rom capacity. The largest could store
|
||||
2^15 word long programs. There were also 2^11, 2^12 and 2^14 bootstick models,
|
||||
all compatible with Fun Machine.
|
||||
|
||||
== JSM-3-Core
|
||||
|
||||
CPU is directly connected to memory. CPU sends signals to
|
||||
monitor module, that in turn can switch on/off lamps on the monitor.
|
||||
CPU is capable of waiting for events on the input module, such as keyboard events or
|
||||
lever update event. Input module is capable of storing 20 events in a queue-like electrical
|
||||
scheme. Also, at any time CPU can read input signal from lever board. State of 16 levers
|
||||
is described by 1 word. 2^16 words (16 bits) of ram are available to CPU. JSM-3-Core in
|
||||
JSM-3 is itself controlled by "boot-chip".
|
||||
After powering JSM-3-core, boot-chip temporarily takes control over memory card and starts
|
||||
copying boot program word by word into the ram, until bootstick reports the end.
|
||||
Physical interface of bootstick or bootstick reader won't be specified here.
|
||||
After boot-chip is done, it gives start signal to JSM-3-Corem which starts it's timer.
|
||||
Timer counts ticks, 80000 ticks per second. At the beginning of each tick CPU tries to
|
||||
execute one instruction and move to the next.
|
||||
JSM-3 lacks traditional caching. Instead, memory is divided into 3 level, based
|
||||
on it's proximity to CPU.
|
||||
- *M1*: Very fast. Addresses $[0, 2^8-1]$. Occupies first $2^8$ words.
|
||||
- *M2*: Fast. Addresses $[2^8, 2^11-1]$. Fast and very fast levels occupy first $2^11$ words.
|
||||
- *M3*: Slow. Addresses $[2^11, 2^14-1]$. Slow, fast and very fast levels occupy
|
||||
first $2^14$ words.
|
||||
- *M4*: Very slow. Addresses $[2^14, 2^161-]$.
|
||||
6
earth_doc/test.typ
Normal file
6
earth_doc/test.typ
Normal file
@ -0,0 +1,6 @@
|
||||
#import "./head.typ": *
|
||||
|
||||
Some text in line
|
||||
#rect(stroke: none)[
|
||||
#draw-content((0, 0), line(start: (0pt, 20pt), end: (40pt, 0pt), stroke: black + 0.1pt))
|
||||
]
|
||||
@ -1,29 +0,0 @@
|
||||
#ifndef prototype1_src_l1_anne_alice_h
|
||||
#define prototype1_src_l1_anne_alice_h
|
||||
|
||||
#include "../codegen/codegen.h"
|
||||
|
||||
void generate_code_for_alice_on_l1(){
|
||||
mkdir_nofail("l1/eve/alice");
|
||||
mkdir_nofail("l1/eve/alice");
|
||||
SpanU8 l = cstr("l1"), ns = cstr("alice");
|
||||
/* Assets: model topology */
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("GenericMeshVertexInc"), true, true);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("ShinyMeshVertexInc"), true, true);
|
||||
|
||||
/* Engine stuff */
|
||||
// todo: yes, maybe right now it is not primitive but I surely will make it primitive someday. Right now I don't care
|
||||
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){
|
||||
.T = cstr("AliceGenericMeshHand"), .t_primitive = true}, true);
|
||||
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){
|
||||
.T = cstr("AliceShinyMeshHand"), .t_primitive = true}, true);
|
||||
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeAliceGenericMeshHand"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("RefListNodeAliceShinyMeshHand"), true, false);
|
||||
|
||||
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
|
||||
.T = cstr("GenericMeshTopology")
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -7,13 +7,10 @@
|
||||
|
||||
#include "some_tests.h"
|
||||
#include "util_temp_vulkan.h"
|
||||
#include "margaret/margaret_misc.h"
|
||||
#include "margaret/vulkan_utils.h"
|
||||
#include "marie/graphics_geom.h"
|
||||
#include "liza.h"
|
||||
#include "embassy_l1_5.h"
|
||||
#include "margaret/png_pixel_masses.h"
|
||||
#include "lucy.h"
|
||||
#include "alice.h"
|
||||
#include "codegen_from_l1_5.h"
|
||||
|
||||
int main() {
|
||||
mkdir_nofail("l1");
|
||||
@ -24,13 +21,10 @@ int main() {
|
||||
generate_pixel_masses_header();
|
||||
generate_headers_for_r0_r1_r2_r3();
|
||||
generate_util_templ_inst_for_vulkan_headers();
|
||||
generate_margaret_eve_for_vulkan_utils();
|
||||
generate_marie_headers_for_graphics_geom();
|
||||
generate_liza_l1_headers();
|
||||
generate_l1_headers_for_l1_5();
|
||||
generate_margaret_eve_for_vulkan_utils(); /* margaret misc */
|
||||
generate_margaret_png_pixel_masses_header();
|
||||
generate_l1_lucy_headers();
|
||||
generate_code_for_alice_on_l1();
|
||||
finish_layer(cstr("l1"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ void generate_l1_headers_for_l1_5() {
|
||||
SpanU8 ns = cstr("embassy_l1_5");
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("NamedVariableRecordRef"), false, true);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("NamedMethodSignatureRecordRef"), false, true);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("BufRBTreeNode"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("RBTreeNode"), true, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -179,7 +179,7 @@ NODISCARD VecU8 generate_xmatnm_struct_and_methods(
|
||||
for (int x = 0; x < cols; x++) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s %s;\n", xvecm, vec_field_name(x)));
|
||||
if (sv) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "char _padding_%u[%u];\n", (U64)x, (U64)(16 - sv)));
|
||||
VecU8_append_vec(&res, VecU8_format(SPACE "char _padding_%d[%d];\n", x, 16 - sv));
|
||||
}
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", xmatnm));
|
||||
@ -337,81 +337,6 @@ NODISCARD VecU8 generate_square_xmatn_methods(SpanU8 xmat, SpanU8 xvec, SpanU8 m
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xmat_inverse_methods(SpanU8 xmat, SpanU8 xvec, SpanU8 memb){
|
||||
VecU8 res = VecU8_fmt("%s4 %s4_inverse(%s4 A) {\n", xmat, xmat, xmat);
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s m2[6][6] = {\n", memb));
|
||||
SpanU8 first_of_pair[6] = {cstr("x"), cstr("x"), cstr("x"), cstr("y"), cstr("y"), cstr("z")};
|
||||
SpanU8 second_of_pair[6] = {cstr("y"), cstr("z"), cstr("w"), cstr("z"), cstr("w"), cstr("w")};
|
||||
for (int w_col = 0; w_col < 6; w_col++) {
|
||||
VecU8_append_span(&res, cstr(SPACE SPACE "{ "));
|
||||
for (int w_row = 0; w_row < 6; w_row++) {
|
||||
if (w_row)
|
||||
VecU8_append_span(&res, cstr(", "));
|
||||
/* first first = A second first = B
|
||||
* first second = C second second = D
|
||||
* A * D - B * C */
|
||||
VecU8_append_vec(&res, VecU8_fmt("A.%s.%s * A.%s.%s - A.%s.%s * A.%s.%s",
|
||||
first_of_pair[w_col], first_of_pair[w_row], second_of_pair[w_col], second_of_pair[w_row],
|
||||
second_of_pair[w_col], first_of_pair[w_row], first_of_pair[w_col], second_of_pair[w_row]
|
||||
));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(" },\n"));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(SPACE "};\n"));
|
||||
|
||||
U64 a0_contr[4] = {5, 5, 4, 3};
|
||||
U64 a1_contr[4] = {4, 2, 2, 1};
|
||||
U64 a2_contr[4] = {3, 1, 0, 0};
|
||||
SpanU8 a0[4] = {cstr("y"), cstr("x"), cstr("x"), cstr("x")};
|
||||
SpanU8 a1[4] = {cstr("z"), cstr("z"), cstr("y"), cstr("y")};
|
||||
SpanU8 a2[4] = {cstr("w"), cstr("w"), cstr("w"), cstr("z")};
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s m3[4][4] = {\n", memb));
|
||||
for (int no_col = 0; no_col < 4; no_col++) {
|
||||
SpanU8 walking_column = a0[no_col];
|
||||
U64 minor_col_pair = a0_contr[no_col];
|
||||
VecU8_append_span(&res, cstr(SPACE SPACE "{ "));
|
||||
for (int no_row = 0; no_row < 4; no_row++) {
|
||||
if (no_row)
|
||||
VecU8_append_span(&res, cstr(", \n" SPACE SPACE));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"A.%s.%s * m2[%u][%u] - A.%s.%s * m2[%u][%u] + A.%s.%s * m2[%u][%u]",
|
||||
walking_column, a0[no_row], minor_col_pair, a0_contr[no_row],
|
||||
walking_column, a1[no_row], minor_col_pair, a1_contr[no_row],
|
||||
walking_column, a2[no_row], minor_col_pair, a2_contr[no_row]));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(" },\n"));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(SPACE "};\n"));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "%s d = 1 / (A.x.x * m3[0][0] - A.x.y * m3[0][1] + A.x.z * m3[0][2] - A.x.w * m3[0][3]);\n"
|
||||
SPACE "return (mat4){ "
|
||||
, memb));
|
||||
for (U64 i = 0; i < 4; i++) {
|
||||
if (i)
|
||||
VecU8_append_span(&res, cstr(",\n" SPACE SPACE ));
|
||||
VecU8_append_vec(&res, VecU8_fmt(".%s={ ", vec_field_name((int)i)));
|
||||
for (U64 j = 0; j < 4; j++) {
|
||||
if (j)
|
||||
VecU8_append_span(&res, cstr(", "));
|
||||
VecU8_append_vec(&res, VecU8_fmt("%sm3[%u][%u] * d",
|
||||
(i + j) % 2 ? cstr("-") : cstr(""), j, i));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(" }"));
|
||||
}
|
||||
VecU8_append_span(&res, cstr(" };\n}\n\n"));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s2 %s2_inverse(%s2 A) {\n" /* xmat, xmat, xmat */
|
||||
SPACE "%s d = 1 / (A.x.x * A.y.y - A.y.x * A.x.y);\n" /* memb */
|
||||
SPACE "return (%s2){ .x = { A.y.y * d, -A.x.y * d}, .y = {-A.y.x * d, A.x.x * d}};\n" /* xmat */
|
||||
"}\n\n", xmat, xmat, xmat, memb, xmat));
|
||||
|
||||
// VecU8_append_vec(&res, VecU8_fmt( "%s3 %s3_inverse(%s3 A) {\n", xmat, xmat, xmat));
|
||||
// VecU8_append_vec(&res, VecU8_fmt(SPACE "%s d = 1 / ("));
|
||||
// VecU8_append_span(&res, cstr("}\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_xmatnm_method_mul_xmatkn(SpanU8 xmat, int n, int m, int k) {
|
||||
VecU8 g_xmatkm = codegen_name_xmatnm(xmat, k, m);
|
||||
VecU8 g_xmatnm = codegen_name_xmatnm(xmat, n, m);
|
||||
@ -489,7 +414,6 @@ NODISCARD VecU8 generate_xmat234x234_structs_methods(SpanU8 xmat, SpanU8 xvec, S
|
||||
}
|
||||
}
|
||||
}
|
||||
VecU8_append_vec(&res, generate_xmat_inverse_methods(xmat, xvec, memb));
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -504,7 +428,7 @@ void generate_geom_header() {
|
||||
VecU8_append_vec(&res.result, generate_xvec234_structs_and_cool_methods(cstr("vec"), cstr("float"), cstr("sqrtf")));
|
||||
VecU8_append_vec(&res.result, generate_xvec234_structs_and_cool_methods(cstr("dvec"), cstr("double"), cstr("sqrt")));
|
||||
VecU8_append_vec(&res.result, generate_xmat234x234_structs_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float)));
|
||||
/* VecU8_append_vec(&res.result, generate_xmat234x234_structs_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double))); */
|
||||
VecU8_append_vec(&res.result, generate_xmat234x234_structs_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double)));
|
||||
finish_header(res);
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
#ifndef prototype1_src_l1_anne_lucy_h
|
||||
#define prototype1_src_l1_anne_lucy_h
|
||||
|
||||
#include "../codegen/util_template_inst.h"
|
||||
#include "../codegen/list_template_inst.h"
|
||||
|
||||
void generate_l1_lucy_headers(){
|
||||
SpanU8 l = cstr("l1"), ns = cstr("lucy");
|
||||
mkdir_nofail("l1/eve/lucy");
|
||||
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
|
||||
.T = cstr("LucyImage"), .t_primitive = true});
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("OptionLucyImage"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyStoredGlyph"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("KVPU32ToLucyFaceFixedSize"), true, false);
|
||||
|
||||
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("LucyGlyphCachingRequest"), true, true);
|
||||
|
||||
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
|
||||
.T = cstr("LucyPositionedStagingGlyph"), .vec = true, .sort = true,
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,33 +0,0 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_MARGARET_MISC_H
|
||||
#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_MARGARET_MISC_H
|
||||
|
||||
#include "../../codegen/util_template_inst.h"
|
||||
#include "../../codegen/list_template_inst.h"
|
||||
|
||||
void generate_margaret_eve_for_vulkan_utils() {
|
||||
SpanU8 l = cstr("l1");
|
||||
SpanU8 ns = cstr("margaret");
|
||||
mkdir_nofail("l1/margaret");
|
||||
mkdir_nofail("l1/eve/margaret");
|
||||
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
|
||||
.T = cstr("MargaretScoredPhysicalDevice"), .t_primitive = true, .vec = true, .sort = true
|
||||
});
|
||||
|
||||
/* For l2/margaret/{ vulkan_img_claire.h , vulkan_buffer_claire.h } */
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("MargaretIAFreeSegment"), true, false);
|
||||
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
|
||||
.T = cstr("MargaretIAFreeSegment"), .t_primitive = true});
|
||||
// todo: add to BufRBTree instantiator option to create necessary crrp by itself
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("MargaretBAFreeSegment"), true, false);
|
||||
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
|
||||
.T = cstr("MargaretBAFreeSegment"), .t_primitive = true});
|
||||
|
||||
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
|
||||
.T = cstr("BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment")});
|
||||
|
||||
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("MargaretImgAllocatorOneBlock"), true, false);
|
||||
generate_List_templ_inst_eve_header(l, ns, (list_instantiation_op){.T = cstr("MargaretBufAllocatorOneBlock")}, true);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,302 +0,0 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_PNG_PIXEL_MASSES_H
|
||||
#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_PNG_PIXEL_MASSES_H
|
||||
|
||||
#include "../../codegen/util_template_inst.h"
|
||||
|
||||
typedef struct {
|
||||
S64 channel_count;
|
||||
SpanU8 name;
|
||||
} color_type_name_in_png;
|
||||
|
||||
color_type_name_in_png color_types_names_in_png[] = {
|
||||
{1, cstr("PNG_COLOR_TYPE_GRAY")},
|
||||
{2, cstr("PNG_COLOR_TYPE_GRAY_ALPHA")},
|
||||
{3, cstr("PNG_COLOR_TYPE_RGB")},
|
||||
{4, cstr("PNG_COLOR_TYPE_RGBA")},
|
||||
};
|
||||
|
||||
NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, S64 depth, S64 channel_count) {
|
||||
if (depth != 8)
|
||||
abortf("Please no\n");
|
||||
SpanU8 color_type = cstr("");
|
||||
for (size_t i = 0; i < ARRAY_SIZE(color_types_names_in_png); i++) {
|
||||
if (color_types_names_in_png[i].channel_count == channel_count)
|
||||
color_type = color_types_names_in_png[i].name;
|
||||
}
|
||||
if (color_type.len == 0)
|
||||
abortf("Please don't\n");
|
||||
|
||||
U64 sizeof_pixel = (U64)depth / 8 * (U64)channel_count;
|
||||
VecU8 res = VecU8_new();
|
||||
|
||||
VecU8 g_promise = VecU8_fmt("MargaretPromisedPng%s", format_signature);
|
||||
SpanU8 promise = VecU8_to_span(&g_promise);
|
||||
VecU8 g_tex = VecU8_fmt("TextureData%s", format_signature);
|
||||
SpanU8 tex = VecU8_to_span(&g_tex);
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD ResultVoidOrVecU8 %s_write_to_png(const %s* self, SpanU8 filename) {\n" /* tex, tex */
|
||||
SPACE "VecU8 nt_filename = VecU8_fmt(\"%%s%%c\", filename, 0);\n"
|
||||
SPACE "FILE *fp = fopen((CSTR)nt_filename.buf, \"wb\");\n"
|
||||
SPACE "VecU8_drop(nt_filename);\n"
|
||||
SPACE "if (!fp) {\n"
|
||||
SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_fmt(\"Unable to open file %%s\", filename)};\n"
|
||||
SPACE "}\n"
|
||||
SPACE "png_structp pngshka = png_create_write_struct(PNG_LIBPNG_VER_STRING,\n"
|
||||
SPACE SPACE "NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);\n"
|
||||
SPACE "if (!pngshka)\n"
|
||||
SPACE SPACE "abortf(\"png_create_write_struct\");\n"
|
||||
SPACE "png_infop info = png_create_info_struct(pngshka);\n"
|
||||
SPACE "if (!info)\n"
|
||||
SPACE SPACE"abortf(\"png_create_info_struct\");\n"
|
||||
SPACE "png_bytep* row_pointers = NULL;\n"
|
||||
SPACE "if (setjmp(png_jmpbuf(pngshka))){\n"
|
||||
SPACE SPACE "png_destroy_write_struct(&pngshka, &info);\n"
|
||||
SPACE SPACE "fclose(fp);\n"
|
||||
SPACE SPACE "free(row_pointers);\n"
|
||||
SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr(\"Some png error happened\")};\n"
|
||||
SPACE "}\n"
|
||||
SPACE "png_init_io(pngshka, fp);\n"
|
||||
SPACE "U32 width = self->width;\n"
|
||||
SPACE "U32 height = self->height;\n"
|
||||
SPACE "png_set_IHDR(pngshka, info, width, height, %i, %s,\n" /* depth, color_type */
|
||||
SPACE SPACE "PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);\n"
|
||||
SPACE "row_pointers = calloc(height, sizeof(row_pointers));\n"
|
||||
SPACE "for (U32 y = 0; y < height; y++) {\n"
|
||||
SPACE SPACE "row_pointers[height - 1 - y] = (png_bytep)((%s_at(self, 0, y)));\n" /* tex */
|
||||
SPACE "}\n"
|
||||
SPACE "png_set_rows(pngshka, info, row_pointers);\n"
|
||||
SPACE "png_write_png(pngshka, info, 0, NULL);\n"
|
||||
SPACE "/* No more errors */\n"
|
||||
SPACE "free(row_pointers);\n"
|
||||
SPACE "png_destroy_write_struct(&pngshka, &info);\n"
|
||||
SPACE "fclose(fp);\n"
|
||||
SPACE "return (ResultVoidOrVecU8){.variant = Result_Ok};\n"
|
||||
"}\n\n"
|
||||
"/* Aborts on error */\n"
|
||||
"void %s_write_to_png_nofail(const %s* self, SpanU8 filename) {\n" /* tex, tex*/
|
||||
SPACE "ResultVoidOrVecU8 res = %s_write_to_png(self, filename);\n" /* tex */
|
||||
SPACE "if (res.variant == Result_Err) {\n"
|
||||
SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res.err), stderr);\n"
|
||||
SPACE SPACE "abortf(\" %s_write_to_png\\n\");\n" /* tex */
|
||||
SPACE "}\n"
|
||||
"}\n",
|
||||
tex, tex, depth, color_type, tex, tex, tex, tex, tex));
|
||||
|
||||
/* Non clonable structure */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "FILE* fp;\n"
|
||||
SPACE "png_structp pngshka;\n"
|
||||
SPACE "png_infop info;\n"
|
||||
SPACE "png_infop end_info;\n"
|
||||
"} %s;\n\n"
|
||||
"void %s_drop(%s self) {\n"
|
||||
SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n"
|
||||
SPACE "fclose(self.fp);\n"
|
||||
"}\n\n",
|
||||
promise, promise, promise));
|
||||
|
||||
VecU8_append_vec(&res, generate_result_template_inst(promise, cstr("VecU8"), false, false));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD Result%sOrVecU8 %s_begin(SpanU8 filename) {\n" /* promise, promise */
|
||||
SPACE "VecU8 nt_filename = VecU8_fmt(\"%%s%%c\", filename, 0);\n"
|
||||
SPACE "FILE* fp = fopen((CSTR)nt_filename.buf, \"rb\");\n"
|
||||
SPACE "VecU8_drop(nt_filename);\n"
|
||||
SPACE "if (!fp) {\n"
|
||||
SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err,\n" /* promise */
|
||||
SPACE SPACE SPACE ".err = VecU8_fmt(\"Unable to open file %%s\", filename)};\n"
|
||||
SPACE "}\n"
|
||||
SPACE "png_structp pngshka = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);\n"
|
||||
SPACE "if (!pngshka)\n"
|
||||
SPACE SPACE "abortf(\"png_create_read_struct\");\n"
|
||||
SPACE "png_infop info = png_create_info_struct(pngshka);\n"
|
||||
SPACE "if (!info)\n"
|
||||
SPACE SPACE "abortf(\"png_create_info_struct\");\n"
|
||||
SPACE "png_infop end_info = png_create_info_struct(pngshka);\n"
|
||||
SPACE "if (!end_info)\n"
|
||||
SPACE SPACE "abortf(\"png_create_info_struct\");\n"
|
||||
SPACE "if (setjmp(png_jmpbuf(pngshka))) {\n"
|
||||
SPACE SPACE "png_destroy_read_struct(&pngshka, &info, &end_info);\n"
|
||||
SPACE SPACE "fclose(fp);\n"
|
||||
SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err,\n" /* promise */
|
||||
SPACE SPACE SPACE ".err = VecU8_from_cstr(\"Some png error happened\")};\n"
|
||||
SPACE "}\n"
|
||||
SPACE "png_init_io(pngshka, fp);\n"
|
||||
SPACE "png_read_info(pngshka, info);\n"
|
||||
SPACE "U32 width, height;\n"
|
||||
SPACE "int bit_depth, color_type;\n"
|
||||
SPACE "check(png_get_IHDR(pngshka, info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));\n",
|
||||
promise, promise, promise, promise));
|
||||
|
||||
/* We are still in PROMISE_begin method, now we need to do the conversion */
|
||||
if (depth == 8) {
|
||||
VecU8_append_span(&res, cstr(
|
||||
SPACE "if (bit_depth == 16)\n"
|
||||
SPACE SPACE "png_set_strip_16(pngshka);\n"
|
||||
SPACE "else if (color_type == PNG_COLOR_TYPE_GRAY && (bit_depth == 1 || bit_depth == 2 || bit_depth == 4))\n"
|
||||
SPACE SPACE "png_set_expand_gray_1_2_4_to_8(pngshka);\n"
|
||||
));
|
||||
} else
|
||||
assert(false);
|
||||
if (channel_count == 3 || channel_count == 4) {
|
||||
VecU8_append_span(&res, cstr(
|
||||
SPACE "if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n"
|
||||
SPACE SPACE "png_set_gray_to_rgb(pngshka);\n"
|
||||
SPACE "else if (color_type == PNG_COLOR_TYPE_PALETTE)"
|
||||
SPACE SPACE "png_set_palette_to_rgb(pngshka);\n"
|
||||
));
|
||||
} else if (channel_count == 1 || channel_count == 2) {
|
||||
VecU8_append_span(&res, cstr(
|
||||
SPACE "if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGBA) {\n"
|
||||
SPACE SPACE "png_set_rgb_to_gray_fixed(pngshka, 1, 21268, 71514);\n"
|
||||
SPACE "} else if (color_type == PNG_COLOR_TYPE_PALETTE) {\n"
|
||||
SPACE SPACE "png_set_palette_to_rgb(pngshka);\n"
|
||||
SPACE SPACE "png_set_rgb_to_gray_fixed(pngshka, 1, 21268, 71514);\n"
|
||||
SPACE "}\n"
|
||||
));
|
||||
} else
|
||||
assert(false);
|
||||
if (channel_count == 4 || channel_count == 2) {
|
||||
VecU8_append_span(&res, cstr(
|
||||
SPACE "if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_PALETTE) {\n"
|
||||
SPACE SPACE "if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) \n"
|
||||
SPACE SPACE SPACE "png_set_tRNS_to_alpha(pngshka);\n"
|
||||
SPACE SPACE "else\n"
|
||||
SPACE SPACE SPACE "png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER);\n"
|
||||
SPACE "}\n"
|
||||
));
|
||||
} else if (channel_count == 1 || channel_count == 3) {
|
||||
VecU8_append_span(&res, cstr(
|
||||
SPACE "if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGBA)\n"
|
||||
SPACE SPACE "png_set_strip_alpha(pngshka);\n"
|
||||
));
|
||||
} else
|
||||
assert(false);
|
||||
/* At this point we have a converted image png structure */
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "png_read_update_info(pngshka, info);\n"
|
||||
SPACE "{\n"
|
||||
SPACE SPACE "U32 new_width, new_height;\n"
|
||||
SPACE SPACE "int new_bit_depth, new_color_type;\n"
|
||||
SPACE SPACE "check(png_get_IHDR(pngshka, info, &new_width, &new_height, &new_bit_depth, &new_color_type, NULL, NULL, NULL));\n"
|
||||
SPACE SPACE "assert(new_width == width && new_height == height && new_bit_depth == %i && new_color_type == %s);\n" /* depth, color_type */
|
||||
SPACE "}\n"
|
||||
SPACE "return (Result%sOrVecU8){.variant = Result_Ok,\n" /* promise */
|
||||
SPACE SPACE ".ok = (%s){.fp = fp, .pngshka = pngshka, .info = info, .end_info = end_info}};\n" /* promise */
|
||||
"}\n\n",
|
||||
(S64)depth, color_type,
|
||||
promise, promise));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"SizeOfRectangleU32 %s_get_extent(const %s* self) {\n" /* promise, promise */
|
||||
SPACE "U32 width, height;\n"
|
||||
SPACE "int bit_depth, color_type;\n"
|
||||
SPACE "check(png_get_IHDR(self->pngshka, self->info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));\n"
|
||||
SPACE "return (SizeOfRectangleU32){width, height};\n"
|
||||
"}\n\n",
|
||||
promise, promise));
|
||||
|
||||
assert(depth == 8 || depth == 16);
|
||||
assert(channel_count == 1 || channel_count == 2 || channel_count == 4 || channel_count == 3);
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"size_t %s_get_needed_buffer_size(const %s* self) {\n" /* promise, promise */
|
||||
SPACE "SizeOfRectangleU32 dim = %s_get_extent(self);\n" /* promise */
|
||||
SPACE "return %u * dim.width * dim.height;\n" /* sizeof_pixel */
|
||||
"}\n\n",
|
||||
promise, promise, promise, sizeof_pixel));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD ResultVoidOrVecU8 %s_finish(%s self, void* buffer) {\n" /* promise, promise */
|
||||
SPACE "SizeOfRectangleU32 dim = %s_get_extent(&self);\n" /* promise */
|
||||
SPACE "png_bytep* row_pointers = NULL;\n"
|
||||
SPACE "if (setjmp(png_jmpbuf(self.pngshka))) {\n"
|
||||
SPACE SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n"
|
||||
SPACE SPACE "fclose(self.fp);\n"
|
||||
SPACE SPACE "free(row_pointers);\n"
|
||||
SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr(\"Some png error happened\")};\n"
|
||||
SPACE "}\n"
|
||||
SPACE "row_pointers = calloc(dim.height, sizeof(row_pointers));\n"
|
||||
SPACE "for (U32 y = 0; y < dim.height; y++) {\n"
|
||||
SPACE SPACE "row_pointers[dim.height - 1 - y] = ((png_bytep)buffer) + %u * dim.width * y;\n" /* sizeof_pixel */
|
||||
SPACE "}\n"
|
||||
SPACE "png_read_image(self.pngshka, row_pointers);\n"
|
||||
SPACE "png_read_end(self.pngshka, self.end_info);\n"
|
||||
SPACE "/* No more errors */\n"
|
||||
SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n"
|
||||
SPACE "fclose(self.fp);\n"
|
||||
SPACE "free(row_pointers);\n"
|
||||
SPACE "return (ResultVoidOrVecU8){.variant = Result_Ok};\n"
|
||||
"}\n\n",
|
||||
promise, promise, promise, sizeof_pixel
|
||||
));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD Result%sOrVecU8 %s_finish_into_%s(%s self) {\n" /* tex, promise, tex, promise */
|
||||
SPACE "SizeOfRectangleU32 dim = %s_get_extent(&self);\n" /* promise */
|
||||
SPACE "if (dim.width >= UINT32_MAX / 10 || dim.height >= UINT32_MAX / 10) {\n"
|
||||
SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err, .err = vcstr(\"Input image is too big\")};\n" /* tex */
|
||||
SPACE "}\n"
|
||||
SPACE "%s tex = %s_new(dim.width, dim.height);\n" /* tex, tex */
|
||||
SPACE "ResultVoidOrVecU8 res = %s_finish(self, tex.pixels.buf);\n" /* promise */
|
||||
SPACE "if (res.variant == Result_Err) {\n"
|
||||
SPACE SPACE "%s_drop(tex);\n" /* tex */
|
||||
SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err, .err = res.err};\n" /* tex */
|
||||
SPACE "}\n"
|
||||
SPACE "return (Result%sOrVecU8){.variant = Result_Ok, .ok = tex};\n" /* tex */
|
||||
"}\n\n",
|
||||
tex, promise, tex, promise, promise, tex, tex, tex, promise, tex, tex, tex
|
||||
));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
|
||||
"/* aborts on error */\n"
|
||||
"NODISCARD %s %s_read_from_png_nofail(SpanU8 name) {\n" /* tex, tex */
|
||||
SPACE "Result%sOrVecU8 res_1 = %s_begin(name);\n" /* promise, promise */
|
||||
SPACE "if (res_1.variant == Result_Err) {\n"
|
||||
SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res_1.err), stderr);\n"
|
||||
SPACE SPACE "abortf(\" MargaretPromisedPng_begin\\n\");\n"
|
||||
SPACE "}\n"
|
||||
SPACE "/* res_1 invalidated, we moved ownership to _finish methos */\n"
|
||||
SPACE "Result%sOrVecU8 res_2 = %s_finish_into_%s(res_1.ok);\n" /* tex, promise, tex */
|
||||
SPACE "if (res_2.variant == Result_Err) {\n"
|
||||
SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res_2.err), stderr);\n"
|
||||
SPACE SPACE "abortf(\" MargaretPromisedPng_finish (into TextureData)\\n\");\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return res_2.ok;\n"
|
||||
"}\n\n",
|
||||
tex, tex, promise, promise, tex, promise, tex
|
||||
));
|
||||
|
||||
VecU8_drop(g_promise);
|
||||
VecU8_drop(g_tex);
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_margaret_png_pixel_masses_header() {
|
||||
GeneratedHeader header = begin_header(cstr("l1/margaret/png_pixel_masses.h"));
|
||||
|
||||
VecU8_append_span(&header.result, cstr(
|
||||
"#include \"../pixel_masses.h\"\n"
|
||||
"#include \"../ResultVoidOrVecU8.h\"\n"
|
||||
"#include <png.h>\n\n"));
|
||||
|
||||
VecU8_append_span(&header.result, cstr(
|
||||
"void margaret_libpng_h_error_cb(png_structp pngshka, png_const_charp err) {\n"
|
||||
SPACE "printf(\"[!] %s\\n\", err);\n"
|
||||
"}\n\n"
|
||||
"void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) {\n"
|
||||
SPACE "printf(\"[.] %s\\n\", warning);\n"
|
||||
"}\n\n"));
|
||||
|
||||
VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8"), 8, 1));
|
||||
VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8G8B8"), 8, 3));
|
||||
VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8G8B8A8"), 8, 4));
|
||||
|
||||
finish_header(header);
|
||||
}
|
||||
|
||||
#endif
|
||||
26
src/l1/anne/margaret/vulkan_utils.h
Normal file
26
src/l1/anne/margaret/vulkan_utils.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_VULKAN_H
|
||||
#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_VULKAN_H
|
||||
|
||||
#include "../../codegen/util_template_inst.h"
|
||||
|
||||
void generate_margaret_eve_for_vulkan_utils() {
|
||||
SpanU8 l = cstr("l1");
|
||||
SpanU8 ns = cstr("margaret");
|
||||
mkdir_nofail("l1/eve/margaret");
|
||||
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
|
||||
.T = cstr("MargaretScoredPhysicalDevice"), .t_primitive = true, .vec = true, .span = true,
|
||||
.mut_span = true, .collab_vec_span = true, .span_sort = true
|
||||
});
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("MargaretBufferInMemoryInfo"), true, false);
|
||||
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
|
||||
.T = cstr("PtrMargaretBufferInMemoryInfo"), .t_primitive = true, .vec = true, .span = true, .mut_span = true,
|
||||
.collab_vec_span = true
|
||||
});
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("MargaretImageInMemoryInfo"), true, false);
|
||||
generate_util_templ_inst_eve_header(l, ns, (util_templates_instantiation_options){
|
||||
.T = cstr("PtrMargaretImageInMemoryInfo"), .t_primitive = true, .vec = true, .span = true, .mut_span = true,
|
||||
.collab_vec_span = true
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -2,7 +2,6 @@
|
||||
#define PROTOTYPE_SRC_L1_CODEGEN_PIXEL_MASSES_H
|
||||
|
||||
#include "../codegen/codegen.h"
|
||||
#include "../codegen/util_template_inst.h"
|
||||
|
||||
/* Used to generate both _at() and _cat() methods */
|
||||
NODISCARD VecU8 generate_texture_data_method_at(SpanU8 tex, SpanU8 pixvec, SpanU8 memb, bool const_access) {
|
||||
@ -17,27 +16,31 @@ NODISCARD VecU8 generate_texture_data_method_at(SpanU8 tex, SpanU8 pixvec, SpanU
|
||||
|
||||
/* `tex` is the type name of texture data type
|
||||
* `memb` is the type name of pixel data type */
|
||||
NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 memb, SpanU8 luminosity_formula) {
|
||||
NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 memb) {
|
||||
VecU8 g_pixvec = VecU8_fmt("Vec%s", memb);
|
||||
SpanU8 pixvec = VecU8_to_span(&g_pixvec);
|
||||
VecU8 res = VecU8_fmt(
|
||||
|
||||
VecU8 res = VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "%s pixels;\n"
|
||||
SPACE "size_t width;\n"
|
||||
SPACE "size_t height;\n"
|
||||
"} %s;\n\n", pixvec, tex);
|
||||
/* Method _new() */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s %s_new(U32 width, U32 height) {\n"
|
||||
SPACE "assert(width == 0 || height == 0 ||\n"
|
||||
SPACE SPACE "!(SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10));\n"
|
||||
SPACE "return (%s){.pixels = %s_new_zeroinit((size_t)width * height), .width = width, .height = height};\n"
|
||||
SPACE "assert(!(SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10));\n"
|
||||
SPACE "return (%s){.pixels = %s_new_zeroinit((size_t)width * height), .width = width};\n"
|
||||
"}\n\n", tex, tex, tex, pixvec));
|
||||
/* Method _drop() */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_drop(%s self) {\n"
|
||||
SPACE "%s_drop(self.pixels);\n"
|
||||
"}\n\n", tex, tex, pixvec));
|
||||
/* Method _get_height() */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"size_t %s_get_height(const %s* self) {\n"
|
||||
SPACE "return self->pixels.len / self->width;\n"
|
||||
"}\n\n", tex, tex));
|
||||
/* Methods _at and _cat */
|
||||
VecU8_append_vec(&res, generate_texture_data_method_at(tex, pixvec, memb, false));
|
||||
VecU8_append_vec(&res, generate_texture_data_method_at(tex, pixvec, memb, true));
|
||||
@ -46,59 +49,96 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8
|
||||
"size_t %s_get_size_in_bytes(const %s* self) {\n"
|
||||
SPACE "return self->pixels.len * sizeof(%s);\n"
|
||||
"}\n\n", tex, tex, memb));
|
||||
/* Result<tex, VecU8> structure */
|
||||
VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("VecU8"), false, false));
|
||||
/* Method _to_bitmap_text()
|
||||
* We use the assumption that bytes in type member are tightly packed
|
||||
* Actually, our current method of texture read/write is super inefficient
|
||||
*/
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"VecU8 %s_to_bitmap_text(const %s* self) {\n"
|
||||
SPACE "assert(SIZE_MAX / self->pixels.len >= 100);\n"
|
||||
SPACE "size_t len = self->pixels.len * sizeof(%s);\n"
|
||||
SPACE "VecU8 res = VecU8_new_zeroinit(8 + len);\n"
|
||||
SPACE "size_t width = self->width;\n"
|
||||
SPACE "size_t height = self->pixels.len / self->width;\n"
|
||||
SPACE "assert(UINT32_MAX / width >= 10 && UINT32_MAX / height >= 10);\n"
|
||||
SPACE "for (int i = 0; i < 4; i++)\n"
|
||||
SPACE SPACE "*VecU8_mat(&res, 0 + i) = (width >> (8 * i)) & 0xff;\n"
|
||||
SPACE "for (int i = 0; i < 4; i++)\n"
|
||||
SPACE SPACE "*VecU8_mat(&res, 4 + i) = (height >> (8 * i)) & 0xff;\n"
|
||||
SPACE "memcpy(res.buf + 8, self->pixels.buf, len);\n"
|
||||
SPACE "return res;\n"
|
||||
"}\n\n", tex, tex, memb));
|
||||
/* Method _write_to_file
|
||||
* Aborts on failure */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_write_to_file(const %s* self, const char* path) {\n"
|
||||
SPACE "VecU8 data = %s_to_bitmap_text(self);\n"
|
||||
SPACE "write_whole_file_or_abort(path, VecU8_to_span(&data));\n"
|
||||
SPACE "VecU8_drop(data);\n"
|
||||
"}\n\n", tex, tex, tex));
|
||||
/* Result<texdatat, SpanU8> structure */
|
||||
VecU8 g_resoftex = VecU8_fmt("Result%sOrSpanU8", tex);
|
||||
SpanU8 resoftex = VecU8_to_span(&g_resoftex);
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "Result_variant variant;\n"
|
||||
SPACE "union {\n"
|
||||
SPACE SPACE "%s ok;\n"
|
||||
SPACE SPACE "SpanU8 err;\n"
|
||||
SPACE "};\n"
|
||||
"} %s;\n\n", tex, resoftex));
|
||||
/* Method _from_bitmap_text()
|
||||
* We assume that bytes are tightly packed in member type */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s %s_from_bitmap_text(SpanU8 text) {\n"
|
||||
SPACE "if (text.len < 8)\n"
|
||||
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"No header *crying emoji*\")};\n"
|
||||
SPACE "size_t width = 0, height = 0;\n"
|
||||
SPACE "for (int i = 0; i < 4; i++)\n"
|
||||
SPACE SPACE "width |= (((size_t)*SpanU8_at(text, 0 + i)) << (8 * i));\n"
|
||||
SPACE "for (int i = 0; i < 4; i++)\n"
|
||||
SPACE SPACE "height |= (((size_t)*SpanU8_at(text, 4 + i)) << (8 * i));\n"
|
||||
SPACE "if (SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10)\n"
|
||||
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"Image is too big\")};\n"
|
||||
SPACE "size_t len = width * height * sizeof(%s);\n"
|
||||
SPACE "if (text.len < 8 + len)\n"
|
||||
SPACE SPACE "return (%s){.variant = Result_Err, .err = cstr(\"Texture size and file size mismatch\")};\n"
|
||||
SPACE "%s res = %s_new(width, height);\n"
|
||||
SPACE "memcpy(res.pixels.buf, text.data + 8, len);\n"
|
||||
SPACE "return (%s){.variant = Result_Ok, .ok = res};\n"
|
||||
"}\n\n", resoftex, tex, resoftex, resoftex, memb, resoftex, tex, tex, resoftex));
|
||||
/* Method _read_from_file */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s %s_read_from_file(const char* path) {\n"
|
||||
SPACE "VecU8 data = read_whole_file_or_abort(path);\n"
|
||||
SPACE "%s res = %s_from_bitmap_text(VecU8_to_span(&data));\n"
|
||||
SPACE "if (res.variant != Result_Ok) {\n"
|
||||
SPACE SPACE "fprintf(stderr, \"Tried loading bitmap texture from file, but encountered decoding error: \");\n"
|
||||
SPACE SPACE "SpanU8_fprint(res.err, stderr);\n"
|
||||
SPACE SPACE "abortf(\"\\n\");\n"
|
||||
SPACE "}\n"
|
||||
SPACE "VecU8_drop(data);\n"
|
||||
SPACE "return res.ok;\n"
|
||||
"}\n\n", tex, tex, resoftex, tex));
|
||||
/* Method _is_inside() */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"bool %s_is_inside(const %s* self, S32 x, S32 y) {\n"
|
||||
SPACE "return x >= 0 && y >= 0 && x < (S32)self->width && self->width * y + x < self->pixels.len;\n"
|
||||
"}\n\n", tex, tex));
|
||||
/* Method _print() */
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_print(const %s* self) {\n" /* tex, tex */
|
||||
SPACE "U64 width = self->width;\n"
|
||||
SPACE "U64 height = self->height;\n"
|
||||
SPACE "U64 cell_width = MAX_U64(1, width / 190);\n"
|
||||
SPACE "U64 cell_height = MAX_U64(1, cell_width * 14 / 8);\n"
|
||||
SPACE "for (U64 CY = 0; CY < height; CY += cell_height) {\n"
|
||||
SPACE SPACE "for (U64 CX = 0; CX < width; CX += cell_width) {\n"
|
||||
SPACE SPACE SPACE "float lum = 0;\n"
|
||||
SPACE SPACE SPACE "for (U64 j = 0; j < cell_height; j++) {\n"
|
||||
SPACE SPACE SPACE SPACE "U64 y = CY + j;\n"
|
||||
SPACE SPACE SPACE SPACE "if (y >= height)\n"
|
||||
SPACE SPACE SPACE SPACE SPACE "continue;\n"
|
||||
SPACE SPACE SPACE SPACE "for (U64 i = 0; i < cell_width; i++) {\n"
|
||||
SPACE SPACE SPACE SPACE SPACE "U64 x = CX + i;\n"
|
||||
SPACE SPACE SPACE SPACE SPACE "if (x >= width)\n"
|
||||
SPACE SPACE SPACE SPACE SPACE SPACE "continue;\n"
|
||||
SPACE SPACE SPACE SPACE SPACE "%s pix = *%s_at(self, x, y);\n" /* memb, tex */
|
||||
SPACE SPACE SPACE SPACE SPACE "lum += %s;\n" /* luminosity_formula */
|
||||
SPACE SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE SPACE "lum /= (float)cell_width * (float)cell_height;\n"
|
||||
SPACE SPACE SPACE "putc(lum > 0.95 ? '@' : (lum > 0.8 ? '#' : (lum > 0.65 ? '*' : (lum > 0.4 ? '_' : (lum > 0.2 ? '.' : ' ')))), stdout);\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE SPACE "putc('\\n', stdout);\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n", tex, tex, memb, tex, luminosity_formula));
|
||||
|
||||
VecU8_drop(g_resoftex);
|
||||
VecU8_drop(g_pixvec);
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_pixel_masses_header() {
|
||||
GeneratedHeader res = begin_header(cstr("l1/pixel_masses.h"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_U8.h\"\n"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_int_primitives.h\"\n"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"../../src/l1/system/fileio.h\"\n"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_cvec3.h\"\n"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_cvec4.h\"\n\n"));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8"),
|
||||
cstr("(float)pix / 255")));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3"),
|
||||
cstr("(float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f")));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4"),
|
||||
cstr("(float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f")));
|
||||
VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_cvec.h\"\n\n"));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8")));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3")));
|
||||
VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4")));
|
||||
finish_header(res);
|
||||
}
|
||||
|
||||
|
||||
@ -5,12 +5,22 @@
|
||||
|
||||
void generate_headers_for_r0_r1_r2_r3() {
|
||||
SpanU8 l = cstr("l1");
|
||||
mkdir_nofail("l1/eve");
|
||||
mkdir_nofail("l1/eve/r0");
|
||||
{ /* Needed in r0_assets.h */
|
||||
SpanU8 ns = cstr("r0");
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("GenericMeshVertex"), true, true);
|
||||
generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("GenericMeshInSceneTemplate"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("GenericMeshInstance"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("ShinyMeshVertex"), true, true);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("ShinyMeshInstance"), true, false);
|
||||
generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("ShinyMeshInSceneTemplate"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("Pipeline0Spotlight"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("Pipeline0PointLight"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("Wimbzle"), true, false);
|
||||
generate_eve_span_company_for_primitive(l, ns, cstr("Nibzle"), true, false);
|
||||
/* r0_scene.h */
|
||||
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("UsedGenericModelOnScene"), true, false);
|
||||
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("UsedShinyModelOnScene"), true, false);
|
||||
}
|
||||
mkdir_nofail("l1/eve/r2");
|
||||
{ /* r2 */
|
||||
@ -19,10 +29,6 @@ void generate_headers_for_r0_r1_r2_r3() {
|
||||
.T = cstr("PlayingSound"), .vec_extended = true
|
||||
});
|
||||
}
|
||||
mkdir_nofail("l1/eve/ds_test");
|
||||
{ /* This structure is needed for testing purposes only */
|
||||
generate_eve_span_company_for_primitive(l, cstr("ds_test"), cstr("RefRBTreeNode_S64"), true, false);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -4,10 +4,29 @@
|
||||
#include "../codegen/util_template_inst.h"
|
||||
|
||||
void generate_util_temp_geom_headers() {
|
||||
SpanU8 T[] = {cstr("cvec3"), cstr("cvec4"), cstr("vec2"), cstr("vec3"), cstr("vec4")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
generate_guarded_span_company_for_primitive(cstr("l1"), cstr(""), T[i],
|
||||
cstr("#include \"geom.h\"\n"), true, true);
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_cvec.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"geom.h\"\n"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
|
||||
SpanU8 T[] = {cstr("cvec3"), cstr("cvec4")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
|
||||
.T = T[i], .t_primitive = true, .vec = true, .span = true, .collab_vec_span = true,
|
||||
}));
|
||||
}
|
||||
finish_header(head);
|
||||
}
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_vec.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"geom.h\"\n"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
|
||||
SpanU8 T[] = {cstr("vec2"), cstr("vec3"), cstr("vec4")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
|
||||
.T = T[i], .t_primitive = true, .vec = true, .span = true, .collab_vec_span = true,
|
||||
}));
|
||||
}
|
||||
finish_header(head);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,70 +3,61 @@
|
||||
|
||||
#include "../codegen/util_template_inst.h"
|
||||
|
||||
// todo: split VecAndSpan_int_primitives into multiple files (one file per integer type)
|
||||
|
||||
/* These headers are guarded */
|
||||
void generate_util_temp_very_base_headers() {
|
||||
SpanU8 l = cstr("l1"), ns = cstr("");
|
||||
SpanU8 T_codegen_VecAndSpan[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64")};
|
||||
SpanU8 T_codegen_Option[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")};
|
||||
SpanU8 T_codegen_VecAndSpan_of_Vec[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")};
|
||||
SpanU8 T_codegen_VecAndSpan_of_Span[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T_codegen_VecAndSpan); i++) {
|
||||
generate_util_templ_inst_guarded_header(l, ns,
|
||||
cstr(""),
|
||||
(util_templates_instantiation_options){
|
||||
.T = T_codegen_VecAndSpan[i],
|
||||
.t_integer = true, .t_primitive = true, .vec = true, .vec_extended = true,
|
||||
.vec_equal = true, .span = true, .span_extended = true, .mut_span = true,
|
||||
.collab_vec_span = true, .collab_vec_span_extended = true,
|
||||
});
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_int_primitives.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
|
||||
SpanU8 T[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
|
||||
.T = T[i],
|
||||
.t_integer = true, .t_primitive = true, .vec = true, .vec_extended = true,
|
||||
.vec_equal = true, .span = true, .span_extended = true, .mut_span = true,
|
||||
.collab_vec_span = true, .collab_vec_span_extended = true,
|
||||
}));
|
||||
}
|
||||
finish_header(head);
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T_codegen_Option); i++) {
|
||||
generate_Option_templ_inst_guarded_header(l, ns,
|
||||
cstr(""),
|
||||
(option_template_instantiation_op){.T = T_codegen_Option[i], .t_integer = true});
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/Option_int_primitives.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../src/l1/core/util.h\"\n\n"));
|
||||
SpanU8 T[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_OptionT_struct_and_methods((option_template_instantiation_op){
|
||||
.T = T[i], .t_integer = true, .t_primitive = true
|
||||
}));
|
||||
}
|
||||
finish_header(head);
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T_codegen_VecAndSpan_of_Vec); i++) {
|
||||
VecU8 VecT = VecU8_fmt("Vec%s", T_codegen_VecAndSpan_of_Vec[i]);
|
||||
VecU8 dependency = VecU8_fmt("#include \"VecAndSpan_%s.h\"", T_codegen_VecAndSpan_of_Vec[i]);
|
||||
generate_util_templ_inst_guarded_header(l, ns,
|
||||
VecU8_to_span(&dependency),
|
||||
(util_templates_instantiation_options){
|
||||
.T = VecU8_to_span(&VecT), .t_clonable = true, .vec = true, .vec_extended = true,
|
||||
.span = true, .collab_vec_span = true, .vec_equal = true, .vec_new_of_size = true
|
||||
});
|
||||
VecU8_drop(VecT);
|
||||
VecU8_drop(dependency);
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_Vec_int_primitives.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"VecAndSpan_int_primitives.h\"\n\n"));
|
||||
SpanU8 T[] = {cstr("VecU8"), cstr("VecU16"), cstr("VecU32"), cstr("VecU64")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
|
||||
.T = T[i], .t_clonable = true, .vec = true, .vec_extended = true,
|
||||
.span = true, .collab_vec_span = true, .vec_equal = true,
|
||||
}));
|
||||
}
|
||||
VecU8_append_vec(&head.result, generate_VecT_new_of_size_method(cstr("VecU8")));
|
||||
finish_header(head);
|
||||
}
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T_codegen_VecAndSpan_of_Span); i++) {
|
||||
VecU8 SpanT = VecU8_fmt("Span%s", T_codegen_VecAndSpan_of_Span[i]);
|
||||
VecU8 dependency = VecU8_fmt("#include \"VecAndSpan_%s.h\"", T_codegen_VecAndSpan_of_Span[i]);
|
||||
generate_util_templ_inst_guarded_header(l, ns,
|
||||
VecU8_to_span(&dependency),
|
||||
(util_templates_instantiation_options){
|
||||
.T = VecU8_to_span(&SpanT), .t_primitive = true, .vec = true, .span = true, .mut_span = true, .collab_vec_span = true,
|
||||
});
|
||||
VecU8_drop(SpanT);
|
||||
VecU8_drop(dependency);
|
||||
{
|
||||
GeneratedHeader head = begin_header(cstr("l1/VecAndSpan_Span_int_primitives.h"));
|
||||
VecU8_append_span(&head.result, cstr("#include \"VecAndSpan_int_primitives.h\"\n\n"));
|
||||
SpanU8 T[1] = {cstr("SpanU8")};
|
||||
for (size_t i = 0; i < ARRAY_SIZE(T); i++) {
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation((util_templates_instantiation_options){
|
||||
.T = T[i], .t_primitive = true, .vec = true, .span = true, .mut_span = true, .collab_vec_span = true,
|
||||
}));
|
||||
}
|
||||
finish_header(head);
|
||||
}
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("CSTR"), cstr(""), true, false);
|
||||
|
||||
generate_ResultType_templ_inst_guarded_header(l, ns,
|
||||
cstr(""), cstr("VecU8"), cstr("#include \"VecAndSpan_U8.h\""), true, false);
|
||||
generate_ResultType_templ_inst_guarded_header(l, ns,
|
||||
cstr(""), cstr("SpanU8"), cstr("#include \"VecAndSpan_U8.h\""), true, true);
|
||||
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("U32Segment"),
|
||||
cstr("#include \"../../src/l1/core/uint_segments.h\""), true, true);
|
||||
|
||||
/* Not very basic but definitely very common */
|
||||
generate_guarded_span_company_for_non_primitive_clonable(l, ns, cstr("TextureDataR8G8B8A8"),
|
||||
cstr("#include \"../../gen/l1/pixel_masses.h\"\n"), true, false);
|
||||
generate_guarded_span_company_for_non_primitive_clonable(l, ns, cstr("TextureDataR8G8B8"),
|
||||
cstr("#include \"../../gen/l1/pixel_masses.h\"\n"), true, false);
|
||||
generate_guarded_span_company_for_non_primitive_clonable(l, ns, cstr("TextureDataR8"),
|
||||
cstr("#include \"../../gen/l1/pixel_masses.h\"\n"), true, false);
|
||||
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("KVPU64ToU64"), cstr(""), true, false);
|
||||
generate_guarded_span_company_for_primitive(cstr("l1"), cstr(""),
|
||||
cstr("CSTR"), cstr(""), true, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -39,9 +39,8 @@ void generate_util_templ_inst_for_vulkan_headers() {
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkImageView"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkFramebuffer"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkSemaphore"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkDescriptorPoolSize"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkBufferCopy"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkImageMemoryBarrier"), vulkan_dep, true, false);
|
||||
generate_guarded_span_company_for_primitive(l, ns, cstr("VkDescriptorImageInfo"), vulkan_dep, true, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
typedef struct {
|
||||
VecU8 result;
|
||||
VecU8 filename;
|
||||
VecU8 nt_filename;
|
||||
} GeneratedHeader;
|
||||
|
||||
NODISCARD GeneratedHeader begin_header(SpanU8 filename) {
|
||||
@ -26,13 +26,14 @@ NODISCARD GeneratedHeader begin_header(SpanU8 filename) {
|
||||
VecU8_append_span(&res, cstr("\n#define "));
|
||||
VecU8_append_vec(&res, guard);
|
||||
VecU8_append_span(&res, cstr("\n/* Automatically generated file. Do not edit it. */\n\n"));
|
||||
return (GeneratedHeader){.result = res, .filename = VecU8_from_span(filename) };
|
||||
return (GeneratedHeader){.result = res, .nt_filename = VecU8_fmt("%s%c", filename, 0) };
|
||||
}
|
||||
|
||||
/* Codegen script's working directory should be `gen` */
|
||||
void finish_header(GeneratedHeader header) {
|
||||
VecU8_append_span(&header.result, cstr("#endif\n"));
|
||||
write_file_by_path(header.filename, VecU8_to_span(&header.result));
|
||||
write_whole_file_or_abort((const char*)header.nt_filename.buf, VecU8_to_span(&header.result));
|
||||
VecU8_drop(header.nt_filename);
|
||||
VecU8_drop(header.result);
|
||||
}
|
||||
|
||||
@ -42,7 +43,9 @@ void finish_header(GeneratedHeader header) {
|
||||
#define SPACE16 " "
|
||||
|
||||
void finish_layer(SpanU8 layer_name) {
|
||||
write_file_by_path(VecU8_fmt("%s/dorothy.txt", layer_name), cstr(""));
|
||||
VecU8 nt_name = VecU8_fmt("%s/dorothy.txt%c", layer_name, 0);
|
||||
write_whole_file_or_abort((const char*)nt_name.buf, cstr(""));
|
||||
VecU8_drop(nt_name);
|
||||
}
|
||||
|
||||
int get_number_of_parts_in_header_namespace(SpanU8 ns) {
|
||||
@ -82,38 +85,4 @@ NODISCARD VecU8 prepend_spaces_to_SpanU8_lines(SpanU8 lines, int tabulation){
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_SOME_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, VecU8 body, VecU8 name){
|
||||
VecU8 text = VecU8_fmt("/* Automatically generated file. Don't edit it.\n"
|
||||
"* Don't include it in more than one place */\n\n%v", body);
|
||||
write_file_by_path(VecU8_fmt("%s/eve/%s/%v.h", layer, bonus_ns, name), VecU8_to_span(&text));
|
||||
VecU8_drop(text);
|
||||
}
|
||||
|
||||
void generate_SOME_templ_inst_guarded_header(SpanU8 layer, SpanU8 bonus_ns, VecU8 all_dependencies, VecU8 body, VecU8 name){
|
||||
assert(layer.len > 1);
|
||||
VecU8 path = VecU8_fmt("%s/%s%s%v.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), name);
|
||||
GeneratedHeader head = begin_header(VecU8_to_span(&path));
|
||||
VecU8_drop(path);
|
||||
VecU8_append_vec(&head.result, all_dependencies);
|
||||
VecU8_append_span(&head.result, cstr("\n"));
|
||||
VecU8_append_vec(&head.result, body);
|
||||
finish_header(head);
|
||||
}
|
||||
|
||||
/* Assumed we are at some_layer/bonus_ns/header.h header */
|
||||
NODISCARD VecU8 codegen_include_relative_to_root(SpanU8 bonus_ns, SpanU8 abs_path){
|
||||
VecU8 res = vcstr("#include \"../../");
|
||||
int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns);
|
||||
for (int i = 0; i < to_my_layer; i++)
|
||||
VecU8_append_span(&res, cstr("../"));
|
||||
VecU8_append_span(&res, abs_path);
|
||||
VecU8_append_span(&res, cstr("\"\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
/* returns back `type` string, but if it is "", returns "void" instead */
|
||||
SpanU8 c_type_empty_means_void(SpanU8 type){
|
||||
return type.len > 0 ? type : cstr("void");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
#ifndef prototype1_src_l1_codegen_list_template_inst_h
|
||||
#define prototype1_src_l1_codegen_list_template_inst_h
|
||||
|
||||
#include "codegen.h"
|
||||
|
||||
typedef struct {
|
||||
SpanU8 T;
|
||||
bool t_primitive;
|
||||
bool t_clonable;
|
||||
} list_instantiation_op;
|
||||
|
||||
NODISCARD VecU8 generate_List_template_instantiation(list_instantiation_op op, bool gen_node_declaration){
|
||||
if (op.t_primitive)
|
||||
op.t_clonable = true;
|
||||
assert(op.T.len > 0);
|
||||
|
||||
VecU8 res = VecU8_new();
|
||||
if (gen_node_declaration) {
|
||||
VecU8_append_vec(&res, VecU8_fmt("typedef struct ListNode%s ListNode%s;\n", op.T, op.T));
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"struct ListNode%s {\n" /* op.T */
|
||||
SPACE "ListNode%s* prev;\n" /* op.T */
|
||||
SPACE "ListNode%s* next;\n" /* op.T */
|
||||
SPACE "%s el;\n" /* op.T */
|
||||
"};\n\n", op.T, op.T, op.T, op.T));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "ListNode%s* first;\n" /* op.T */
|
||||
"} List%s;\n\n", /* op.T */
|
||||
op.T, op.T));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"#define List%s_new() {0}\n\n" /* op.T */
|
||||
"void List%s_drop(List%s self) {\n" /* op.T, op.T */
|
||||
SPACE "ListNode%s* cur = self.first;\n" /* op.T */
|
||||
SPACE "while (cur){\n"
|
||||
SPACE SPACE "ListNode%s* next = cur->next;\n" /* op.T */
|
||||
"%v" /* "" / %s_drop(cur->el) */
|
||||
SPACE SPACE "free(cur);\n"
|
||||
SPACE SPACE "cur = next;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n",
|
||||
op.T, op.T, op.T, op.T, op.T,
|
||||
op.t_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE "%s_drop(cur->el);\n", op.T)));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"ListNode%s* List%s_insert(List%s* self, %s el) {\n" /* op.T, op.T, op.T, op.T */
|
||||
SPACE "ListNode%s* new_node = safe_malloc(sizeof(ListNode%s));\n" /* op.T, op.T */
|
||||
SPACE "new_node->prev = NULL;\n"
|
||||
SPACE "new_node->next = self->first;\n"
|
||||
SPACE "new_node->el = el;\n"
|
||||
SPACE "if (self->first)\n"
|
||||
SPACE SPACE "self->first->prev = new_node;\n"
|
||||
SPACE "self->first = new_node;\n"
|
||||
SPACE "return new_node;\n"
|
||||
"}\n\n", op.T, op.T, op.T, op.T, op.T, op.T));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void List%s_insert_node(List%s* self, ListNode%s* new_node) {\n" /* op.T, op.T, op.T */
|
||||
SPACE "new_node->prev = NULL;\n"
|
||||
SPACE "new_node->next = self->first;\n"
|
||||
SPACE "if (self->first)\n"
|
||||
SPACE SPACE "self->first->prev = new_node;\n"
|
||||
SPACE "self->first = new_node;\n"
|
||||
"}\n\n", op.T, op.T, op.T));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void List%s_erase_by_it(List%s* self, ListNode%s* it) {\n" /* op.T, op.T, op.T */
|
||||
SPACE "if (it->prev)\n"
|
||||
SPACE SPACE "it->prev->next = it->next;\n"
|
||||
SPACE "else\n"
|
||||
SPACE SPACE "self->first = it->next;\n"
|
||||
SPACE "if (it->next)\n"
|
||||
SPACE SPACE "it->next->prev = it->prev;\n"
|
||||
"%v" /* "" / %s_drop(it->el) */
|
||||
SPACE "free(it);\n"
|
||||
"}\n\n",
|
||||
op.T, op.T, op.T,
|
||||
op.t_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(it->el);\n", op.T)));
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void List%s_sink(List%s* self) {\n" /* op.T, op.T */
|
||||
SPACE "ListNode%s* cur = self->first;\n" /* op.T */
|
||||
SPACE "while (cur){\n"
|
||||
SPACE SPACE "ListNode%s* next = cur->next;\n" /* op.T */
|
||||
"%v" /* "" / %s_drop(cur->el) */
|
||||
SPACE SPACE "free(cur);\n"
|
||||
SPACE SPACE "cur = next;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "self->first = NULL;\n"
|
||||
"}\n\n",
|
||||
op.T, op.T, op.T, op.T,
|
||||
op.t_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE "%s_drop(cur->el);\n", op.T)));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void generate_List_templ_inst_eve_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, list_instantiation_op op, bool gen_node_declaration) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_List_template_instantiation(op, gen_node_declaration), VecU8_fmt("List%s", op.T));
|
||||
}
|
||||
|
||||
void generate_List_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, list_instantiation_op op
|
||||
){
|
||||
VecU8 all_dependencies = VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1/core/utils.h")), dependencies);
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies,
|
||||
generate_List_template_instantiation(op, true), VecU8_fmt("List%s", op.T));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@ -30,20 +30,20 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive,
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_reserved(size_t n) {\n"
|
||||
SPACE "return (%s){ .buf = (%s*)safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n"
|
||||
"}\n\n", VecT, VecT, VecT, T, T));
|
||||
SPACE "return (%s){ .buf = safe_calloc(n, sizeof(%s)), .len = 0, .capacity = n };\n"
|
||||
"}\n\n", VecT, VecT, VecT, T));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_append(%s* self, %s el) {\n" /* VecT, VecT, T */
|
||||
"void %s_append(%s* self, %s el) {\n"
|
||||
SPACE "size_t new_length = self->len + 1;\n"
|
||||
SPACE "if (new_length > self->capacity) {\n"
|
||||
SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n"
|
||||
SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */
|
||||
SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n"
|
||||
SPACE SPACE "self->capacity = new_capacity;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "self->buf[self->len] = el;\n"
|
||||
SPACE "self->len = new_length;\n"
|
||||
"}\n\n", VecT, VecT, T, T, T));
|
||||
"}\n\n", VecT, VecT, T, T));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s* %s_mat(%s* self, size_t i) {\n"
|
||||
@ -57,22 +57,11 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive,
|
||||
SPACE "return &self->buf[i];\n"
|
||||
"}\n\n", T, VecT, VecT));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_sink(%s* self, size_t new_len) {\n" /* VecT, VecT */
|
||||
SPACE "assert(new_len <= self->len);\n"
|
||||
"%v" /* dropping */
|
||||
SPACE "self->len = new_len;\n"
|
||||
"}\n\n", VecT, VecT,
|
||||
primitive ? vcstr("") : VecU8_fmt(
|
||||
SPACE "for (size_t i = new_len; i < self->len; i++)\n"
|
||||
SPACE SPACE "%s_drop(self->buf[i]);\n", /* T */
|
||||
T)));
|
||||
|
||||
if (clonable) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_clone(const %s* self) {\n" /* VecT, VecT, VecT */
|
||||
SPACE "%s res = (%s){.buf = (%s*)safe_calloc(self->len, sizeof(%s)), .len = self->len, .capacity = self->len};\n",
|
||||
VecT, VecT, VecT, VecT, VecT, T, T));
|
||||
"NODISCARD %s %s_clone(const %s* self) {\n"
|
||||
SPACE "%s res = (%s){.buf = safe_calloc(self->len, sizeof(%s)), .len = self->len, .capacity = self->len};\n",
|
||||
VecT, VecT, VecT, VecT, VecT, T));
|
||||
if (primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "memcpy(res.buf, self->buf, self->len * sizeof(%s));\n", T));
|
||||
} else {
|
||||
@ -84,11 +73,11 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive,
|
||||
}
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_append_vec(%s* self, %s b) {\n" /* VecT, VecT, VecT */
|
||||
"void %s_append_vec(%s* self, %s b) {\n"
|
||||
SPACE "size_t new_length = self->len + b.len;\n"
|
||||
SPACE "if (new_length > self->capacity) {\n"
|
||||
SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n"
|
||||
SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */
|
||||
SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n"
|
||||
SPACE SPACE "self->capacity = new_capacity;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "for (size_t i = 0; i < b.len; i++){\n"
|
||||
@ -96,14 +85,13 @@ NODISCARD VecU8 generate_VecT_struct_and_base_methods(SpanU8 T, bool primitive,
|
||||
SPACE "}\n"
|
||||
SPACE "self->len = new_length;\n"
|
||||
SPACE "free(b.buf);\n"
|
||||
"}\n\n", VecT, VecT, VecT, T, T));
|
||||
"}\n\n", VecT, VecT, VecT, T));
|
||||
|
||||
if (primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_zeroinit(size_t len) {\n" /* VecT, VecT*/
|
||||
SPACE "return (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, T, T */
|
||||
"}\n\n",
|
||||
VecT, VecT, VecT, T, T));
|
||||
"NODISCARD %s %s_new_zeroinit(size_t len) {\n"
|
||||
SPACE "return (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n"
|
||||
"}\n\n", VecT, VecT, VecT, T));
|
||||
}
|
||||
|
||||
VecU8_drop(g_VecT); // VecT invalidated too
|
||||
@ -160,20 +148,20 @@ NODISCARD VecU8 generate_VecT_trivmove_extended_methods(SpanU8 T, bool primitive
|
||||
|
||||
if (primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_filled(size_t len, %s el) {\n" /* VecT, VecT, T */
|
||||
SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */
|
||||
"NODISCARD %s %s_new_filled(size_t len, %s el) {\n"
|
||||
SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n"
|
||||
SPACE "for (size_t i = 0; i < len; i++)\n"
|
||||
SPACE SPACE "res.buf[i] = el;\n"
|
||||
SPACE "return res;\n"
|
||||
"}\n\n", VecT, VecT, T, VecT, VecT, T, T));
|
||||
"}\n\n", VecT, VecT, T, VecT, VecT, T));
|
||||
} else if (clonable) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_filled(size_t len, const %s* el) {\n" /* VecT, VecT, T */
|
||||
SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */
|
||||
"NODISCARD %s %s_new_filled(size_t len, const %s* el) {\n"
|
||||
SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n"
|
||||
SPACE "for (size_t i = 0; i < len; i++)\n"
|
||||
SPACE SPACE "res.buf[i] = %s_clone(el);\n" /* T */
|
||||
SPACE SPACE "res.buf[i] = %s_clone(el);\n"
|
||||
SPACE "return res;\n"
|
||||
"}\n\n", VecT, VecT, T, VecT, VecT, T, T, T));
|
||||
"}\n\n", VecT, VecT, T, VecT, VecT, T, T));
|
||||
}
|
||||
|
||||
VecU8_drop(g_VecT); // VecT invalidated
|
||||
@ -210,12 +198,12 @@ NODISCARD VecU8 generate_VecT_new_of_size_method(SpanU8 T) {
|
||||
VecU8 g_VecT = VecU8_fmt("Vec%s", T);
|
||||
SpanU8 VecT = VecU8_to_span(&g_VecT);
|
||||
VecU8 res = VecU8_fmt(
|
||||
"NODISCARD %s %s_new_of_size(size_t len) {\n" /* VecT, VecT */
|
||||
SPACE "%s res = (%s){.buf = (%s*)safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n" /* VecT, VecT, T, T */
|
||||
"NODISCARD %s %s_new_of_size(size_t len) {\n"
|
||||
SPACE "%s res = (%s){.buf = safe_calloc(len, sizeof(%s)), .len = len, .capacity = len};\n"
|
||||
SPACE "for (size_t i = 0; i < len; i++)\n"
|
||||
SPACE SPACE "res.buf[i] = %s_new();\n" /* T */
|
||||
SPACE SPACE "res.buf[i] = %s_new();\n"
|
||||
SPACE "return res;\n"
|
||||
"}\n", VecT, VecT, VecT, VecT, T, T, T);
|
||||
"}\n", VecT, VecT, VecT, VecT, T, T);
|
||||
|
||||
VecU8_drop(g_VecT);
|
||||
return res;
|
||||
@ -260,9 +248,9 @@ void codegen_append_some_span_span_method(VecU8* res, SpanU8 SpanT) {
|
||||
/* T must be sized. Option `add_sort` requires option `add_mutable` and method T_less
|
||||
* add_mutable option generates MutSpanT.
|
||||
* add_equal option generates equal method. add_extended option generated extended methods
|
||||
*/
|
||||
* add_sort option generates T_qcompare and MutSpanT_sort methods */
|
||||
NODISCARD VecU8 generate_SpanT_struct_and_methods(
|
||||
SpanU8 T, bool integer, bool add_mutable, bool add_equal, bool add_extended
|
||||
SpanU8 T, bool integer, bool add_mutable, bool add_equal, bool add_extended, bool add_sort
|
||||
) {
|
||||
VecU8 g_SpanT = VecU8_fmt("Span%s", T);
|
||||
VecU8 g_MutSpanT = VecU8_fmt("MutSpan%s", T);
|
||||
@ -293,38 +281,31 @@ NODISCARD VecU8 generate_SpanT_struct_and_methods(
|
||||
codegen_append_some_span_span_method(&res, MutSpanT);
|
||||
}
|
||||
|
||||
if (add_sort) {
|
||||
assert(add_mutable);
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"int %s_qcompare(const void* a, const void* b) {\n"
|
||||
SPACE "const %s* A = a;\n"
|
||||
SPACE "const %s* B = b;\n", T, T, T));
|
||||
if (integer) {
|
||||
VecU8_append_span(&res, cstr(SPACE "return (int)(B < A) - (int)(A < B);\n"));
|
||||
} else {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "return (int)%s_less_%s(B, A) - (int)%s_less_%s(A, B);\n", T, T, T, T));
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"}\n\n"
|
||||
"void %s_sort(%s self) {\n"
|
||||
SPACE "qsort(self.data, self.len, sizeof(%s), %s_qcompare);\n"
|
||||
"}\n\n", MutSpanT, MutSpanT, T, T));
|
||||
}
|
||||
|
||||
VecU8_drop(g_MutSpanT);
|
||||
VecU8_drop(g_SpanT);
|
||||
return res;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_span_company_sort_methods(SpanU8 T, bool t_integer, bool mut_span, bool vec){
|
||||
VecU8 res = VecU8_new();
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"int %s_qcompare(const void* a, const void* b) {\n" /* T */
|
||||
SPACE "const %s* A = a;\n" /* T */
|
||||
SPACE "const %s* B = b;\n" /* T */
|
||||
SPACE "return %v;\n" /* we return stuff */
|
||||
"}\n\n",
|
||||
T, T, T, t_integer ? vcstr("(int)(*B < *A) - (int)(*A < *B)") :
|
||||
VecU8_fmt("(int)%s_less_%s(B, A) - (int)%s_less_%s(A, B)", T, T, T, T)));
|
||||
|
||||
if (mut_span) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void MutSpan%s_sort(MutSpan%s self) {\n"
|
||||
SPACE "qsort(self.data, self.len, sizeof(%s), %s_qcompare);\n"
|
||||
"}\n\n", T, T, T, T));
|
||||
}
|
||||
if (vec) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void Vec%s_sort(Vec%s* self) {\n"
|
||||
SPACE "qsort(self->buf, self->len, sizeof(%s), %s_qcompare);\n"
|
||||
"}\n\n", T, T, T, T));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
// void codegen_append_vec_some_span_method(VecU8* res, SpanU8 mod, SpanU8 )
|
||||
|
||||
/* T must be trivially movable. If !primitive, requires methods T_drop (implicitly) and, if clonable, requires T_clone */
|
||||
NODISCARD VecU8 generate_SpanT_VecT_trivmove_collab(SpanU8 T, bool primitive, bool clonable, bool add_mutable, bool add_extended) {
|
||||
@ -338,9 +319,9 @@ NODISCARD VecU8 generate_SpanT_VecT_trivmove_collab(SpanU8 T, bool primitive, bo
|
||||
|
||||
if (clonable) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_from_span(%s src){\n" /* VecT, VecT, SpanT */
|
||||
SPACE "%s res = (%s){ .buf = (%s*)safe_calloc(src.len, sizeof(%s)), .len = src.len, .capacity = src.len };\n", /* VecT, VecT, T, T */
|
||||
VecT, VecT, SpanT, VecT, VecT, T, T));
|
||||
"NODISCARD %s %s_from_span(%s src){\n"
|
||||
SPACE "%s res = (%s){ .buf = safe_calloc(src.len, sizeof(%s)), .len = src.len, .capacity = src.len };\n",
|
||||
VecT, VecT, SpanT, VecT, VecT, T));
|
||||
if (primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "memcpy(res.buf, src.data, src.len * sizeof(%s));\n", T));
|
||||
@ -365,13 +346,13 @@ NODISCARD VecU8 generate_SpanT_VecT_trivmove_collab(SpanU8 T, bool primitive, bo
|
||||
|
||||
if (clonable) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_append_span(%s* self, %s b) {\n" /* VecT, VecT, SpanT */
|
||||
"void %s_append_span(%s* self, %s b) {\n"
|
||||
SPACE "size_t new_length = self->len + b.len;\n"
|
||||
SPACE "if (new_length > self->capacity) {\n"
|
||||
SPACE SPACE "size_t new_capacity = Vec_get_new_capacity(self->capacity, new_length);\n"
|
||||
SPACE SPACE "self->buf = (%s*)safe_realloc(self->buf, new_capacity * sizeof(%s));\n" /* T, T */
|
||||
SPACE SPACE "self->buf = safe_realloc(self->buf, new_capacity * sizeof(%s));\n"
|
||||
SPACE SPACE "self->capacity = new_capacity;\n"
|
||||
SPACE "}\n", VecT, VecT, SpanT, T, T));
|
||||
SPACE "}\n", VecT, VecT, SpanT, T));
|
||||
if (primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "memcpy(self->buf + self->len, b.data, b.len * sizeof(%s));\n", T));
|
||||
@ -423,7 +404,7 @@ typedef struct {
|
||||
bool span;
|
||||
bool mut_span;
|
||||
bool span_extended;
|
||||
bool sort;
|
||||
bool span_sort;
|
||||
bool collab_vec_span;
|
||||
bool collab_vec_span_extended;
|
||||
} util_templates_instantiation_options;
|
||||
@ -440,6 +421,8 @@ void util_templates_instantiation_options_fix(util_templates_instantiation_optio
|
||||
op->vec = true;
|
||||
if (op->span_extended)
|
||||
op->span = true;
|
||||
if (op->span_sort)
|
||||
op->span = true;
|
||||
if (op->mut_span)
|
||||
op->span = true;
|
||||
if (op->collab_vec_span_extended)
|
||||
@ -472,10 +455,7 @@ NODISCARD VecU8 generate_util_templates_instantiation(util_templates_instantiati
|
||||
VecU8_append_vec(&res, generate_VecT_new_of_size_method(op.T));
|
||||
}
|
||||
if (op.span) {
|
||||
VecU8_append_vec(&res, generate_SpanT_struct_and_methods(op.T, op.t_integer, op.mut_span, false, op.span_extended));
|
||||
}
|
||||
if (op.sort) {
|
||||
VecU8_append_vec(&res, generate_span_company_sort_methods(op.T, op.t_integer, op.mut_span, op.vec));
|
||||
VecU8_append_vec(&res, generate_SpanT_struct_and_methods(op.T, op.t_integer, op.mut_span, false, op.span_extended, op.span_sort));
|
||||
}
|
||||
if (op.collab_vec_span) {
|
||||
assert(op.vec && op.span);
|
||||
@ -486,14 +466,21 @@ NODISCARD VecU8 generate_util_templates_instantiation(util_templates_instantiati
|
||||
|
||||
NODISCARD VecU8 util_templates_instantiation_get_appropriate_filename(util_templates_instantiation_options op) {
|
||||
util_templates_instantiation_options_fix(&op);
|
||||
return VecU8_fmt("%s%s%s""%s%s",
|
||||
return VecU8_fmt("%s%s%s""%s%s.h",
|
||||
op.vec ? cstr("Vec") : cstr(""), op.vec && op.span ? cstr("And") : cstr(""), op.span ? cstr("Span") : cstr(""),
|
||||
(int)op.vec + (int)op.span > 1 ? cstr("_") : cstr(""), op.T);
|
||||
}
|
||||
|
||||
void generate_util_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, util_templates_instantiation_options op) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_util_templates_instantiation(op),
|
||||
util_templates_instantiation_get_appropriate_filename(op));
|
||||
VecU8 text = VecU8_from_cstr("/* Automatically generated file. Do not edit it.\n"
|
||||
" * Do not include it in more than one place */\n\n");
|
||||
VecU8_append_vec(&text, generate_util_templates_instantiation(op));
|
||||
VecU8 filename = util_templates_instantiation_get_appropriate_filename(op);
|
||||
// todo: add %v that takes a vector
|
||||
VecU8 nt_path = VecU8_fmt("%s/eve/%s/%v%c", layer, bonus_ns, filename, 0);
|
||||
write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text));
|
||||
VecU8_drop(nt_path);
|
||||
VecU8_drop(text);
|
||||
}
|
||||
|
||||
void generate_eve_span_company_for_primitive(SpanU8 layer, SpanU8 ns, SpanU8 T, bool with_vector, bool with_span) {
|
||||
@ -520,9 +507,21 @@ void generate_eve_span_company_for_non_primitive_non_clonable(SpanU8 layer, Span
|
||||
void generate_util_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, util_templates_instantiation_options op
|
||||
) {
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1/core/util.h")), dependencies),
|
||||
generate_util_templates_instantiation(op), util_templates_instantiation_get_appropriate_filename(op));
|
||||
assert(layer.len > 1);
|
||||
VecU8 filename = util_templates_instantiation_get_appropriate_filename(op);
|
||||
VecU8 path = VecU8_fmt("%s/%s%s%s", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), VecU8_to_span(&filename));
|
||||
GeneratedHeader head = begin_header(VecU8_to_span(&path));
|
||||
VecU8_drop(path);
|
||||
VecU8_drop(filename);
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../"));
|
||||
int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns);
|
||||
for (int i = 0; i < to_my_layer; i++)
|
||||
VecU8_append_span(&head.result, cstr("../"));
|
||||
VecU8_append_span(&head.result, cstr("src/l1/core/util.h\"\n"));
|
||||
VecU8_append_span(&head.result, dependencies);
|
||||
VecU8_append_span(&head.result, cstr("\n\n"));
|
||||
VecU8_append_vec(&head.result, generate_util_templates_instantiation(op));
|
||||
finish_header(head);
|
||||
}
|
||||
|
||||
void generate_guarded_span_company_for_primitive(
|
||||
@ -552,82 +551,6 @@ void generate_guarded_span_company_for_non_primitive_non_clonable(
|
||||
});
|
||||
}
|
||||
|
||||
NODISCARD VecU8 get_ResultType_inst_name(SpanU8 OkT, SpanU8 ErrT){
|
||||
bool ok_t_void = OkT.len == 0;
|
||||
bool err_t_void = ErrT.len == 0;
|
||||
assert(!ok_t_void || !err_t_void);
|
||||
return VecU8_fmt("Result%s%s%s", !ok_t_void ? OkT : cstr("Void"),
|
||||
!err_t_void ? cstr("Or") : cstr(""), !err_t_void ? ErrT : cstr(""));
|
||||
}
|
||||
|
||||
/* We are talking about Result<OkT, ErrT> template instantiation */
|
||||
NODISCARD VecU8 generate_result_template_inst(SpanU8 OkT, SpanU8 ErrT, bool ok_t_primitive, bool err_t_primitive) {
|
||||
bool ok_t_void = OkT.len == 0;
|
||||
bool err_t_void = ErrT.len == 0;
|
||||
assert(!ok_t_void || !err_t_void);
|
||||
assert(!ok_t_void || ok_t_primitive);
|
||||
assert(!err_t_void || err_t_primitive);
|
||||
|
||||
VecU8 g_ResultT = get_ResultType_inst_name(OkT, ErrT);
|
||||
SpanU8 ResultT = VecU8_to_span(&g_ResultT);
|
||||
|
||||
VecU8 res = VecU8_new();
|
||||
|
||||
VecU8_append_span(&res, cstr(
|
||||
"typedef struct {\n"
|
||||
SPACE "Result_variant variant;\n"));
|
||||
if (ok_t_void && !err_t_void) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s err;\n", ErrT));
|
||||
} else if (!ok_t_void && err_t_void) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s ok;\n", OkT));
|
||||
} else {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "union {\n"
|
||||
SPACE SPACE "%s ok;\n"
|
||||
SPACE SPACE "%s err;\n"
|
||||
SPACE "};\n", OkT, ErrT));
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", ResultT));
|
||||
|
||||
if (!ok_t_primitive || !err_t_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_drop(%s self) {\n", ResultT, ResultT));
|
||||
if (ok_t_primitive && !err_t_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "if (self.variant == Result_Err)\n"
|
||||
SPACE SPACE "%s_drop(self.err);\n", ErrT));
|
||||
} else if (!ok_t_primitive && err_t_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "if (self.variant == Result_Ok)\n"
|
||||
SPACE SPACE "%s_drop(self.ok);\n", OkT));
|
||||
} else {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "if (self.variant == Result_Ok)\n"
|
||||
SPACE SPACE "%s_drop(self.ok);\n"
|
||||
SPACE "else\n"
|
||||
SPACE SPACE "%s_drop(self.err);\n", OkT, ErrT));
|
||||
}
|
||||
VecU8_append_span(&res, cstr("}\n\n"));
|
||||
}
|
||||
VecU8_drop(g_ResultT); /* ResultT variable invalidated */
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_ResultType_templ_inst_eve_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 OkT, SpanU8 ErrT, bool ok_t_primitive, bool err_t_primitive
|
||||
) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_result_template_inst(OkT, ErrT, ok_t_primitive, err_t_primitive), get_ResultType_inst_name(OkT, ErrT));
|
||||
}
|
||||
|
||||
void generate_ResultType_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 OkT, SpanU8 ErrT, SpanU8 dependencies, bool ok_t_primitive, bool err_t_primitive
|
||||
){
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1/core/util.h")), dependencies),
|
||||
generate_result_template_inst(OkT, ErrT, ok_t_primitive, err_t_primitive), get_ResultType_inst_name(OkT, ErrT));
|
||||
}
|
||||
|
||||
typedef struct{
|
||||
SpanU8 T;
|
||||
bool t_ptr;
|
||||
@ -698,16 +621,31 @@ NODISCARD VecU8 generate_OptionT_struct_and_methods(option_template_instantiatio
|
||||
}
|
||||
|
||||
void generate_Option_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, option_template_instantiation_op op) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_OptionT_struct_and_methods(op),
|
||||
VecU8_fmt("Option%s", op.T));
|
||||
VecU8 text = VecU8_from_cstr("/* Automatically generated file. Do not edit it.\n"
|
||||
" * Do not include it in more than one place */\n\n");
|
||||
VecU8_append_vec(&text, generate_OptionT_struct_and_methods(op));
|
||||
VecU8 nt_path = VecU8_fmt("%s/eve/%s/Option%s%c", layer, bonus_ns, op.T, 0);
|
||||
write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text));
|
||||
VecU8_drop(nt_path);
|
||||
VecU8_drop(text);
|
||||
}
|
||||
|
||||
void generate_Option_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, option_template_instantiation_op op
|
||||
) {
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1/core/util.h")), dependencies),
|
||||
generate_OptionT_struct_and_methods(op), VecU8_fmt("Option%s", op.T));
|
||||
assert(layer.len > 1);
|
||||
VecU8 path = VecU8_fmt("%s/%s%sOption%s.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), op.T);
|
||||
GeneratedHeader head = begin_header(VecU8_to_span(&path));
|
||||
VecU8_drop(path);
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../"));
|
||||
int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns);
|
||||
for (int i = 0; i < to_my_layer; i++)
|
||||
VecU8_append_span(&head.result, cstr("../"));
|
||||
VecU8_append_span(&head.result, cstr("src/l1/core/util.h\"\n"));
|
||||
VecU8_append_span(&head.result, dependencies);
|
||||
VecU8_append_span(&head.result, cstr("\n\n"));
|
||||
VecU8_append_vec(&head.result, generate_OptionT_struct_and_methods(op));
|
||||
finish_header(head);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#ifdef PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8
|
||||
#include "chicken_VecU8.h"
|
||||
#else
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
#include "../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
#endif
|
||||
|
||||
VecU8 VecU8_from_cstr(const char* dc) {
|
||||
@ -135,12 +135,7 @@ void U64_stringification_into_buf(U64 x, VecU8* targ){
|
||||
}
|
||||
}
|
||||
|
||||
/* %s - SpanU8
|
||||
* %v - VecU8
|
||||
* %u - U64
|
||||
* %c - int (one byte character)
|
||||
* %i - S64
|
||||
*/
|
||||
// todo: add %d (when I figure out how to do it)
|
||||
NODISCARD VecU8 VecU8_fmt(const char* fmt, ...) {
|
||||
assert(fmt);
|
||||
size_t k = 0;
|
||||
@ -209,7 +204,7 @@ NODISCARD VecU8 VecU8_fmt(const char* fmt, ...) {
|
||||
}
|
||||
|
||||
// todo: generate a special span method to check equality of contents
|
||||
bool SpanU8_cont_equal(SpanU8 a, SpanU8 b) {
|
||||
bool strings_in_spans_equal(SpanU8 a, SpanU8 b) {
|
||||
if (a.len != b.len)
|
||||
return false;
|
||||
for (size_t i = 0; i < a.len; i++) {
|
||||
@ -219,45 +214,5 @@ bool SpanU8_cont_equal(SpanU8 a, SpanU8 b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 0 means error */
|
||||
U32 SpanU8_decode_as_utf8(SpanU8* rem){
|
||||
assert(rem->len > 0);
|
||||
U8 first = rem->data[0];
|
||||
rem->data++;
|
||||
rem->len--;
|
||||
if (!(first & 0b10000000))
|
||||
return first;
|
||||
uint8_t a = 0b11000000;
|
||||
uint8_t b = 0b00100000;
|
||||
for (int sz = 1; sz <= 3; sz++){
|
||||
if ((first & (a | b)) == a) {
|
||||
/* sz is the character size in bytes */
|
||||
if (rem->len < (size_t)sz)
|
||||
return 0;
|
||||
U32 res = first & (b - 1);
|
||||
for (int i = 1; i <= sz; i++) {
|
||||
U8 th = rem->data[0];
|
||||
if ((th & 0b11000000) != 0b10000000)
|
||||
return 0;
|
||||
res <<= 6;
|
||||
res |= (th & 0b00111111);
|
||||
rem->data++;
|
||||
}
|
||||
rem->len -= sz;
|
||||
return res;
|
||||
}
|
||||
a |= b;
|
||||
b >>= 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SpanU8_is_prefix(SpanU8 a, SpanU8 str){
|
||||
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, 0, a.len));
|
||||
}
|
||||
|
||||
bool SpanU8_is_postfix(SpanU8 a, SpanU8 str){
|
||||
return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, str.len - a.len, a.len));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef uint8_t U8;
|
||||
typedef uint16_t U16;
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
#ifndef prototype1_src_l1_core_uint_segments_h
|
||||
#define prototype1_src_l1_core_uint_segments_h
|
||||
|
||||
#include "int_primitives.h"
|
||||
|
||||
typedef struct {
|
||||
U64 start;
|
||||
U64 len;
|
||||
} U64Segment;
|
||||
|
||||
typedef struct{
|
||||
U32 start;
|
||||
U32 len;
|
||||
} U32Segment;
|
||||
|
||||
#endif
|
||||
@ -2,6 +2,7 @@
|
||||
#define PROTOTYPE1_SRC_CORE_UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
@ -10,9 +11,9 @@
|
||||
#include <inttypes.h>
|
||||
#include "int_primitives.h"
|
||||
|
||||
// Gonna change it
|
||||
#define NORETURN __attribute((noreturn))
|
||||
#define NODISCARD __attribute((warn_unused_result))
|
||||
// Gonna change it when I face pedantic compilers
|
||||
#define NORETURN [[noreturn]]
|
||||
#define NODISCARD [[nodiscard]]
|
||||
|
||||
typedef const char* CSTR;
|
||||
|
||||
@ -54,6 +55,16 @@ void* safe_realloc(void* ptr, size_t n) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// todo: rewrite it to make it faster
|
||||
#define unsigned_safe_mul_Definition(TSZ) \
|
||||
U##TSZ safe_mul_U##TSZ(U##TSZ a, U##TSZ b) { \
|
||||
if (b > 0 && a > UINT##TSZ##_MAX / b) \
|
||||
abortf("Overflow in multiplication: %" PRIu##TSZ " * %" PRIu##TSZ "\n", a, b); \
|
||||
return a * b; \
|
||||
}
|
||||
|
||||
unsigned_safe_mul_Definition(64)
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
/* I assume that new_length > old_capacity */
|
||||
@ -69,29 +80,11 @@ float pow2f(float x) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
bool U64_is_2pow(U64 n){
|
||||
return n > 0 && ((n & (n - 1)) == 0);
|
||||
}
|
||||
|
||||
U8 U64_2pow_log(U64 n){
|
||||
U8 log = 0;
|
||||
while (n > 1){
|
||||
n >>= 1;
|
||||
log++;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
U32 width;
|
||||
U32 height;
|
||||
} SizeOfRectangleU32;
|
||||
|
||||
typedef struct{
|
||||
U64 key;
|
||||
U64 value;
|
||||
} KVPU64ToU64;
|
||||
|
||||
#define check(expr) if (!(expr)) { abortf("Assertion failed at %s : %d : " #expr "\n", __FILE__, __LINE__); }
|
||||
|
||||
#endif
|
||||
|
||||
@ -54,13 +54,6 @@ typedef struct {
|
||||
vec2 v2;
|
||||
} MarieTriangle;
|
||||
|
||||
MarieTriangle MarieTriangle_mat3x2_mul_pos(MarieTriangle self, mat3x2 trop) {
|
||||
return (MarieTriangle){
|
||||
.v0 = mat3x2_mul_vec3(trop, vec2_and_one(self.v0)),
|
||||
.v1 = mat3x2_mul_vec3(trop, vec2_and_one(self.v1)),
|
||||
.v2 = mat3x2_mul_vec3(trop, vec2_and_one(self.v2))};
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/marie/VecMarieTriangle.h"
|
||||
|
||||
typedef struct {
|
||||
@ -69,14 +62,6 @@ typedef struct {
|
||||
MariePlaneVertAttr v2;
|
||||
} MarieTriangleAttr;
|
||||
|
||||
MarieTriangleAttr MarieTriangle_goto_nat_cords_pres_par(MarieTriangle self, mat3x2 trop) {
|
||||
return (MarieTriangleAttr){
|
||||
{mat3x2_mul_vec3(trop, vec2_and_one(self.v0)), {self.v0.x, self.v0.y, 0, 0}},
|
||||
{mat3x2_mul_vec3(trop, vec2_and_one(self.v1)), {self.v1.x, self.v1.y, 0, 0}},
|
||||
{mat3x2_mul_vec3(trop, vec2_and_one(self.v2)), {self.v2.x, self.v2.y, 0, 0}},
|
||||
};
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/marie/VecMarieTriangleAttr.h"
|
||||
|
||||
vec2 marie_intersect_lines(vec2 A1, vec2 B1, vec2 A2, vec2 B2) {
|
||||
|
||||
@ -1,282 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from argparse import ArgumentParser
|
||||
from typing import List, Tuple, Set
|
||||
from dataclasses import dataclass
|
||||
|
||||
token_type_if = 0
|
||||
token_type_elif = 1
|
||||
token_type_ifdef = 2
|
||||
token_type_elifdef = 3
|
||||
token_type_ifndef = 4
|
||||
token_type_elifndef = 5
|
||||
token_type_else = 6
|
||||
token_type_endif = 7
|
||||
token_type_regular = 8
|
||||
token_type_include_local = 9
|
||||
token_type_define = 10
|
||||
|
||||
@dataclass
|
||||
class LineToken:
|
||||
type: int = 5
|
||||
symbol: str = ""
|
||||
filepath: str = ""
|
||||
original: str = ""
|
||||
|
||||
@dataclass
|
||||
class IfDirBlock:
|
||||
new_symbol_set: Set[str]
|
||||
text: str = ""
|
||||
|
||||
@dataclass
|
||||
class IfDirCondAndBlock:
|
||||
cond: LineToken
|
||||
inside: IfDirBlock
|
||||
|
||||
class ParserObj:
|
||||
s: str
|
||||
index = 0
|
||||
|
||||
def __init__(self, _s):
|
||||
self.s = _s
|
||||
|
||||
def skip_whitespace(self):
|
||||
while self.index < len(self.s) and self.s[self.index].isspace():
|
||||
self.index += 1
|
||||
|
||||
def skip_word(self):
|
||||
while self.index < len(self.s) and (self.s[self.index].isalnum() or self.s[self.index] == '_'):
|
||||
self.index += 1
|
||||
|
||||
def parse_first_word(s):
|
||||
p = ParserObj(s)
|
||||
length = len(s)
|
||||
p.skip_whitespace()
|
||||
if p.index >= length or s[p.index] != '#':
|
||||
return ""
|
||||
p.index += 1
|
||||
|
||||
start = p.index
|
||||
p.skip_word()
|
||||
return s[start:p.index]
|
||||
|
||||
|
||||
def parse_second_symbol(s):
|
||||
p = ParserObj(s)
|
||||
length = len(s)
|
||||
|
||||
p.skip_whitespace()
|
||||
if p.index >= length or s[p.index] != '#':
|
||||
raise RuntimeError("How????")
|
||||
p.index += 1 # Skip the '#'
|
||||
|
||||
p.skip_word()
|
||||
p.skip_whitespace()
|
||||
|
||||
start = p.index
|
||||
p.skip_word()
|
||||
|
||||
if start == p.index:
|
||||
raise ValueError("This is just chucking disappointing")
|
||||
return s[start:p.index]
|
||||
|
||||
|
||||
def parse_second_quoted_path(s):
|
||||
p = ParserObj(s)
|
||||
length = len(s)
|
||||
|
||||
p.skip_whitespace()
|
||||
if p.index >= length or s[p.index] != '#':
|
||||
return None
|
||||
p.index += 1
|
||||
|
||||
p.skip_word()
|
||||
p.skip_whitespace()
|
||||
|
||||
if p.index >= length or s[p.index] != '"':
|
||||
return None
|
||||
p.index += 1
|
||||
|
||||
start = p.index
|
||||
|
||||
# Find the closing quote
|
||||
while p.index < length and s[p.index] != '"':
|
||||
p.index += 1
|
||||
|
||||
if p.index >= length:
|
||||
return None
|
||||
|
||||
return s[start:p.index]
|
||||
|
||||
def analyze_file(lines_dirty, alien_headers: Set[str]) -> List[LineToken]:
|
||||
lines = list(map(lambda x: x.rstrip(), lines_dirty))
|
||||
i = 0
|
||||
tokens = []
|
||||
while i < len(lines):
|
||||
original_lines = ""
|
||||
line = ""
|
||||
while True:
|
||||
original_lines = original_lines + lines[i] + "\n"
|
||||
partial_line = lines[i]
|
||||
i += 1 # i variable should not be used or changed in the rest of the cycle
|
||||
if partial_line.endswith("\\"):
|
||||
partial_line = partial_line[:-1]
|
||||
line += partial_line
|
||||
else:
|
||||
line += partial_line
|
||||
break
|
||||
|
||||
directive = parse_first_word(line)
|
||||
|
||||
if directive == 'include':
|
||||
local_file = parse_second_quoted_path(line)
|
||||
if (local_file is not None) and (local_file not in alien_headers):
|
||||
tokens.append(LineToken(type = token_type_include_local, filepath=local_file,
|
||||
original=original_lines))
|
||||
else:
|
||||
tokens.append(LineToken(type = token_type_regular, original=original_lines))
|
||||
elif directive == 'define':
|
||||
symbol = parse_second_symbol(line)
|
||||
tokens.append(LineToken(type=token_type_define, symbol=symbol, original=original_lines))
|
||||
elif directive == 'ifdef':
|
||||
symbol = parse_second_symbol(line)
|
||||
tokens.append(LineToken(type=token_type_ifdef, symbol=symbol, original=original_lines))
|
||||
elif directive == 'ifndef':
|
||||
symbol = parse_second_symbol(line)
|
||||
tokens.append(LineToken(type=token_type_ifndef, symbol=symbol, original=original_lines))
|
||||
elif directive == 'elifdef':
|
||||
symbol = parse_second_symbol(line)
|
||||
tokens.append(LineToken(type=token_type_elifdef, symbol=symbol, original=original_lines))
|
||||
elif directive == 'elifndef':
|
||||
symbol = parse_second_symbol(line)
|
||||
tokens.append(LineToken(type=token_type_elifndef, symbol=symbol, original=original_lines))
|
||||
elif directive == 'else':
|
||||
tokens.append(LineToken(type=token_type_else, original=original_lines))
|
||||
elif directive == 'endif':
|
||||
tokens.append(LineToken(type=token_type_endif, original=original_lines))
|
||||
elif directive == 'if':
|
||||
tokens.append(LineToken(type=token_type_if, original=original_lines))
|
||||
elif directive == 'elif':
|
||||
tokens.append(LineToken(type=token_type_elif, original=original_lines))
|
||||
else:
|
||||
tokens.append(LineToken(type=token_type_regular, original=original_lines))
|
||||
return tokens
|
||||
|
||||
|
||||
# Returns new_i, block (text + new_symbol_set)
|
||||
def process_part_of_file(tokens: List[LineToken], defined_symbols_outside: Set[str], i: int, input_dir,
|
||||
take_seriously: bool, alien_headers: Set[str]) -> Tuple[int, IfDirBlock]:
|
||||
output = ""
|
||||
symbols_here = defined_symbols_outside.copy()
|
||||
|
||||
in_if: List[IfDirCondAndBlock] = []
|
||||
saw_unevaluatable_condition = False
|
||||
saw_else = False
|
||||
saw_match = -1
|
||||
|
||||
while i < len(tokens):
|
||||
token = tokens[i]
|
||||
t = token.type
|
||||
i += 1
|
||||
|
||||
if in_if and (t == token_type_if or t == token_type_ifdef or t == token_type_ifndef or
|
||||
t == token_type_include_local or t == token_type_define or
|
||||
t == token_type_regular):
|
||||
raise ValueError("Okay, listen here, you little chuck")
|
||||
|
||||
# When saw_else is true, we are definitely in_if
|
||||
if saw_else and t != token_type_endif:
|
||||
raise ValueError("Skill issue lol")
|
||||
|
||||
if not in_if and t in [token_type_elif, token_type_elifdef, token_type_elifndef,
|
||||
token_type_endif, token_type_else]:
|
||||
i -= 1
|
||||
break
|
||||
|
||||
if t == token_type_if or t == token_type_elif:
|
||||
saw_unevaluatable_condition = True
|
||||
|
||||
# If saw_unevaluatable_condition, nobody cares if we saw_match
|
||||
if saw_match == -1:
|
||||
if (t == token_type_ifdef or t == token_type_elifdef) and (token.symbol in symbols_here):
|
||||
saw_match = len(in_if)
|
||||
if (t == token_type_ifndef or t == token_type_elifndef) and (token.symbol not in symbols_here):
|
||||
saw_match = len(in_if)
|
||||
if t == token_type_else:
|
||||
saw_match = len(in_if)
|
||||
|
||||
if t == token_type_else:
|
||||
saw_else = True
|
||||
|
||||
if t in [token_type_if, token_type_ifdef, token_type_ifndef,
|
||||
token_type_elif, token_type_elifdef, token_type_elifndef, token_type_else]:
|
||||
i, block_in_front = process_part_of_file(tokens, symbols_here, i, input_dir,
|
||||
(saw_match == len(in_if) or (t in [token_type_if, token_type_elif]) or
|
||||
(t == token_type_else and saw_unevaluatable_condition)) and take_seriously,
|
||||
alien_headers)
|
||||
in_if.append(IfDirCondAndBlock(cond=token, inside=block_in_front))
|
||||
|
||||
if t == token_type_endif:
|
||||
assert in_if
|
||||
if saw_unevaluatable_condition:
|
||||
for if_block in in_if:
|
||||
output += if_block.cond.original
|
||||
output += if_block.inside.text
|
||||
output += token.original
|
||||
elif saw_match > -1:
|
||||
output += in_if[saw_match].inside.text
|
||||
symbols_here = in_if[saw_match].inside.new_symbol_set
|
||||
|
||||
saw_unevaluatable_condition = False
|
||||
saw_else = False
|
||||
saw_match = -1
|
||||
in_if = []
|
||||
|
||||
if t == token_type_define:
|
||||
symbols_here.add(token.symbol)
|
||||
output += token.original
|
||||
if t == token_type_include_local:
|
||||
if take_seriously:
|
||||
include_path = os.path.join(input_dir, token.filepath)
|
||||
if not os.path.isfile(include_path):
|
||||
raise ValueError(f"No such file {include_path}")
|
||||
included_output = process_file(include_path, symbols_here, alien_headers)
|
||||
output += included_output.text
|
||||
symbols_here = included_output.new_symbol_set
|
||||
else:
|
||||
output += token.original
|
||||
if t == token_type_regular:
|
||||
output += token.original
|
||||
|
||||
if in_if:
|
||||
ValueError("You reached for the EOF too soon")
|
||||
return i, IfDirBlock(text=output, new_symbol_set=symbols_here)
|
||||
|
||||
# Returns block (text + new_symbols)
|
||||
def process_file(file_path, symbols_here: Set[str], alien_headers: Set[str]) -> IfDirBlock:
|
||||
input_dir = os.path.dirname(os.path.abspath(file_path))
|
||||
with open(file_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
tokens = analyze_file(lines, alien_headers)
|
||||
end_i, block = process_part_of_file(tokens, symbols_here, 0, input_dir, True, alien_headers)
|
||||
assert end_i == len(tokens)
|
||||
return block
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgumentParser(description="Sobiralka")
|
||||
parser.add_argument('input_file', type=str, help="Input C file path")
|
||||
parser.add_argument('output_file', type=str, help="Output C file path")
|
||||
parser.add_argument('-D', action='append', default=[], help="Define symbols")
|
||||
parser.add_argument('-I', action='append', default=[], help="Imaginary headers from the other side")
|
||||
|
||||
args = parser.parse_args()
|
||||
defined_symbols = set(args.D)
|
||||
alien_headers = set(args.I)
|
||||
|
||||
entire_program = process_file(args.input_file, defined_symbols, alien_headers)
|
||||
with open(args.output_file, 'w') as f:
|
||||
f.write(entire_program.text)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -16,18 +16,23 @@ typedef struct {
|
||||
};
|
||||
} Result_VecU8_or_int;
|
||||
|
||||
void Result_VecU8_or_int_drop(Result_VecU8_or_int obj) {
|
||||
if (obj.variant == Result_Ok)
|
||||
VecU8_drop(obj.Ok);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Result_variant variant;
|
||||
int Err;
|
||||
} Result_ok_or_int;
|
||||
|
||||
/* path is VecU8. Aborts on error */
|
||||
NODISCARD VecU8 read_file_by_path(VecU8 path){
|
||||
VecU8_append(&path, 0);
|
||||
FILE* fp = fopen((const char*)path.buf, "rb");
|
||||
if (!fp)
|
||||
abortf("Can't open file %s: %s\n", (const char*)path.buf, strerror(errno));
|
||||
VecU8_drop(path);
|
||||
void Result_ok_or_int_drop(Result_ok_or_int obj) {}
|
||||
|
||||
NODISCARD VecU8 read_whole_file_or_abort(const char* filename) {
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
abortf("Can't open file %s: %s\n", filename, strerror(errno));
|
||||
}
|
||||
if (fseek(fp, 0, SEEK_END) != 0) {
|
||||
abortf("fseek: %s\n", strerror(errno));
|
||||
}
|
||||
@ -40,18 +45,17 @@ NODISCARD VecU8 read_file_by_path(VecU8 path){
|
||||
}
|
||||
VecU8 result = (VecU8){.buf = safe_malloc(file_size), .len = file_size, .capacity = file_size};
|
||||
size_t nread = fread(result.buf, 1, (size_t)file_size, fp);
|
||||
if ((long)nread < file_size) {
|
||||
if (nread < file_size) {
|
||||
abortf("fread\n");
|
||||
}
|
||||
fclose(fp);
|
||||
return result;
|
||||
}
|
||||
|
||||
void write_file_by_path(VecU8 path, SpanU8 content){
|
||||
VecU8_append(&path, 0);
|
||||
FILE* fd = fopen((const char*)path.buf, "wb");
|
||||
void write_whole_file_or_abort(const char* filename, SpanU8 content) {
|
||||
FILE* fd = fopen(filename, "wb");
|
||||
if (!fd) {
|
||||
abortf("Can't open file %s: %s\n", (const char*)path.buf, strerror(errno));
|
||||
abortf("Can't open file %s: %s\n", filename, strerror(errno));
|
||||
}
|
||||
if (fwrite(content.data, 1, content.len, fd) < content.len) {
|
||||
abortf("fwrite\n");
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#define PROTOTYPE1_SRC_L1_SYSTEM_FSMANIP_H
|
||||
|
||||
/* For posix */
|
||||
#include <sys/stat.h>
|
||||
#include "sys/stat.h"
|
||||
#include <errno.h>
|
||||
#include "../core/util.h"
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U32.h"
|
||||
#include "../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
|
||||
int main() {
|
||||
VecU8 a = VecU8_new();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#include "../../../gen/l1/VecAndSpan_U64.h"
|
||||
#include "../../../gen/l1/VecAndSpan_VecU64.h"
|
||||
#include "../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
#include "../../../gen/l1/VecAndSpan_Vec_int_primitives.h"
|
||||
|
||||
int main() {
|
||||
VecU64 v = VecU64_new();
|
||||
|
||||
@ -3,38 +3,38 @@
|
||||
int main(){
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%i", 0);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("0")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("0")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%i%i%i%i", -1LL, 0LL, 44LL, -231LL);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1044-231")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1044-231")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%i", 44LL);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%u", 44ULL);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%u %i", 18446744073709551615ULL, -1LL);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 res = VecU8_fmt("%i %i", 9223372036854775807LL, -9223372036854775807LL-1);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
{
|
||||
VecU8 vec2 = vcstr("vec2");
|
||||
VecU8 res = VecU8_fmt("%i %v %i", -1230LL, vec2, 1340LL);
|
||||
check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340")));
|
||||
check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340")));
|
||||
VecU8_drop(res);
|
||||
}
|
||||
return 0;
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
#include "../../../gen/l1/geom.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
float random_float(float a, float b){
|
||||
int r = rand();
|
||||
return a + (b - a) * ((float)r / (float)RAND_MAX);
|
||||
}
|
||||
|
||||
float random_float100(){
|
||||
return random_float(-100, 100);
|
||||
}
|
||||
|
||||
mat4 random_big_matrix(){
|
||||
return mat4_new(random_float100(), random_float100(), random_float100(), random_float100(),
|
||||
random_float100(), random_float100(), random_float100(), random_float100(),
|
||||
random_float100(), random_float100(), random_float100(), random_float100(),
|
||||
random_float100(), random_float100(), random_float100(), random_float100());
|
||||
}
|
||||
|
||||
mat2 random_smol_matrix(){
|
||||
return mat2_new(random_float100(), random_float100(), random_float100(), random_float100());
|
||||
}
|
||||
|
||||
#define flPr "%02.05f"
|
||||
|
||||
void test_mat4(mat4 A){
|
||||
mat4 iA = mat4_inverse(A);
|
||||
mat4 product = mat4_mul_mat4(iA, A);
|
||||
printf(flPr " " flPr " " flPr " " flPr "\n"
|
||||
flPr " " flPr " " flPr " " flPr "\n"
|
||||
flPr " " flPr " " flPr " " flPr "\n"
|
||||
flPr " " flPr " " flPr " " flPr "\n",
|
||||
product.x.x, product.y.x, product.z.x, product.w.x,
|
||||
product.x.y, product.y.y, product.z.y, product.w.y,
|
||||
product.x.z, product.y.z, product.z.z, product.w.z,
|
||||
product.x.w, product.y.w, product.z.w, product.w.w);
|
||||
}
|
||||
|
||||
void test_mat2(mat2 A){
|
||||
mat2 iA = mat2_inverse(A);
|
||||
mat2 product = mat2_mul_mat2(iA, A);
|
||||
printf(flPr " " flPr "\n"
|
||||
flPr " " flPr "\n",
|
||||
product.x.x, product.y.x,
|
||||
product.x.y, product.y.y);
|
||||
}
|
||||
|
||||
void test(){
|
||||
mat2x3 A = (mat2x3){.x = {1, 2, 3}, .y = {4, 5, 6}};
|
||||
mat3x2 At = mat2x3_transpose(A);
|
||||
assert(At.x.x == 1);
|
||||
assert(At.x.y == 4);
|
||||
assert(At.y.x == 2);
|
||||
assert(At.y.y == 5);
|
||||
assert(At.z.x == 3);
|
||||
assert(At.z.y == 6);
|
||||
}
|
||||
|
||||
int main() {
|
||||
test();
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat4(random_big_matrix());
|
||||
test_mat2(random_smol_matrix());
|
||||
test_mat2(random_smol_matrix());
|
||||
test_mat2(random_smol_matrix());
|
||||
test_mat2(random_smol_matrix());
|
||||
}
|
||||
@ -1,19 +1,15 @@
|
||||
#include "../../l1/system/fsmanip.h"
|
||||
|
||||
#include "marie/clipping.h"
|
||||
#include "liza.h"
|
||||
#include "l1_5_templ_very_base.h"
|
||||
#include "margaret.h"
|
||||
#include "lucy.h"
|
||||
#include "gui.h"
|
||||
|
||||
int main() {
|
||||
mkdir_nofail("l1_5");
|
||||
mkdir_nofail("l1_5/eve");
|
||||
mkdir_nofail("l1_5/marie");
|
||||
generate_marie_clipping_header();
|
||||
generate_l1_5_liza_headers();
|
||||
generate_l1_5_template_instantiation_for_base_types();
|
||||
generate_l1_5_template_instantiations_for_margaret();
|
||||
generate_l1_5_lucy_headers();
|
||||
generate_l1_5_gui_headers();
|
||||
finish_layer(cstr("l1_5"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_anne_gui_h
|
||||
#define prototype1_src_l1_5_anne_gui_h
|
||||
|
||||
#include "../codegen/trait_wrap_boil.h"
|
||||
|
||||
void generate_l1_5_gui_headers(){
|
||||
mkdir_nofail("l1_5/eve/gui");
|
||||
SpanU8 l = cstr("l1_5"), ns = cstr("gui");
|
||||
generate_trait_wrapper_templ_inst_eve_header(l, ns, (trait_wrapper_boil_options){
|
||||
.trait = {
|
||||
.name = cstr("Widget"),
|
||||
.methods = (SpanNamedMethodSignatureRecordRef){
|
||||
.data = (NamedMethodSignatureRecordRef[]){
|
||||
{
|
||||
.takes_self = true,
|
||||
.takes_mut_self = true,
|
||||
.params = (SpanNamedVariableRecordRef){
|
||||
.data = (NamedVariableRecordRef[]){
|
||||
{ .type = cstr("uvec2"), .name = cstr("max_limits") }
|
||||
}, .len = 1
|
||||
},
|
||||
.return_type = cstr("uvec2"),
|
||||
.name = cstr("DRAW_PREPARE"),
|
||||
},
|
||||
{
|
||||
.takes_self = true,
|
||||
.takes_mut_self = true,
|
||||
.params = (SpanNamedVariableRecordRef){
|
||||
.data = (NamedVariableRecordRef[]){
|
||||
{ .type = cstr("ivec2"), .name = cstr("drawing_offset") },
|
||||
{ .type = cstr("uvec2"), .name = cstr("surface_sz") },
|
||||
{ .type = cstr("BorderS32"), .name = cstr("border") },
|
||||
}, .len = 3
|
||||
},
|
||||
.return_type = cstr(""),
|
||||
.name = cstr("DRAW"),
|
||||
}
|
||||
}, .len = 2
|
||||
},
|
||||
.drop_primitive = false,
|
||||
.base_struct_name = cstr("Widget"),
|
||||
},
|
||||
.box = true, .mut_ref = true
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,25 +1,17 @@
|
||||
#ifndef prototype1_src_l1_5_anne_l1_5_templ_very_base_h
|
||||
#define prototype1_src_l1_5_anne_l1_5_templ_very_base_h
|
||||
|
||||
#include "../codegen/buff_rbtree_set_map_template_inst.h"
|
||||
#include "../codegen/rbtree_set_map_template_inst.h"
|
||||
#include "../codegen/rb_tree_set_map_template_inst.h"
|
||||
|
||||
void generate_l1_5_template_instantiation_for_base_types(){
|
||||
SpanU8 l = cstr("l1_5"), ns = cstr("");
|
||||
generate_buf_rbtree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../l1/VecAndSpan_U64.h\""),
|
||||
(set_instantiation_op){.T = cstr("U64"), .t_integer = true});
|
||||
generate_buf_rbtree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../l1/VecAndSpan_S64.h\""),
|
||||
(set_instantiation_op){.T = cstr("S64"), .t_integer = true});
|
||||
|
||||
/* l1/core/utils.h is included in l1_5/core/rb_tree_node.h, hence no additional dependencies needed */
|
||||
generate_rbtree_Set_templ_inst_guarded_header(l, ns, cstr(""), (set_instantiation_op){
|
||||
.T = cstr("U64"), .t_integer = true }, true);
|
||||
generate_rbtree_Set_templ_inst_guarded_header(l, ns, cstr(""), (set_instantiation_op){
|
||||
.T = cstr("S64"), .t_integer = true }, true);
|
||||
|
||||
// todo: move vector declaration HERE
|
||||
generate_buf_rbtree_Map_templ_inst_guarded_header(l, ns, cstr("#include \"../../gen/l1/VecKVPU64ToU64.h\"\n"),
|
||||
(map_instantiation_op){.K = cstr("U64"), .k_integer = true, .V = cstr("U64"), .v_integer = true,});
|
||||
SpanU8 l = cstr("l1_5");
|
||||
SpanU8 ns = cstr("");
|
||||
SpanU8 dep = cstr(
|
||||
"#include \"../l1/VecAndSpan_int_primitives.h\""
|
||||
);
|
||||
// todo: split VecAndSpan_int_primitives into multiple files (one file per integer type)
|
||||
generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("U64"), .t_integer = true});
|
||||
generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("S64"), .t_integer = true});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -4,32 +4,8 @@
|
||||
#include "../codegen/trait_wrap_boil.h"
|
||||
|
||||
void generate_l1_5_liza_headers() {
|
||||
mkdir_nofail("l1_5/eve/liza");
|
||||
SpanU8 l = cstr("l1_5"), ns = cstr("liza");
|
||||
generate_trait_wrapper_templ_inst_eve_header(l, ns, (trait_wrapper_boil_options){
|
||||
.trait = {
|
||||
.name = cstr("LizaInstrument"),
|
||||
.methods = (SpanNamedMethodSignatureRecordRef){
|
||||
// todo: request options for instrument
|
||||
.data = (NamedMethodSignatureRecordRef[]){
|
||||
{
|
||||
.takes_self = true,
|
||||
.params = (SpanNamedVariableRecordRef){
|
||||
.data = (NamedVariableRecordRef[]){
|
||||
{.type = cstr("double"), .name = cstr("frequency") },
|
||||
{ .type = cstr("double"), .name = cstr("time") },
|
||||
}, .len = 2
|
||||
},
|
||||
.return_type = cstr("BoxLizaSound"),
|
||||
.name = cstr("ding"),
|
||||
}
|
||||
}, .len = 1
|
||||
},
|
||||
.drop_primitive = false,
|
||||
.base_struct_name = cstr(""),
|
||||
},
|
||||
.box = true, .ref = true, .mut_ref = true
|
||||
});
|
||||
mkdir_nofail("l1_5/liza");
|
||||
// todo: use#include "../codegen/trait_wrap_boil.h"
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,16 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_anne_lucy_h
|
||||
#define prototype1_src_l1_5_anne_lucy_h
|
||||
|
||||
#include "../codegen/buff_rbtree_set_map_template_inst.h"
|
||||
|
||||
void generate_l1_5_lucy_headers(){
|
||||
SpanU8 l = cstr("l1_5"), ns = cstr("lucy");
|
||||
mkdir_nofail("l1_5/eve/lucy");
|
||||
generate_buf_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){
|
||||
.K = cstr("U32"), .k_integer = true, .V = cstr("LucyStoredGlyph"), .v_primitive = true});
|
||||
generate_rbtree_Map_templ_inst_eve_header(l, ns, (map_instantiation_op){
|
||||
.K = cstr("U32"), .k_integer = true, .V = cstr("LucyFaceFixedSize")}, true);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,28 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_anne_margaret_h
|
||||
#define prototype1_src_l1_5_anne_margaret_h
|
||||
|
||||
#include "../codegen/buff_rbtree_set_map_template_inst.h"
|
||||
#include "../codegen/rbtree_set_map_template_inst.h"
|
||||
|
||||
void generate_l1_5_template_instantiations_for_margaret(){
|
||||
SpanU8 l = cstr("l1_5"), ns = cstr("margaret");
|
||||
mkdir_nofail("l1_5/eve");
|
||||
mkdir_nofail("l1_5/eve/margaret");
|
||||
|
||||
/* For l2/margaret/{ vulkan_img_claire.h , vulkan_buffer_claire.h } */
|
||||
generate_buf_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){
|
||||
.T = cstr("MargaretIAFreeSegment"), .t_primitive = true,
|
||||
/* comparison takes additional U8 parameter */
|
||||
.alternative_less = cstr("MargaretIAFreeSegment_less_resp_align"),
|
||||
.alternative_comp_set_name_embed = cstr("LenRespAlign"),
|
||||
.guest_data_T = cstr("U8"),
|
||||
});
|
||||
generate_buf_rbtree_Set_templ_inst_eve_header(l, ns, (set_instantiation_op){
|
||||
.T = cstr("MargaretBAFreeSegment"), .t_primitive = true,
|
||||
/* comparison takes additional U8 parameter */
|
||||
.alternative_less = cstr("MargaretBAFreeSegment_less_len"),
|
||||
.alternative_comp_set_name_embed = cstr("Len"),
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
419
src/l1_5/anne/marie/clipping.h
Normal file
419
src/l1_5/anne/marie/clipping.h
Normal file
@ -0,0 +1,419 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_CODEGEN_CLIPPING_H
|
||||
#define PROTOTYPE1_SRC_L1_CODEGEN_CLIPPING_H
|
||||
|
||||
#include "../../../l1/codegen/codegen.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_Span_int_primitives.h"
|
||||
|
||||
// todo: move all of this to marie namespace
|
||||
// todo: instead of returning triangles, return points of convex polygon
|
||||
// todo: I would say that I need to rewrite all with VecU8_fmt, but I am not sure I even need this code
|
||||
// todo: rewrite if I decide not to delete
|
||||
|
||||
typedef struct {
|
||||
int order;
|
||||
bool negate;
|
||||
} PossiblyNegatedTriangle;
|
||||
|
||||
int comparison_triang_groups[18][3] = {
|
||||
{10, 11, 20}, {10, 11, 21}, {10, 11, 22},
|
||||
{11, 12, 20}, {11, 12, 21}, {11, 12, 22},
|
||||
{12, 10, 20}, {12, 10, 21}, {12, 10, 22},
|
||||
|
||||
{20, 21, 10}, {20, 21, 11}, {20, 21, 12},
|
||||
{21, 22, 10}, {21, 22, 11}, {21, 22, 12},
|
||||
{22, 20, 10}, {22, 20, 11}, {22, 20, 12},
|
||||
};
|
||||
|
||||
int permutations_of_sigma3(const int ns[static 3]) {
|
||||
return (ns[0] > ns[1]) + (ns[1] > ns[2]) + (ns[0] > ns[2]);
|
||||
}
|
||||
|
||||
PossiblyNegatedTriangle get_order_var_of_triangle_merged_ns(int arg[static 3]) {
|
||||
for (int ord = 0; ord < 18; ord++) {
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 3; y++) {
|
||||
if (comparison_triang_groups[ord][y] == arg[x])
|
||||
goto found_this_one;
|
||||
}
|
||||
goto nah_not_this_one;
|
||||
found_this_one:
|
||||
}
|
||||
return (PossiblyNegatedTriangle){ .order = ord,
|
||||
.negate = ((permutations_of_sigma3(comparison_triang_groups[ord]) +
|
||||
permutations_of_sigma3(arg)) % 2 == 1) };
|
||||
nah_not_this_one: /* We continue out search*/
|
||||
}
|
||||
abortf("Impossible");
|
||||
}
|
||||
|
||||
|
||||
PossiblyNegatedTriangle get_order_var_of_triangle(char tri, int idi, char trj, int idj, char tru, int idu) {
|
||||
assert(tri == 'C' || tri == 'T');
|
||||
assert(trj == 'C' || trj == 'T');
|
||||
assert(tru == 'C' || tru == 'T');
|
||||
assert(0 <= idi && idi < 3);
|
||||
assert(0 <= idj && idj < 3);
|
||||
assert(0 <= idu && idu < 3);
|
||||
assert(!(tri == trj && trj == tru));
|
||||
assert(!(tri == trj && idi == idj));
|
||||
assert(!(trj == tru && idj == idu));
|
||||
assert(!(tri == tru && idi == idu));
|
||||
int arg[3] = { (tri == 'C' ? 10 : 20) + idi, (trj == 'C' ? 10 : 20) + idj, (tru == 'C' ? 10 : 20) + idu };
|
||||
return get_order_var_of_triangle_merged_ns(arg);
|
||||
}
|
||||
|
||||
/* Appends code to string with code.
|
||||
* Triangle is either 'T' or 'C'
|
||||
* Vertexes in triangle are numbered 0,1,2
|
||||
* vertex vi: (index idi of triangle tri)
|
||||
* vertex vj: (index idj of triangle trj)
|
||||
* vertex u: (index idu of triangle tru)
|
||||
* We walk along the vi -> vj ray. If u is on the left, this statement will show true
|
||||
*/
|
||||
void append_on_the_left_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) {
|
||||
PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu);
|
||||
VecU8_append_vec(str, VecU8_format("(M%d %s 0)", measure.order, measure.negate ? "<=" : ">="));
|
||||
}
|
||||
|
||||
void append_on_the_right_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) {
|
||||
PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu);
|
||||
VecU8_append_vec(str, VecU8_format("(M%d %s 0)", measure.order, measure.negate ? ">=" : "<="));
|
||||
}
|
||||
|
||||
|
||||
/* Generates statement that intersects two segments from 2 different triangles:
|
||||
* First segment: (tr1::A1) to (tr1::B1)
|
||||
* Second segment: (tr2::A2) to (tr2::B2)
|
||||
* */
|
||||
void append_intersection_eol_stmt(VecU8* str, char tr1, int A1, int B1, char tr2, int A2, int B2) {
|
||||
assert((tr1 == 'C' && tr2 == 'T') || (tr1 == 'T' && tr2 == 'C'));
|
||||
assert(0 <= A1 && A1 < 3);
|
||||
assert(0 <= B1 && B1 < 3);
|
||||
assert(0 <= A2 && A2 < 3);
|
||||
assert(0 <= B2 && B2 < 3);
|
||||
assert(A1 != B1 && A2 != B2);
|
||||
VecU8_append_vec(str, VecU8_format("marie_intersect_lines(%c.v%d, %c.v%d, %c.v%d, %c.v%d);\n",
|
||||
tr1, A1, tr1, B1, tr2, A2, tr2, B2));
|
||||
}
|
||||
|
||||
SpanU8 marie_names_of_two_clipping_triangles[6] = {
|
||||
cstr("C.v0"), cstr("C.v1"), cstr("C.v2"),
|
||||
cstr("T.v0"), cstr("T.v1"), cstr("T.v2"),
|
||||
};
|
||||
|
||||
NODISCARD SpanU8 get_firstborn_vertex_stmt(char tr, int id) {
|
||||
assert(0 <= id && id < 3);
|
||||
if (tr == 'C')
|
||||
return marie_names_of_two_clipping_triangles[id];
|
||||
if (tr == 'T')
|
||||
return marie_names_of_two_clipping_triangles[3 + id];
|
||||
abortf("Wrong triangle");
|
||||
}
|
||||
|
||||
void append_triangle_registration_stmt(VecU8* str, SpanU8 P0, SpanU8 P1, SpanU8 P2) {
|
||||
VecU8_append_span(str, cstr("VecMarieTriangle_append(pile, (MarieTriangle){"));
|
||||
VecU8_append_span(str, P0);
|
||||
VecU8_append_span(str, cstr(", "));
|
||||
VecU8_append_span(str, P1);
|
||||
VecU8_append_span(str, cstr(", "));
|
||||
VecU8_append_span(str, P2);
|
||||
VecU8_append_span(str, cstr("});\n"));
|
||||
}
|
||||
|
||||
void append_answering_stmt(VecU8* res, SpanSpanU8 vertices, int tabulation_lvl) {
|
||||
size_t n = vertices.len;
|
||||
assert(n >= 3);
|
||||
for (size_t i = 0; i < n - 2; i++) {
|
||||
for (int sp = 0; sp < tabulation_lvl; sp++)
|
||||
VecU8_append(res, ' ');
|
||||
append_triangle_registration_stmt(res, *SpanSpanU8_at(vertices, i),
|
||||
*SpanSpanU8_at(vertices, i + 1), *SpanSpanU8_at(vertices, n - 1));
|
||||
}
|
||||
for (int sp = 0; sp < tabulation_lvl; sp++)
|
||||
VecU8_append(res, ' ');
|
||||
VecU8_append_span(res, cstr("return;\n"));
|
||||
}
|
||||
|
||||
int mod3_inc(int x) {
|
||||
return x == 2 ? 0 : (x + 1);
|
||||
}
|
||||
|
||||
int mod3_dec(int x) {
|
||||
return x ? (x - 1) : 2;
|
||||
}
|
||||
|
||||
void generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(VecU8* res, char tC, char tT, bool tables_turned) {
|
||||
/* Case where all 3 vertices of tT are inside tC */
|
||||
VecU8_append_span(res, cstr(SPACE "if ("));
|
||||
for (int cs = 0; cs < 3; cs++) {
|
||||
for (int tv = 0; tv < 3; tv++) {
|
||||
if (cs != 0 || tv != 0)
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tC, cs, tC, (cs + 1) % 3, tT, tv);
|
||||
}
|
||||
}
|
||||
VecU8_append_span(res, cstr(") {\n" SPACE8));
|
||||
append_triangle_registration_stmt(res,
|
||||
get_firstborn_vertex_stmt(tT, 0), get_firstborn_vertex_stmt(tT, 1), get_firstborn_vertex_stmt(tT, 2));
|
||||
VecU8_append_span(res, cstr(SPACE8 "return;\n" SPACE "}\n\n"));
|
||||
|
||||
/* Cases where two vertices of tT are inside tC, but one is outside */
|
||||
for (int ti = 0; ti < 3; ti++) {
|
||||
VecU8_append_span(res, cstr(SPACE "if ("));
|
||||
int TA = mod3_inc(ti);
|
||||
int TB = mod3_inc(TA);
|
||||
for (int j = 1; j <= 2; j++) {
|
||||
for (int cs = 0; cs < 3; cs++) {
|
||||
if (cs != 0 || j != 1)
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tC, cs, tC, mod3_inc(cs), tT, (ti + j) % 3);
|
||||
}
|
||||
}
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
for (int sc = 0; sc < 3; sc++) {
|
||||
VecU8_append_span(res, cstr(SPACE8 "if ("));
|
||||
append_on_the_right_stmt(res, tC, sc, tC, mod3_inc(sc), tT, ti);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
/* 'Result hits one edge' case */
|
||||
VecU8_append_span(res, cstr(SPACE12 "if ("));
|
||||
append_on_the_left_stmt(res, tT, TA, tC, sc, tT, ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tT, TB, tC, sc, tT, ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, tT, TA, tC, mod3_inc(sc), tT, ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, tT, TB, tC, mod3_inc(sc), tT, ti);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TB);
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TA);
|
||||
SpanU8 quad[4] = {
|
||||
get_firstborn_vertex_stmt(tT, TB), cstr("PB"), cstr("PA"), get_firstborn_vertex_stmt(tT, TA) };
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = quad, .len = ARRAY_SIZE(quad)}, 16);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE12 "}\n"));
|
||||
if (!tables_turned) {
|
||||
/* 'Result hits the angle and two edges' case */
|
||||
VecU8_append_span(res, cstr(SPACE12 "if ("));
|
||||
append_on_the_left_stmt(res, tT, TA, tC, sc, tT, ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, tT, TB, tC, sc, tT, ti);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, tC, sc, mod3_dec(sc), tT, ti, TB);
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TA);
|
||||
SpanU8 pentagon[5] = { get_firstborn_vertex_stmt(tT, TB), cstr("PB"),
|
||||
get_firstborn_vertex_stmt(tC, sc), cstr("PA"), get_firstborn_vertex_stmt(tT, TA)};
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = pentagon, .len = ARRAY_SIZE(pentagon)}, 16);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE12 "}\n"));
|
||||
}
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "}\n"));
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE "}\n\n"));
|
||||
}
|
||||
|
||||
/* Case where one vertice of tT is inside tC, but other two are outside tC */
|
||||
for (int pl = 0; pl < 3; pl++) {
|
||||
int TA = mod3_inc(pl);
|
||||
int TB = mod3_inc(TA);
|
||||
VecU8_append_span(res, cstr(SPACE "if ("));
|
||||
for (int cb = 0; cb < 3; cb++) {
|
||||
if (cb)
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tC, cb, tC, mod3_inc(cb), tT, pl);
|
||||
}
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
for (int cr = 0; cr < 3; cr++) {
|
||||
/* Cases where one vertex (pl) of tT is inside tC, but two other (TA and TB) are in
|
||||
* the same 'third of a surface' */
|
||||
VecU8_append_span(res, cstr(SPACE8 "if ("));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, cr, tT, TA);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, cr, tT, TB);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(cr), tT, TA);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(cr), tT, TB);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TA, tC, cr, mod3_inc(cr));
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TB, tC, cr, mod3_inc(cr));
|
||||
SpanU8 trig[3] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"), cstr("PB")};
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = trig, .len = ARRAY_SIZE(trig)}, 12);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "}\n"));
|
||||
}
|
||||
for (int rc = 0; rc < 3; rc++) {
|
||||
VecU8_append_span(res, cstr(SPACE8 "if ("));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, rc, tT, TA);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, tT, pl, tC, mod3_inc(rc), tT, TA);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(rc), tT, TB);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, tT, pl, tC, mod3_dec(rc), tT, TB);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
/* Case where TA and TB are in different 'thirds of surface' and the vertex of tC that defines
|
||||
* border is outside tT. Result is a pentagon */
|
||||
VecU8_append_span(res, cstr(SPACE12 "if ("));
|
||||
append_on_the_right_stmt(res, tT, TA, tT, TB, tC, mod3_inc(rc));
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TA, tC, rc, mod3_inc(rc));
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 QA = "));
|
||||
append_intersection_eol_stmt(res, tT, TA, TB, tC, rc, mod3_inc(rc));
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 QB = "));
|
||||
append_intersection_eol_stmt(res, tT, TA, TB, tC, mod3_inc(rc), mod3_dec(rc));
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TB, tC, mod3_inc(rc), mod3_dec(rc));
|
||||
SpanU8 pent[5] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"), cstr("QA"), cstr("QB"), cstr("PB")};
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = pent, .len = ARRAY_SIZE(pent)}, 16);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE12 "}"));
|
||||
if (!tables_turned) {
|
||||
/* Case where TA and TB are in different sectors and rc++ is inside tT
|
||||
* Result is a quadrangle */
|
||||
VecU8_append_span(res, cstr(" else {\n"));
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TA, tC, rc, mod3_inc(rc));
|
||||
VecU8_append_span(res, cstr(SPACE16 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, tT, pl, TB, tC, mod3_inc(rc), mod3_dec(rc));
|
||||
SpanU8 quad[4] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"),
|
||||
get_firstborn_vertex_stmt(tC, mod3_inc(rc)), cstr("PB")};
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = quad, .len = ARRAY_SIZE(quad)}, 16);
|
||||
VecU8_append_span(res, cstr(SPACE12 "}"));
|
||||
}
|
||||
VecU8_append_span(res, cstr("\n"));
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "}\n"));
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE "}\n\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/* It is assumed that it goes after two passes of generate_func_clip_triang_on_triang_case_where_some_vertex_stuck */
|
||||
void generate_func_clip_triang_on_triang_case_boring(VecU8* res) {
|
||||
/* Star of David case */
|
||||
for (int cb = 0; cb < 3; cb++) {
|
||||
VecU8_append_span(res, cstr(SPACE "if ("));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i)
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'C', (i + cb) % 3, 'C', (i + cb + 1) % 3, 'T', i);
|
||||
}
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE8 "vec2 hex[6] = {\n"));
|
||||
for (int ti = 0; ti < 3; ti++) {
|
||||
for (int cj = 0; cj < 2; cj++) {
|
||||
VecU8_append_vec(res, VecU8_format(SPACE12 "marie_intersect_lines(T.v%d, T.v%d, C.v%d, C.v%d),\n",
|
||||
ti, (ti + 1) % 3, (ti + cb + cj) % 3, (ti + cb + cj + 1) % 3));
|
||||
}
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "};\n"));
|
||||
VecU8_append_span(res, cstr(SPACE8 "for (int i = 0; i < 4; i++)\n"
|
||||
SPACE12 "VecMarieTriangle_append(pile, (MarieTriangle){hex[i], hex[i + 1], hex[5]});\n"));
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE "}\n"));
|
||||
}
|
||||
/* Wedge cases */
|
||||
for (int cf = 0; cf < 3; cf++) {
|
||||
for (int ti = 0; ti < 3; ti++){
|
||||
VecU8_append_span(res, cstr(SPACE "if ("));
|
||||
append_on_the_left_stmt(res, 'T', ti, 'T', mod3_dec(ti), 'C', cf);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'T', mod3_inc(ti), 'T', mod3_dec(ti), 'C', (cf + 2) % 3);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_left_stmt(res, 'C', cf, 'C', (cf + 2) % 3, 'T', (ti + 2) % 3);
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
SpanU8 quad[4] = {cstr("PA"), cstr("PB"), cstr("PC"), cstr("PD")};
|
||||
/* case A */
|
||||
VecU8_append_span(res, cstr(SPACE8 "if ("));
|
||||
append_on_the_left_stmt(res, 'T', ti, 'T', mod3_dec(ti), 'C', mod3_inc(cf));
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'C', mod3_inc(cf), 'C', mod3_dec(cf), 'T', ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'C', mod3_inc(cf), 'C', mod3_dec(cf), 'T', mod3_inc(ti));
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_inc(cf), mod3_dec(cf));
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_inc(cf), mod3_dec(cf));
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PC = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_dec(cf), cf);
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PD = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_dec(cf), cf);
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = quad, ARRAY_SIZE(quad)}, 12);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "}\n"));
|
||||
/* case B */
|
||||
VecU8_append_span(res, cstr(SPACE8 "if ("));
|
||||
append_on_the_right_stmt(res, 'T', mod3_inc(ti), 'T', mod3_dec(ti), 'C', mod3_inc(cf));
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'C', cf, 'C', mod3_inc(cf), 'T', ti);
|
||||
VecU8_append_span(res, cstr(" && "));
|
||||
append_on_the_right_stmt(res, 'C', cf, 'C', mod3_inc(cf), 'T', mod3_inc(ti));
|
||||
VecU8_append_span(res, cstr(") {\n"));
|
||||
{
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PA = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', cf, mod3_inc(cf));
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PB = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', cf, mod3_inc(cf));
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PC = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_dec(cf), cf);
|
||||
VecU8_append_span(res, cstr(SPACE12 "vec2 PD = "));
|
||||
append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_dec(cf), cf);
|
||||
append_answering_stmt(res, (SpanSpanU8){.data = quad, ARRAY_SIZE(quad)}, 12);
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE8 "}\n"));
|
||||
}
|
||||
VecU8_append_span(res, cstr(SPACE "}\n"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec() {
|
||||
VecU8 res = VecU8_from_cstr(
|
||||
"void marie_clip_ccw_triang_with_ccw_triang_append_to_Vec(MarieTriangle C, MarieTriangle T, VecMarieTriangle* pile) {\n");
|
||||
for (int ord = 0; ord < 18; ord++) {
|
||||
VecU8_append_vec(&res, VecU8_format(SPACE "float M%d = marie_surface(", ord));
|
||||
for (int a = 0; a < 3; a++) {
|
||||
if (a)
|
||||
VecU8_append_span(&res, cstr(", "));
|
||||
int vsh = comparison_triang_groups[ord][a];
|
||||
VecU8_append(&res, (vsh / 10) == 1 ? 'C' : 'T');
|
||||
VecU8_append_span(&res, cstr(".v"));
|
||||
VecU8_append(&res, '0' + vsh % 10);
|
||||
}
|
||||
VecU8_append_span(&res, cstr(");\n"));
|
||||
}
|
||||
generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'C', 'T', false);
|
||||
generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'T', 'C', true);
|
||||
generate_func_clip_triang_on_triang_case_boring(&res);
|
||||
VecU8_append_span(&res, cstr("}\n\n"));
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_marie_clipping_header() {
|
||||
GeneratedHeader res = begin_header(cstr("l1_5/marie/clipping.h"));
|
||||
VecU8_append_span(&res.result, cstr("#include \"../../l1/geom.h\"\n"
|
||||
"#include \"../../../src/l1/marie/geom_alg_utils.h\"\n\n"));
|
||||
VecU8_append_vec(&res.result, generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec());
|
||||
finish_header(res);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -3,99 +3,25 @@
|
||||
|
||||
#include "../../l1/codegen/util_template_inst.h"
|
||||
|
||||
// todo: continue from here
|
||||
|
||||
/* We assume that T is trivially movable */
|
||||
typedef struct {
|
||||
SpanU8 T;
|
||||
bool t_ptr;
|
||||
bool t_integer;
|
||||
bool t_primitive;
|
||||
bool t_clonable;
|
||||
SpanU8 alternative_less;
|
||||
SpanU8 alternative_comp_set_name_embed;
|
||||
|
||||
/* GT. You probably want it to be a pointer or an integer parameter.
|
||||
* Leave empty if you don't need guest data (GT = void)
|
||||
* GT must be primitive, or, even better, be integer */
|
||||
SpanU8 guest_data_T;
|
||||
} set_instantiation_op;
|
||||
|
||||
void set_instantiation_op_fix(set_instantiation_op* self){
|
||||
assert(self->T.len > 0);
|
||||
if (self->t_ptr)
|
||||
self->t_integer = true;
|
||||
if (self->t_integer)
|
||||
self->t_primitive = true;
|
||||
if (self->t_primitive)
|
||||
self->t_clonable = true;
|
||||
assert(self->T.len > 0);
|
||||
assert(self->alternative_less.len > 0 == self->alternative_comp_set_name_embed.len > 0);
|
||||
assert(self->guest_data_T.len == 0 || self->alternative_less.len > 0);
|
||||
}
|
||||
|
||||
/* We assume K and V are trivially movable */
|
||||
typedef struct {
|
||||
SpanU8 K;
|
||||
bool k_integer;
|
||||
bool k_primitive;
|
||||
bool k_clonable;
|
||||
SpanU8 V;
|
||||
bool v_integer;
|
||||
bool v_primitive;
|
||||
bool v_clonable;
|
||||
|
||||
SpanU8 alternative_less;
|
||||
SpanU8 alternative_comp_map_name_embed;
|
||||
|
||||
SpanU8 guest_data_T;
|
||||
|
||||
bool at, mat;
|
||||
bool pop, pop_substitute;
|
||||
} map_instantiation_op;
|
||||
|
||||
void map_instantiation_op_fix(map_instantiation_op* self){
|
||||
assert(self->K.len > 0);
|
||||
if (self->k_integer)
|
||||
self->k_primitive = true;
|
||||
if (self->k_primitive)
|
||||
self->k_clonable = true;
|
||||
|
||||
if (self->V.len == 0)
|
||||
self->v_primitive = true;
|
||||
if (self->v_integer)
|
||||
self->v_primitive = true;
|
||||
if (self->v_primitive)
|
||||
self->v_clonable = true;
|
||||
assert(self->alternative_less.len > 0 == self->alternative_comp_map_name_embed.len > 0);
|
||||
assert(self->guest_data_T.len == 0 || self->alternative_less.len > 0);
|
||||
}
|
||||
|
||||
|
||||
/* --- Sharing is caring --- */
|
||||
/* Assuming A nd B are passed as intended */
|
||||
NODISCARD VecU8 codegen_rbtree_map__less(map_instantiation_op op, VecU8 A, VecU8 B){
|
||||
if (op.guest_data_T.len > 0) {
|
||||
assert(op.alternative_less.len > 0);
|
||||
return VecU8_fmt("%s(%v, %v, self->guest)", op.alternative_less, A, B);
|
||||
}
|
||||
if (op.alternative_less.len > 0)
|
||||
return VecU8_fmt("%s(%v, %v)", op.alternative_less, A, B);
|
||||
if (op.k_integer)
|
||||
return VecU8_fmt("%v < %v", A, B);
|
||||
return VecU8_fmt("%s_less_%s(%v %v)", op.K, op.K, A, B);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_rbtree_map__exp_passing_key_val(map_instantiation_op op){
|
||||
return op.k_integer ? vcstr("key") : vcstr("&key");
|
||||
}
|
||||
|
||||
/* Suppose some method (like _erase() or _pop(), or _find(), or _at(), takes constant reference to key T
|
||||
* This function tells how to write type of this argument. Basically it is needed to take into account that
|
||||
* integer is better than pointer to integer. (Though, notice that _pop family of methods don't exist for
|
||||
* sets of integers
|
||||
*/
|
||||
NODISCARD VecU8 codegen_rbtree_map__taking_ref_k_argument(map_instantiation_op op){
|
||||
return op.k_integer ? VecU8_from_span(op.K) : VecU8_fmt("const %s*", op.K);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_rbtree_map__taking_t_argument(map_instantiation_op op){
|
||||
return op.V.len > 0 ? VecU8_fmt("%s key, %s value", op.K, op.V) : VecU8_fmt("%s key", op.K);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,562 +0,0 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_5_CODEGEN_RB_TREE_SET_MAP_TEMPLATE_INST_H
|
||||
#define PROTOTYPE1_SRC_L1_5_CODEGEN_RB_TREE_SET_MAP_TEMPLATE_INST_H
|
||||
|
||||
#include "all_set_map_templ_util_inst.h"
|
||||
|
||||
/* Assuming A nd B are passed as intended */
|
||||
|
||||
NODISCARD VecU8 codegen_buf_rbtree_map__exp_passing_cur_key(map_instantiation_op op){
|
||||
return VecU8_fmt("%s" "self->el.buf[cur - 1]" "%s",
|
||||
op.k_integer ? cstr("") : cstr("&"), op.V.len > 0 ? cstr(".key") : cstr(""));
|
||||
}
|
||||
|
||||
|
||||
/* Yes, both sets and maps use this function to instantiate themselves. No, user does not need to use it
|
||||
* set is either a set name or a map name. If we are instantiating set, TT is op.T from set options, if we are
|
||||
* instantiating a map, TT is KVP{op.K}To{op.V} from map options
|
||||
* */
|
||||
void codegen_append_buff_rbtree_map__structure_and_simplest_methods(
|
||||
VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT
|
||||
){
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "VecBufRBTreeNode tree;\n"
|
||||
SPACE "U64 root;\n"
|
||||
SPACE "Vec%s el;\n"
|
||||
"%v"
|
||||
"} %s;\n\n",
|
||||
TT, op.guest_data_T.len > 0 ? VecU8_fmt(SPACE "%s guest;\n", op.guest_data_T) : vcstr(""), set));
|
||||
|
||||
if (op.guest_data_T.len > 0) {
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new(%s guest) {\n" /* set, set, op.guest_data_T */
|
||||
SPACE "return (%s){.tree = VecBufRBTreeNode_new_zeroinit(1), .root = 0, .el = Vec%s_new(), .guest = guest};\n" /* set, TT */
|
||||
"}\n\n",
|
||||
set, set, op.guest_data_T,
|
||||
set, TT));
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_reserved(%s guest, size_t size) {\n" /* set, set, op.guest_data_T */
|
||||
SPACE "return (%s){.tree = (VecBufRBTreeNode){\n" /* set */
|
||||
SPACE SPACE ".buf = (BufRBTreeNode*)safe_calloc(size + 1, sizeof(BufRBTreeNode)), .len = 1, .capacity = size + 1},\n"
|
||||
SPACE SPACE ".root = 0, .el = Vec%s_new_reserved(size), .guest = guest};\n" /* TT */
|
||||
"}\n\n",
|
||||
set, set, op.guest_data_T,
|
||||
set, TT));
|
||||
} else {
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new() {\n" /* set, set */
|
||||
SPACE "return (%s){.tree = VecBufRBTreeNode_new_zeroinit(1), .root = 0, .el = Vec%s_new()};\n" /* set, TT */
|
||||
"}\n\n",
|
||||
set, set,
|
||||
set, TT));
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new_reserved(size_t size) {\n" /* set, set */
|
||||
SPACE "return (%s){.tree = (VecBufRBTreeNode){\n"
|
||||
SPACE SPACE ".buf = (BufRBTreeNode*)safe_calloc(size + 1, sizeof(BufRBTreeNode)), .len = 1, .capacity = size + 1},\n"
|
||||
SPACE SPACE ".root = 0, .el = Vec%s_new_reserved(size)};\n" /* set, TT */
|
||||
"}\n\n",
|
||||
set, set,
|
||||
set, TT));
|
||||
}
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"void %s_drop(%s self) {\n" /* set, set */
|
||||
SPACE "VecBufRBTreeNode_drop(self.tree);\n"
|
||||
SPACE "Vec%s_drop(self.el);\n" /* TT */
|
||||
"}\n\n", set, set, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"void %s_sink(%s* self) {\n" /* set, set */
|
||||
SPACE "self->tree.len = 1;\n"
|
||||
SPACE "self->tree.buf[0] = (BufRBTreeNode){0};\n"
|
||||
SPACE "Vec%s_sink(&self->el, 0);\n" /* TT */
|
||||
"}\n\n", set, set, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find(const %s* self, %v key) {\n" /* set, set, taking_ref_k_argument */
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v)\n" /* key < cur key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "else if (%v)\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "else \n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return 0;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key"))));
|
||||
|
||||
if (op.k_clonable && op.v_clonable) {
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_clone(const %s* self){\n" /* set, set, set */
|
||||
SPACE "return (%s){.tree = VecBufRBTreeNode_clone(&self->tree), .root = self->root,\n" /* set */
|
||||
SPACE SPACE ".el = Vec%s_clone(&self->el)%s};\n" /* TT, whether to clone guest or no */
|
||||
"}\n\n",
|
||||
set, set, set,
|
||||
set,
|
||||
TT, op.guest_data_T.len > 0 ? cstr(", .guest = self->guest") : cstr("")));
|
||||
}
|
||||
|
||||
// todo: move to common code
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_next(const %s* self, U64 x){\n"
|
||||
SPACE "assert(x != 0 && x < self->tree.len);\n"
|
||||
SPACE "if (self->tree.buf[x].right != 0)\n"
|
||||
SPACE SPACE "return BufRBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[x].right);\n"
|
||||
SPACE "while (true) {\n"
|
||||
SPACE SPACE "U64 p = self->tree.buf[x].parent;\n"
|
||||
SPACE SPACE "if (p == 0)\n"
|
||||
SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE "if (self->tree.buf[p].left == x)\n"
|
||||
SPACE SPACE SPACE "return p;\n"
|
||||
SPACE SPACE "x = p;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
// todo: move to comon code (core/buff_rb_tree_node.h)
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_prev(const %s* self, U64 x){\n"
|
||||
SPACE "assert(x != 0 && x < self->tree.len);\n"
|
||||
SPACE "if (self->tree.buf[x].left != 0)\n"
|
||||
SPACE SPACE "return BufRBTree_maximum_in_subtree(self->tree.buf, self->tree.buf[x].left);\n"
|
||||
SPACE "while (true) {\n"
|
||||
SPACE SPACE "U64 p = self->tree.buf[x].parent;\n"
|
||||
SPACE SPACE "if (p == 0)\n"
|
||||
SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE "if (self->tree.buf[p].right == x)\n"
|
||||
SPACE SPACE SPACE "return p;\n"
|
||||
SPACE SPACE "x = p;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_min(const %s* self) {\n"
|
||||
SPACE "return self->root != 0 ? BufRBTree_minimum_in_subtree(self->tree.buf, self->root) : 0;\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_max(const %s* self) {\n"
|
||||
SPACE "return self->root != 0 ? BufRBTree_maximum_in_subtree(self->tree.buf, self->root) : 0;\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_max_less(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */
|
||||
SPACE "U64 last_less = 0;\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {" /* key < cur key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "last_less = cur;\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE SPACE "if (cur == 0)\n"
|
||||
SPACE SPACE SPACE SPACE "return last_less;\n"
|
||||
SPACE SPACE SPACE "while (self->tree.buf[cur].right != 0)\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_less;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key"))));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_max_less_or_eq(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */
|
||||
SPACE "U64 last_less = 0;\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {" /* key < cur key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "last_less = cur;\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_less;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key"))));
|
||||
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_min_grtr(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */
|
||||
SPACE "U64 last_grtr = 0;\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur key*/
|
||||
SPACE SPACE SPACE "last_grtr = cur;\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE SPACE "if (cur == 0)\n"
|
||||
SPACE SPACE SPACE SPACE "return last_grtr;\n"
|
||||
SPACE SPACE SPACE "while (self->tree.buf[cur].left != 0)\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_grtr;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key"))));
|
||||
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"U64 %s_find_min_grtr_or_eq(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */
|
||||
SPACE "U64 last_grtr = 0;\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur key*/
|
||||
SPACE SPACE SPACE "last_grtr = cur;\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_grtr;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key"))));
|
||||
|
||||
VecU8 line_that_appends_new_el_to_el_vec = op.V.len > 0 ?
|
||||
VecU8_fmt("VecKVP%sTo%s_append(&self->el, (KVP%sTo%s){.key = key, .value = value});", op.K, op.V, op.K, op.V) :
|
||||
VecU8_fmt("Vec%s_append(&self->el, key);", op.K);
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
/* This method is unsafe. Arguments key, value will be taken if 0 is returned,
|
||||
* or left on their place if not-0 is returned */
|
||||
"/* UNSAFE */\n"
|
||||
"NODISCARD U64 %s_try_insert(%s* self, %v) {\n" /* set, set, taking_t_argument */
|
||||
SPACE "if (self->root == 0) {\n"
|
||||
SPACE SPACE "assert(self->tree.len == 1);\n"
|
||||
SPACE SPACE "VecBufRBTreeNode_append(&self->tree, (BufRBTreeNode){.color = RBTree_black});\n"
|
||||
SPACE SPACE "self->root = 1;\n"
|
||||
SPACE SPACE "%s\n" /* line_that_appends_new_el_to_el_vec */
|
||||
SPACE SPACE "return 0;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (true) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < el[cur] */
|
||||
SPACE SPACE SPACE "if (self->tree.buf[cur].left != 0) {\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE SPACE "} else { \n"
|
||||
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
|
||||
SPACE SPACE SPACE SPACE "VecBufRBTreeNode_append(&self->tree, (BufRBTreeNode){.parent = cur, .color = RBTree_red});\n"
|
||||
SPACE SPACE SPACE SPACE "self->tree.buf[cur].left = n;\n"
|
||||
SPACE SPACE SPACE SPACE "BufRBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
|
||||
SPACE SPACE SPACE SPACE "%s\n" /* line_that_appends_new_el_to_el_vec */
|
||||
SPACE SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* el[cur] < key */
|
||||
SPACE SPACE SPACE "if (self->tree.buf[cur].right != 0) {\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
|
||||
SPACE SPACE SPACE SPACE "VecBufRBTreeNode_append(&self->tree, (BufRBTreeNode){.parent = cur, .color = RBTree_red});\n"
|
||||
SPACE SPACE SPACE SPACE "self->tree.buf[cur].right = n;\n"
|
||||
SPACE SPACE SPACE SPACE "BufRBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
|
||||
SPACE SPACE SPACE SPACE "%s\n" /* line_that_appends_new_el_to_el_vec */
|
||||
SPACE SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return cur;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_t_argument(op),
|
||||
VecU8_to_span(&line_that_appends_new_el_to_el_vec),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_val(op), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
VecU8_to_span(&line_that_appends_new_el_to_el_vec),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_val(op)),
|
||||
VecU8_to_span(&line_that_appends_new_el_to_el_vec)));
|
||||
VecU8_drop(line_that_appends_new_el_to_el_vec);
|
||||
|
||||
// VecU8_append_vec(res, VecU8_fmt(
|
||||
// "/* UNSAFE. Use when you dropped the symbol that is about to be deleted */\n"
|
||||
// "void %s_empty_index_erase(%s* self, U64 z) {\n" /* set, set */
|
||||
// SPACE "assert(z != 0 && z < self->tree.len);\n"
|
||||
// SPACE "U64 y = (self->tree.buf[z].left == 0 || self->tree.buf[z].right == 0) ? z : BufRBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[z].right);\n"
|
||||
// SPACE "U64 x = self->tree.buf[y].left != 0 ? self->tree.buf[y].left : self->tree.buf[y].right;\n"
|
||||
// SPACE "assert(x != y && x != z);\n"
|
||||
// SPACE "U64 x_adopter = self->tree.buf[y].parent;\n"
|
||||
// SPACE "self->tree.buf[x].parent = x_adopter;\n"
|
||||
// SPACE "if (x_adopter == 0)\n"
|
||||
// SPACE SPACE "self->root = x;\n"
|
||||
// SPACE "else if (self->tree.buf[x_adopter].left == y)\n"
|
||||
// SPACE SPACE "self->tree.buf[x_adopter].left = x;\n"
|
||||
// SPACE "else\n"
|
||||
// SPACE SPACE "self->tree.buf[x_adopter].right = x;\n"
|
||||
// SPACE "RBTreeColor y_org_clr = self->tree.buf[y].color;\n"
|
||||
// SPACE "if (z != y) {\n"
|
||||
// SPACE SPACE "BufRBTree_steal_neighbours(self->tree.buf, &self->root, z, y);\n"
|
||||
// SPACE SPACE "if (x_adopter == z)\n"
|
||||
// SPACE SPACE SPACE "x_adopter = y;\n"
|
||||
// SPACE "}\n"
|
||||
// SPACE "U64 L = self->el.len;\n"
|
||||
// SPACE "if (L != z) {\n"
|
||||
// SPACE SPACE "BufRBTree_steal_neighbours(self->tree.buf, &self->root, L, z);\n"
|
||||
// SPACE SPACE "self->el.buf[z-1] = self->el.buf[L-1];\n"
|
||||
// SPACE SPACE "if (L == x)\n"
|
||||
// SPACE SPACE SPACE "x = z;\n"
|
||||
// SPACE SPACE "else if (L == x_adopter) \n"
|
||||
// SPACE SPACE SPACE "x_adopter = z;\n"
|
||||
// SPACE "}\n"
|
||||
// SPACE "self->tree.buf[x].parent = x_adopter;\n"
|
||||
// SPACE "self->tree.len--;\n"
|
||||
// SPACE "self->el.len--;\n"
|
||||
// SPACE "if (y_org_clr == RBTree_black)\n"
|
||||
// SPACE SPACE "BufRBTree_fix_after_delete(self->tree.buf, &self->root, x);\n"
|
||||
// "}\n\n",
|
||||
// set, set));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"bool %s_insert(%s* self, %v) {\n" /* set, set, taking_t_argument */
|
||||
SPACE "U64 col = %s_try_insert(self, key" "%s" ");\n" /* set, "" /, value */
|
||||
SPACE "if (col == 0)\n"
|
||||
SPACE SPACE "return true;\n"
|
||||
"%v" "%v" /* "" / dropping key, "" / dropping value */
|
||||
SPACE "return false;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_t_argument(op),
|
||||
set, op.V.len > 0 ? cstr(", value") : cstr(""),
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(key);\n", op.K),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(value);\n", op.V)));
|
||||
|
||||
// todo: write _erase_by_iter method
|
||||
|
||||
// todo: rewrite _erase using _erase_by_it
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"bool %s_erase(%s* self, %v key) {\n" /* set, set, taking_ref_k_argument */
|
||||
SPACE "U64 v = %s_find(self, key);\n" /* set */
|
||||
SPACE "if (v == 0)\n"
|
||||
SPACE SPACE "return false;\n"
|
||||
"%v" /* "" / op.K_drop(v->key) */
|
||||
"%v" /* "" / op.V_drop(v->value) */
|
||||
SPACE "BufRBTree_empty_index_erase(&self->tree, &self->root, v);\n"
|
||||
SPACE "self->el.buf[v - 1] = self->el.buf[self->el.len - 1];\n"
|
||||
SPACE "self->el.len--;\n"
|
||||
SPACE "return true;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op), set,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(
|
||||
SPACE "%s_drop(self->el.buf[v - 1]%s);\n", op.K, op.V.len > 0 ? cstr(".key") : cstr("")),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(self->el.buf[v - 1].value);\n", op.V)));
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_buf_rbtree_map__option_returned_ref_v(map_instantiation_op op, bool mut){
|
||||
assert(op.V.len > 0);
|
||||
if (op.v_integer)
|
||||
return VecU8_fmt("Option%s", op.V);
|
||||
return mut ? VecU8_fmt("OptionRefMut%s", op.V) : VecU8_fmt("OptionRef%s", op.V);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_buf_rbtree_map__some_ref_v(map_instantiation_op op, bool mut){
|
||||
assert(op.V.len > 0);
|
||||
if (op.v_integer)
|
||||
return VecU8_fmt("Some_%s(self->el.buf[cur - 1].value)", op.V);
|
||||
if (mut)
|
||||
return VecU8_fmt("Some_RefMut%s(&self->el.buf[cur - 1].value)", op.V);
|
||||
return VecU8_fmt("Some_Ref%s(&self->el.buf[cur - 1].value)", op.V);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_buf_rbtree_map__none_ref_v(map_instantiation_op op, bool mut){
|
||||
assert(op.V.len > 0);
|
||||
if (op.v_integer)
|
||||
return VecU8_fmt("None_%s()", op.V);
|
||||
return mut ? VecU8_fmt("None_RefMut%s()", op.V) : VecU8_fmt("None_Ref%s()", op.V) ;
|
||||
}
|
||||
|
||||
void codegen_append_buf_rbtree_map__method_at(VecU8* res, map_instantiation_op op, SpanU8 set, bool mut){
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"%v %s_%s(%s%s* self, %v key) {\n" /* option_returned_ref_t, set, mat/at, e/const, set, taking_ref_t_argument */
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur key < key */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return %v;\n" /* some_ref_t */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return %v;\n" /* none_ref_t */
|
||||
"}\n\n",
|
||||
codegen_buf_rbtree_map__option_returned_ref_v(op, mut), set, mut ? cstr("mat") : cstr("at"),
|
||||
mut ? cstr("") : cstr("const "), set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_buf_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_buf_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
codegen_buf_rbtree_map__some_ref_v(op, mut),
|
||||
codegen_buf_rbtree_map__none_ref_v(op, mut)
|
||||
));
|
||||
}
|
||||
|
||||
NODISCARD VecU8 get_name_of_buf_rbtree_set_structure(set_instantiation_op op){
|
||||
if (op.alternative_comp_set_name_embed.len)
|
||||
return VecU8_fmt("BufRBTreeBy%s_Set%s", op.alternative_comp_set_name_embed, op.T);
|
||||
return VecU8_fmt("BufRBTree_Set%s", op.T);
|
||||
}
|
||||
|
||||
/* src/l1_5/core/buff_rb_tree_node.h is a dependency of all instantiations of BufRBTree_Set template
|
||||
* Don't forget to include them
|
||||
* */
|
||||
NODISCARD VecU8 generate_buf_rbtree_Set_template_instantiation(set_instantiation_op op){
|
||||
set_instantiation_op_fix(&op);
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8 g_set = get_name_of_buf_rbtree_set_structure(op);
|
||||
SpanU8 set = VecU8_to_span(&g_set);
|
||||
|
||||
map_instantiation_op map_op = {.K = op.T,
|
||||
.k_integer = op.t_integer, .k_primitive = op.t_primitive, .k_clonable = op.t_clonable,
|
||||
.V = cstr(""), .v_primitive = true, .v_clonable = true,
|
||||
.alternative_less = op.alternative_less,
|
||||
.alternative_comp_map_name_embed = op.alternative_comp_set_name_embed, .guest_data_T = op.guest_data_T,
|
||||
};
|
||||
|
||||
codegen_append_buff_rbtree_map__structure_and_simplest_methods(&res, map_op, set, op.T);
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"const %s* %s_at_iter(const %s* self, U64 it) {\n" /* op.T, set, set */
|
||||
SPACE "assert(0 < it && it < self->tree.len);\n"
|
||||
SPACE "return &self->el.buf[it - 1];\n"
|
||||
"}\n\n",
|
||||
op.T, set, set));
|
||||
|
||||
VecU8_drop(g_set);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void generate_buf_rbtree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_buf_rbtree_Set_template_instantiation(op), get_name_of_buf_rbtree_set_structure(op));
|
||||
}
|
||||
|
||||
void generate_buf_rbtree_Set_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op
|
||||
){
|
||||
VecU8 all_dependencies = VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/buff_rb_tree_node.h")), dependencies);
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies,
|
||||
generate_buf_rbtree_Set_template_instantiation(op), get_name_of_buf_rbtree_set_structure(op));
|
||||
}
|
||||
|
||||
/* ========= Now we add Map<K, V> into the picture ======== */
|
||||
|
||||
void codegen_append_buff_rbtree_map__method_at_iter(VecU8* res, map_instantiation_op op, SpanU8 set, bool mut){
|
||||
assert(op.V.len > 0);
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"void %s_%s(%s%s* self, U64 it, %v* ret_key, %v* ret_value) {\n" /* set, method name, self access modifier, set, key ret ptr, value ret ptr */
|
||||
SPACE "assert(0 < it && it < self->tree.len);\n"
|
||||
SPACE "*ret_key = %s" "self->el.buf[it - 1].key;\n" /* epsilon / ampersand */
|
||||
SPACE "*ret_value = %s" "self->el.buf[it - 1].value;\n" /* epsilon / ampersand */
|
||||
"}\n\n",
|
||||
set, mut ? cstr("mat_iter") : cstr("at_iter"), mut ? cstr("") : cstr("const "), set,
|
||||
op.k_integer ? VecU8_from_span(op.K) : VecU8_fmt("const %s*", op.K),
|
||||
mut ? VecU8_fmt("%s*", op.V) : (op.v_integer ? VecU8_from_span(op.V) : VecU8_fmt("const %s*", op.V)),
|
||||
|
||||
op.k_integer ? cstr("") : cstr("&"), (op.v_integer && !mut) ? cstr("") : cstr("&")));
|
||||
}
|
||||
|
||||
NODISCARD VecU8 get_name_of_buf_rbtree_map_structure(map_instantiation_op op){
|
||||
if (op.alternative_comp_map_name_embed.len)
|
||||
return VecU8_fmt("BufRBTreeBy%s_Map%sTo%s", op.alternative_comp_map_name_embed, op.K, op.V);
|
||||
return VecU8_fmt("BufRBTree_Map%sTo%s", op.K, op.V);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_buf_rbtree_Map_template_instantiation(map_instantiation_op op){
|
||||
assert(op.V.len > 0);
|
||||
map_instantiation_op_fix(&op);
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8 map_g = get_name_of_buf_rbtree_map_structure(op);
|
||||
SpanU8 map = VecU8_to_span(&map_g);
|
||||
|
||||
VecU8 kvp_g = VecU8_fmt("KVP%sTo%s", op.K, op.V);
|
||||
codegen_append_buff_rbtree_map__structure_and_simplest_methods(&res, op, map, VecU8_to_span(&kvp_g));
|
||||
VecU8_drop(kvp_g);
|
||||
|
||||
// todo: write erase_substitute (only if v is not primitive) using try_insert
|
||||
|
||||
// todo: write pop_substitute using try_insert
|
||||
if (!op.v_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"bool %s_erase_substitute(%s* self, %s key, %s value) {\n" /* map, map, op.K, op.V */
|
||||
SPACE "U64 col = %s_try_insert(self, key, value);\n" /* map */
|
||||
SPACE "if (col == 0)\n"
|
||||
SPACE SPACE "return true;\n"
|
||||
"%v" "%v" /* "" / drop col->key, "" / drop col->value */
|
||||
SPACE "self->el.buf[col - 1].key = key;\n"
|
||||
SPACE "self->el.buf[col - 1].value = value;\n"
|
||||
SPACE "return false;\n"
|
||||
"}\n\n",
|
||||
map, map, op.K, op.V, map,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(self->el.buf[col - 1].key);\n", op.K),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(self->el.buf[col - 1].value);\n", op.V)));
|
||||
}
|
||||
|
||||
if (op.pop_substitute) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"Option%s %s_pop_substitute(%s* self, %s key, %s value) {\n" /* op.V, map, map, op.K, op.V */
|
||||
SPACE "U64 col = %s_try_insert(self, key, value);\n" /* map */
|
||||
SPACE "if (col == 0)\n"
|
||||
SPACE SPACE "return None_%s();\n" /* op.V */
|
||||
"%s saved = self->el.buf[col - 1].value;\n" /* op.V */
|
||||
"%v" /* "" / drop col->key */
|
||||
SPACE "self->el.buf[col - 1].key = key;\n"
|
||||
SPACE "self->el.buf[col - 1].value = value;\n"
|
||||
SPACE "return Some_%s(saved);\n" /* op.V */
|
||||
"}\n\n",
|
||||
op.V, map, map, op.K, op.V,
|
||||
map, op.V,
|
||||
op.V,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(self->el.buf[col - 1].key);\n", op.K),
|
||||
op.V));
|
||||
}
|
||||
|
||||
// todo: write _pop_by_iter method
|
||||
|
||||
// todo: write _pop method
|
||||
|
||||
if (op.at)
|
||||
codegen_append_buf_rbtree_map__method_at(&res, op, map, false);
|
||||
if (op.mat)
|
||||
codegen_append_buf_rbtree_map__method_at(&res, op, map, true);
|
||||
|
||||
/* These functions break my design and return answer through pointers given in arguments. For greater good ofk */
|
||||
codegen_append_buff_rbtree_map__method_at_iter(&res, op, map, false);
|
||||
codegen_append_buff_rbtree_map__method_at_iter(&res, op, map, true);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_buf_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_buf_rbtree_Map_template_instantiation(op), get_name_of_buf_rbtree_map_structure(op));
|
||||
}
|
||||
|
||||
void generate_buf_rbtree_Map_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, map_instantiation_op op
|
||||
){
|
||||
VecU8 all_dependencies = VecU8_fmt("%v%s\n",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/buff_rb_tree_node.h")), dependencies);
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies,
|
||||
generate_buf_rbtree_Map_template_instantiation(op), get_name_of_buf_rbtree_map_structure(op));
|
||||
}
|
||||
|
||||
#endif
|
||||
419
src/l1_5/codegen/rb_tree_set_map_template_inst.h
Normal file
419
src/l1_5/codegen/rb_tree_set_map_template_inst.h
Normal file
@ -0,0 +1,419 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_5_CODEGEN_RB_TREE_SET_MAP_TEMPLATE_INST_H
|
||||
#define PROTOTYPE1_SRC_L1_5_CODEGEN_RB_TREE_SET_MAP_TEMPLATE_INST_H
|
||||
|
||||
#include "all_set_map_templ_util_inst.h"
|
||||
|
||||
/* When key is given by value into some method of Buff_RBTreeSet */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_key_value_NOT_EQUAL_element(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("key != self->el.buf[cur - 1]");
|
||||
return VecU8_fmt("!%s_equal_%s(&key, &self->el.buf[cur - 1])", op.T, op.T);
|
||||
}
|
||||
|
||||
/* When key is given by value into some method of Buff_RBTreeSet */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_key_value_LESS_element(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("key < self->el.buf[cur - 1]");
|
||||
return VecU8_fmt("%s_less_%s(&key, &self->el.buf[cur - 1])", op.T, op.T);
|
||||
}
|
||||
|
||||
/* When key is given by ref into some method of Buff_RBTreeSet
|
||||
* Ofk when op.T is integer, argument is still taken by a value */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_key_ref_NOT_EQUAL_element(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("key != self->el.buf[cur - 1]");
|
||||
return VecU8_fmt("!%s_equal_%s(key, &self->el.buf[cur - 1])", op.T, op.T);
|
||||
}
|
||||
|
||||
/* When key is given by a pointer into some method of Buff_RBTreeSet */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_key_ref_EQUAL_element(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("key == self->el.buf[cur - 1]");
|
||||
return VecU8_fmt("%s_equal_%s(ref, &self->el.buf[cur - 1])", op.T, op.T);
|
||||
}
|
||||
|
||||
/* When key is given by a pointer into some method of Buff_RBTreeSet */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_key_ref_LESS_element(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("key < self->el.buf[cur - 1]");
|
||||
return VecU8_fmt("%s_less_%s(key, &self->el.buf[cur - 1])", op.T, op.T);
|
||||
}
|
||||
|
||||
/* When method returns constant pointer to found key (wrapped in Option) we will use this type
|
||||
* Ofcourse, it can turn out that it is not generated. So be careful and generate it by yourself
|
||||
*/
|
||||
NODISCARD VecU8 codegen_rb_tree_set_option_returned_ref_t(set_instantiation_op op){
|
||||
/* Constant pointer to an integer is an integer */
|
||||
return op.t_integer ? VecU8_fmt("Option%s", op.T) : VecU8_fmt("OptionRef%s", op.T);
|
||||
}
|
||||
|
||||
/* Suppose some method returns pointer to key (ofc wrapped in option). And we found what to return
|
||||
* we return it from self->el array */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_some_ref_t(set_instantiation_op op, SpanU8 index_var_name){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("Some_%s(self->el[%s - 1])", op.T, index_var_name);
|
||||
return VecU8_fmt("Some_Ref%s(&self->el[%s - 1])", op.T, index_var_name);
|
||||
}
|
||||
|
||||
/* Suppose some method returns pointer to key (ofc wrapped in option). But this time we found nothing */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_none_ref_t(set_instantiation_op op){
|
||||
if (op.t_integer)
|
||||
return VecU8_fmt("Some_%s()", op.T);
|
||||
return VecU8_fmt("Some_Ref%s()", op.T);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_rb_tree_set_option_returned_value_t(set_instantiation_op op){
|
||||
return VecU8_fmt("Option%s", op.T);
|
||||
}
|
||||
|
||||
/* Suppose some method returns an owned key (by value, ofc wrapped in option). If we DID found something,
|
||||
* we construct Option_Some */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_some_t(set_instantiation_op op, SpanU8 val_giving_expr){
|
||||
return VecU8_fmt("Some_%s(%s)", op.T, val_giving_expr);
|
||||
}
|
||||
|
||||
/* Suppose some method returns an owned key (by value, ofc wrapped in option). But this time we found nothing */
|
||||
NODISCARD VecU8 codegen_rb_tree_set_none_t(set_instantiation_op op){
|
||||
return VecU8_fmt("None_%s()", op.T);
|
||||
}
|
||||
|
||||
/* Suppose some method (like _erase() or _pop(), or _find(), or _at(), takes constant reference to key T
|
||||
* This function tells how to write type of this argument. Basically it is needed to take into account that
|
||||
* integer is better than pointer to integer. (Though, notice that _pop family of methods don't exist for
|
||||
* sets of integers
|
||||
*/
|
||||
NODISCARD VecU8 codegen_rb_tree_set_taking_ref_t_argument(set_instantiation_op op){
|
||||
return !op.t_integer ? VecU8_fmt("const %s*", op.T) : VecU8_from_span(op.T);
|
||||
}
|
||||
|
||||
/* Generates methods _insert() _pop_substitute() _erase_substitute() for SetT
|
||||
* Takes ownership of strings Tc, Fc */
|
||||
void codegen_append_rb_tree_set_insert_kind_method(
|
||||
VecU8* result, set_instantiation_op op, SpanU8 set, SpanU8 method_name, VecU8 RT, VecU8 Tc, VecU8 Fc
|
||||
){
|
||||
VecU8 Tc_root = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 2);
|
||||
VecU8 Tc_on_left = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 4);
|
||||
VecU8 Tc_on_right = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc), 4);
|
||||
VecU8 Fc_exists = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Fc), 1);
|
||||
VecU8_drop(Tc);
|
||||
VecU8_drop(Fc);
|
||||
|
||||
VecU8_append_vec(result, VecU8_fmt(
|
||||
"%v %s_%s(%s* self, %s key) {\n" /* set, set, op.T */
|
||||
SPACE "if (self->root == 0) {\n"
|
||||
SPACE SPACE "assert(self->tree.len == 1);\n"
|
||||
SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.color = RBTree_black});\n"
|
||||
SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
|
||||
SPACE SPACE "self->root = 1;\n"
|
||||
"%v" /* Tc_root */
|
||||
/* Should have returned by now in Tc*/
|
||||
SPACE "}\n"
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (%v) {\n" /* el[cur] != key */
|
||||
SPACE SPACE "if (%v) {\n" /* key < el[cur] */
|
||||
SPACE SPACE SPACE "if (self->tree.buf[cur].left != 0) {\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE SPACE "} else { \n"
|
||||
/* We are inserting to the left of cur */
|
||||
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
|
||||
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.parent = cur, .color = RBTree_red});\n"
|
||||
SPACE SPACE SPACE SPACE "self->tree.buf[cur].left = n;\n"
|
||||
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
|
||||
SPACE SPACE SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
|
||||
"%v" /* Tc_on_left */
|
||||
/* Should have returned by now in Tc*/
|
||||
SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "if (self->tree.buf[cur].right != 0) {\n"
|
||||
SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE SPACE "} else {\n"
|
||||
/* We are inserting to the right of cur */
|
||||
SPACE SPACE SPACE SPACE "U64 n = self->tree.len;\n"
|
||||
SPACE SPACE SPACE SPACE "VecRBTreeNode_append(&self->tree, (RBTreeNode){.parent = cur, .color = RBTree_red});\n"
|
||||
SPACE SPACE SPACE SPACE "self->tree.buf[cur].right = n;\n"
|
||||
SPACE SPACE SPACE SPACE "RBTree_fix_after_insert(self->tree.buf, &self->root, n);\n"
|
||||
SPACE SPACE SPACE SPACE "Vec%s_append(&self->el, key);\n" /* op.T */
|
||||
"%v" /* Tc_on_right */
|
||||
/* Should have returned by now in Tc*/
|
||||
SPACE SPACE SPACE "}\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
"%v" /* Fc_exists */
|
||||
/* Should have returned by now in Tc*/
|
||||
"}\n\n",
|
||||
RT, set, method_name, set, op.T, op.T, Tc_root,
|
||||
codegen_rb_tree_set_key_value_NOT_EQUAL_element(op),
|
||||
codegen_rb_tree_set_key_value_LESS_element(op),
|
||||
op.T, Tc_on_left, op.T, Tc_on_right, Fc_exists
|
||||
));
|
||||
}
|
||||
|
||||
void codegen_append_rb_tree_set_erase_kind_method(
|
||||
VecU8* result, set_instantiation_op op, SpanU8 set, SpanU8 method_name, VecU8 RT,
|
||||
VecU8 Fc, VecU8 Tc_cur_available, VecU8 Tc_returning
|
||||
){
|
||||
VecU8 not_found_case = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Fc), 3);
|
||||
VecU8 saving_prev = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc_cur_available), 1);
|
||||
VecU8 ret_found_case = prepend_spaces_to_SpanU8_lines(VecU8_to_span(&Tc_returning), 1);
|
||||
VecU8_drop(Fc);
|
||||
VecU8_drop(Tc_cur_available);
|
||||
VecU8_drop(Tc_returning);
|
||||
|
||||
VecU8_append_vec(result, VecU8_fmt(
|
||||
"%v %s_%s(%s* self, %v key) {\n" /* RT, set, method_name, set, taking_ref_t_argument */
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (true){\n"
|
||||
SPACE SPACE "if (cur == 0) {\n"
|
||||
"%v" /* not_found_case */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE SPACE "if (%v)\n" /* key_ref_EQUAL_element */
|
||||
SPACE SPACE SPACE "break;\n"
|
||||
SPACE SPACE "if (%v)\n" /* key_ref_LESS_element */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "else\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE "}\n"
|
||||
"%v" /* saving_prev */
|
||||
SPACE "U64 z = cur;\n"
|
||||
SPACE "U64 y = (self->tree.buf[z].left == 0 || self->tree.buf[z].right == 0) ? z : RBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[z].right);\n"
|
||||
SPACE "U64 x = self->tree.buf[y].left != 0 ? self->tree.buf[y].left : self->tree.buf[y].right;\n"
|
||||
SPACE "assert(x != y && x != z);\n"
|
||||
SPACE "U64 x_adopter = self->tree.buf[y].parent;\n"
|
||||
SPACE "self->tree.buf[x].parent = x_adopter;\n"
|
||||
SPACE "if (x_adopter == 0)\n"
|
||||
SPACE SPACE "self->root = x;\n"
|
||||
SPACE "else if (self->tree.buf[x_adopter].left == y)\n"
|
||||
SPACE SPACE "self->tree.buf[x_adopter].left = x;\n"
|
||||
SPACE "else\n"
|
||||
SPACE SPACE "self->tree.buf[x_adopter].right = x;\n"
|
||||
SPACE "RBTreeColor y_org_clr = self->tree.buf[y].color;\n"
|
||||
SPACE "if (z != y) {\n"
|
||||
SPACE SPACE "RBTree_steal_neighbours(self->tree.buf, &self->root, z, y);\n"
|
||||
SPACE SPACE "if (x_adopter == z)\n"
|
||||
SPACE SPACE SPACE "x_adopter = y;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "U64 L = self->el.len;\n"
|
||||
SPACE "if (L != z) {\n"
|
||||
SPACE SPACE "RBTree_steal_neighbours(self->tree.buf, &self->root, L, z);\n"
|
||||
SPACE SPACE "self->el.buf[z-1] = self->el.buf[L-1];\n"
|
||||
SPACE SPACE "if (L == x)\n"
|
||||
SPACE SPACE SPACE "x = z;\n"
|
||||
SPACE SPACE "else if (L == x_adopter) \n"
|
||||
SPACE SPACE SPACE "x_adopter = z;\n"
|
||||
SPACE "}\n"
|
||||
SPACE "self->tree.buf[x].parent = x_adopter;\n"
|
||||
SPACE "self->tree.len--;\n"
|
||||
SPACE "self->el.len--;\n"
|
||||
SPACE "if (y_org_clr == RBTree_black)\n"
|
||||
SPACE SPACE "RBTree_fix_after_delete(self->tree.buf, &self->root, x);\n"
|
||||
"%v" /* ret_found_case */
|
||||
"}\n\n",
|
||||
RT, set, method_name, set, codegen_rb_tree_set_taking_ref_t_argument(op),
|
||||
not_found_case,
|
||||
codegen_rb_tree_set_key_ref_EQUAL_element(op),
|
||||
codegen_rb_tree_set_key_ref_LESS_element(op),
|
||||
saving_prev,
|
||||
ret_found_case
|
||||
));
|
||||
}
|
||||
|
||||
/* src/l1_5/core/rb_tree_node.h is a dependency of all instantiations of rb_tree_set template
|
||||
* Don't forget to include them
|
||||
*/
|
||||
NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op op){
|
||||
set_instantiation_op_fix(&op);
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8 g_set = VecU8_fmt("BuffRBTree_Set%s", op.T);
|
||||
SpanU8 set = VecU8_to_span(&g_set);
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "VecRBTreeNode tree;\n"
|
||||
SPACE "U64 root;\n"
|
||||
SPACE "Vec%s el;\n"
|
||||
"} %s;\n\n", op.T, set));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new() {\n"
|
||||
SPACE "return (%s){.tree = VecRBTreeNode_new_zeroinit(1), .root = 0, .el = Vec%s_new()};\n"
|
||||
"}\n\n", set, set, set, op.T));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void %s_drop(%s self) {\n"
|
||||
SPACE "VecRBTreeNode_drop(self.tree);\n"
|
||||
SPACE "Vec%s_drop(self.el);\n"
|
||||
"}\n\n", set, set, op.T));
|
||||
|
||||
/* Method _insert() does not try to replace the existing element with equal key,
|
||||
* it returns true if insertion was done, false if collision happened and key was not inserted */
|
||||
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("insert"), vcstr("bool"),
|
||||
vcstr("return true;\n"),
|
||||
op.t_integer ?
|
||||
vcstr("return false;\n") :
|
||||
VecU8_fmt(
|
||||
"%s_drop(key);\n" /* op.T */
|
||||
"return false;\n",
|
||||
op.T));
|
||||
|
||||
if (!op.t_integer) {
|
||||
/* Method _erase_substitute() is a more bald version of _insert() method. It will substitute
|
||||
* previous element with equal key it it was found. It still returns true if no conflict has happened, though */
|
||||
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("erase_substitute"), vcstr("bool"),
|
||||
vcstr("return true;\n"),
|
||||
op.t_integer ?
|
||||
vcstr("return false;\n") :
|
||||
VecU8_fmt(
|
||||
"%s_drop(self->el.buf[cur - 1]);\n"
|
||||
"self->el.buf[cur - 1] = key;\n"
|
||||
"return false;\n"
|
||||
));
|
||||
|
||||
/* Method _pop_substitute() is just like _erase_substitute(), but it returns a previous key
|
||||
* that was overthrown after collision. Wrapped in option, ofcourse */
|
||||
codegen_append_rb_tree_set_insert_kind_method(&res, op, set, cstr("pop_substitute"),
|
||||
codegen_rb_tree_set_option_returned_value_t(op),
|
||||
VecU8_fmt("return %v;\n", codegen_rb_tree_set_none_t(op)),
|
||||
VecU8_fmt(
|
||||
"%s old = self->el.buf[cur - 1];\n" /* op.T */
|
||||
"self->el.buf[cur - 1] = key;\n"
|
||||
"return %v;", /* Some_T(old) */
|
||||
op.T, codegen_rb_tree_set_some_t(op, cstr("old"))));
|
||||
}
|
||||
|
||||
codegen_append_rb_tree_set_erase_kind_method(&res, op, set, cstr("erase"), vcstr("bool"),
|
||||
vcstr("return false;\n"),
|
||||
op.t_primitive ? vcstr("") : VecU8_fmt("%s_drop(self->el.buf[cur - 1]);\n", op.T),
|
||||
vcstr("return true;\n"));
|
||||
|
||||
if (!op.t_integer) {
|
||||
codegen_append_rb_tree_set_erase_kind_method(&res, op, set, cstr("pop"),
|
||||
codegen_rb_tree_set_option_returned_value_t(op),
|
||||
VecU8_fmt("return %v;\n", codegen_rb_tree_set_none_t(op)),
|
||||
VecU8_fmt("%s saved = self->el[cur - 1];\n", op.T),
|
||||
VecU8_fmt("return %v;\n", codegen_rb_tree_set_some_t(op, cstr("saved")))
|
||||
);
|
||||
}
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"U64 %s_find(const %s* self, %v key) {\n" /* set, set taking_ref_t_argument */
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0 && %v) {\n" /* key reference not equal cur element */
|
||||
SPACE SPACE "if (%v) {\n" /* key reference less than cue element */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return cur;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rb_tree_set_taking_ref_t_argument(op),
|
||||
codegen_rb_tree_set_key_ref_NOT_EQUAL_element(op),
|
||||
codegen_rb_tree_set_key_ref_LESS_element(op)
|
||||
));
|
||||
|
||||
if (!op.t_integer) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%v %s_at(const %s* self, %v key) {\n" /* option_returned_ref_t, set, set, taking_ref_t_argument */
|
||||
SPACE "U64 cur = self->root;\n"
|
||||
SPACE "while (cur != 0) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */
|
||||
SPACE SPACE SPACE "return %v;\n" /* some_ref_t */
|
||||
SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return %v;\n" /* none_ref_t */
|
||||
"}\n\n",
|
||||
codegen_rb_tree_set_option_returned_ref_t(op), set, set, codegen_rb_tree_set_taking_ref_t_argument(op),
|
||||
codegen_rb_tree_set_key_ref_EQUAL_element(op),
|
||||
codegen_rb_tree_set_some_ref_t(op, cstr("cur")),
|
||||
codegen_rb_tree_set_key_ref_LESS_element(op),
|
||||
codegen_rb_tree_set_none_ref_t(op)
|
||||
));
|
||||
}
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"NODISCARD %s %s_clone(const %s* self){\n"
|
||||
SPACE "return (%s){.tree = VecRBTreeNode_clone(&self->tree), .root = self->root,\n"
|
||||
SPACE SPACE "Vec%s_clone(&self->el)};\n"
|
||||
"}\n\n", set, set, set, set, op.T));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"U64 %s_find_next(const %s* self, U64 x){\n"
|
||||
SPACE "assert(x != 0 && x < self->tree.len);\n"
|
||||
SPACE "if (self->tree.buf[x].right != 0)\n"
|
||||
SPACE SPACE "return RBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[x].right);\n"
|
||||
SPACE "while (true) {\n"
|
||||
SPACE SPACE "U64 p = self->tree.buf[x].parent;\n"
|
||||
SPACE SPACE "if (p == 0)\n"
|
||||
SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE "if (self->tree.buf[p].left == x)\n"
|
||||
SPACE SPACE SPACE "return p;\n"
|
||||
SPACE SPACE "x = p;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"U64 %s_find_prev(const %s* self, U64 x){\n"
|
||||
SPACE "assert(x != 0 && x < self->tree.len);\n"
|
||||
SPACE "if (self->tree.buf[x].left != 0)\n"
|
||||
SPACE SPACE "return RBTree_maximum_in_subtree(self->tree.buf, self->tree.buf[x].left);\n"
|
||||
SPACE "while (true) {\n"
|
||||
SPACE SPACE "U64 p = self->tree.buf[x].parent;\n"
|
||||
SPACE SPACE "if (p == 0)\n"
|
||||
SPACE SPACE SPACE "return 0;\n"
|
||||
SPACE SPACE "if (self->tree.buf[p].right == x)\n"
|
||||
SPACE SPACE SPACE "return p;\n"
|
||||
SPACE SPACE "x = p;\n"
|
||||
SPACE "}\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"U64 %s_find_min(const %s* self) {\n"
|
||||
SPACE "return self->root != 0 ? RBTree_minimum_in_subtree(self->tree.buf, self->root) : 0;\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"U64 %s_find_max(const %s* self) {\n"
|
||||
SPACE "return self->root != 0 ? RBTree_maximum_in_subtree(self->tree.buf, self->root) : 0;\n"
|
||||
"}\n\n", set, set));
|
||||
|
||||
// todo: continue from here. Implement method _pop_and_substitute()
|
||||
|
||||
// todo: All the other methods are secondary in importance
|
||||
|
||||
VecU8_drop(g_set);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void generate_rb_tree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, option_template_instantiation_op op) {
|
||||
VecU8 text = VecU8_from_cstr("/* Automatically generated file. Do not edit it.\n"
|
||||
" * Do not include it in more than one place */\n\n");
|
||||
VecU8_append_vec(&text, generate_OptionT_struct_and_methods(op));
|
||||
VecU8 nt_path = VecU8_fmt("%s/eve/%s/BuffRBTree_Set%s%c", layer, bonus_ns, op.T, 0);
|
||||
write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text));
|
||||
VecU8_drop(nt_path);
|
||||
VecU8_drop(text);
|
||||
}
|
||||
|
||||
void generate_rb_tree_Set_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op
|
||||
){
|
||||
assert(layer.len > 1);
|
||||
VecU8 path = VecU8_fmt("%s/%s%sBuffRBTree_Set%s.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), op.T);
|
||||
GeneratedHeader head = begin_header(VecU8_to_span(&path));
|
||||
VecU8_drop(path);
|
||||
VecU8_append_span(&head.result, cstr("#include \"../../"));
|
||||
int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns);
|
||||
for (int i = 0; i < to_my_layer; i++)
|
||||
VecU8_append_span(&head.result, cstr("../"));
|
||||
VecU8_append_span(&head.result, cstr("src/l1_5/core/rb_tree_node.h\"\n"));
|
||||
VecU8_append_span(&head.result, dependencies);
|
||||
VecU8_append_span(&head.result, cstr("\n\n"));
|
||||
VecU8_append_vec(&head.result, generate_rb_tree_Set_template_instantiation(op));
|
||||
finish_header(head);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,433 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_codegen_rbtree_set_map_template_inst_h
|
||||
#define prototype1_src_l1_5_codegen_rbtree_set_map_template_inst_h
|
||||
|
||||
#include "all_set_map_templ_util_inst.h"
|
||||
|
||||
NODISCARD VecU8 codegen_rbtree__node_struct_name(map_instantiation_op op){
|
||||
return (op.V.len > 0) ? VecU8_fmt("RBTreeNode_KVP%sTo%s", op.K, op.V) : VecU8_fmt("RBTreeNode_%s", op.K);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 codegen_rbtree__node_structure(map_instantiation_op op){
|
||||
map_instantiation_op_fix(&op);
|
||||
VecU8 node_g = codegen_rbtree__node_struct_name(op);
|
||||
SpanU8 node = VecU8_to_span(&node_g);
|
||||
VecU8 res = VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "RBTreeNode base;\n"
|
||||
SPACE "%s key;\n" /* op.K*/
|
||||
"%v" /* "" / op.V value; */
|
||||
"} %s;\n\n", /* node */
|
||||
op.K, op.V.len > 0 ? VecU8_fmt(SPACE "%s value;\n", op.V) : vcstr(""),
|
||||
node);
|
||||
VecU8_drop(node_g);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
NODISCARD VecU8 codegen_rbtree_map__exp_passing_cur_key(map_instantiation_op op){
|
||||
return VecU8_fmt("%s" "((%v*)cur)->key", op.k_integer ? cstr("") : cstr("&"), codegen_rbtree__node_struct_name(op));
|
||||
}
|
||||
|
||||
void codegen_append_rbtree_map__structure_and_simplest_methods(
|
||||
VecU8* res, map_instantiation_op op, SpanU8 set, SpanU8 TT
|
||||
){
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "RBTreeNode* root;\n"
|
||||
SPACE "RBTreeNode* NIL;\n"
|
||||
"%v" /* "" / guest field */
|
||||
"} %s;\n\n",
|
||||
op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest;\n", op.guest_data_T),
|
||||
set));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"NODISCARD %s %s_new(" "%v" ") {\n" /* set, set, "" / GT guest */
|
||||
/* Only color field initialization is important (should be 0) */
|
||||
SPACE "RBTreeNode* NIL = (RBTreeNode*)safe_calloc(1, sizeof(RBTreeNode));\n"
|
||||
SPACE "return (%s){.root = NIL, .NIL = NIL" "%s" "};\n" /* set, "" / , .guest = guest */
|
||||
"}\n\n",
|
||||
set, set, op.guest_data_T.len == 0 ? vcstr("") : VecU8_fmt("%s guest", op.guest_data_T),
|
||||
set, op.guest_data_T.len == 0 ? cstr("") : cstr(", .guest = guest")));
|
||||
|
||||
// todo: figure out mutability restrictions crrp later
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_min(const %s* self) {\n" /* TT, set, set */
|
||||
SPACE "if (self->root == self->NIL)\n"
|
||||
SPACE SPACE "return NULL;\n"
|
||||
SPACE "return (RBTreeNode_%s*)RBTreeNode_minimum_in_subtree(self->root, self->NIL);\n" /* TT */
|
||||
"}\n\n", TT, set, set, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_max(const %s* self) {\n" /* TT, set, set */
|
||||
SPACE "if (self->root == self->NIL)\n"
|
||||
SPACE SPACE "return NULL;\n"
|
||||
SPACE "return (RBTreeNode_%s*)RBTreeNode_maximum_in_subtree(self->root, self->NIL);\n" /* TT */
|
||||
"}\n\n", TT, set, set, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_next(const %s* self, RBTreeNode_%s* x){\n" /* TT, set, set, TT */
|
||||
SPACE "return (RBTreeNode_%s *)RBTreeNode_find_next((RBTreeNode*)x, self->NIL);\n" /* TT */
|
||||
"}\n\n", TT, set, set, TT, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_prev(const %s* self, RBTreeNode_%s* x){\n" /* TT, set, set, TT */
|
||||
SPACE "return (RBTreeNode_%s *)RBTreeNode_find_prev((RBTreeNode*)x, self->NIL);\n" /* TT */
|
||||
"}\n\n", TT, set, set, TT, TT));
|
||||
|
||||
/* Here we read and write something to ->left, ->right field of NIL sentinel node.
|
||||
* These fields are correct pointers (NULL), so everything is ok */
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"void %s_drop(%s self){\n" /* set, set */
|
||||
SPACE "RBTreeNode* cur = self.root;\n"
|
||||
SPACE "while (cur != self.NIL){\n"
|
||||
SPACE SPACE "if (cur->left != self.NIL) {\n"
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (cur->right != self.NIL) {\n"
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
/* This is actually safe, although cur->parent may be self.NIL */
|
||||
SPACE SPACE SPACE "if (cur->parent->left == cur)\n"
|
||||
SPACE SPACE SPACE SPACE "cur->parent->left = self.NIL;\n"
|
||||
SPACE SPACE SPACE "else"
|
||||
SPACE SPACE SPACE SPACE "cur->parent->right = self.NIL;\n"
|
||||
SPACE SPACE SPACE "RBTreeNode* parent = cur->parent;\n"
|
||||
"%v" /* "" / tabulation op.K_drop((RBTreeNode_TT*)cur->key */
|
||||
"%v" /* "" / tabulation op.V_drop((RBTreeNode_TT*)cur->value */
|
||||
SPACE SPACE SPACE "free((void*)cur);\n"
|
||||
SPACE SPACE SPACE "cur = parent;\n"
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "free(self.NIL);\n"
|
||||
"}\n\n", set, set,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE SPACE "%s_drop(((RBTreeNode_%s*)cur)->key);\n", op.K, TT),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE SPACE "%s_drop(((RBTreeNode_%s*)cur)->value);\n", op.V, TT)
|
||||
));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_k_argument */
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return NULL;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_max_less(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */
|
||||
SPACE "RBTreeNode_%s* last_less = NULL;\n" /* TT */
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "last_less = (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE SPACE "if (cur == self->NIL)\n"
|
||||
SPACE SPACE SPACE SPACE "return last_less;\n"
|
||||
SPACE SPACE SPACE "while (cur->right != self->NIL)\n"
|
||||
SPACE SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_less;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT,
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
TT, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_max_less_or_eq(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */
|
||||
SPACE "RBTreeNode_%s* last_less = NULL;\n" /* TT */
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "last_less = (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_less;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT,
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
TT, TT));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_min_grtr(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */
|
||||
SPACE "RBTreeNode_%s* last_grtr = NULL;\n" /* TT */
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "last_grtr = (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE SPACE "if (cur == self->NIL)\n"
|
||||
SPACE SPACE SPACE SPACE "return last_grtr;\n"
|
||||
SPACE SPACE SPACE "while (cur->left != self->NIL)\n"
|
||||
SPACE SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_grtr;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT,
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
TT,
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
TT));
|
||||
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"RBTreeNode_%s* %s_find_min_grtr_or_eq(const %s* self, %v key) {\n" /* TT, set, set, taking_ref_t_argument */
|
||||
SPACE "RBTreeNode_%s* last_grtr = NULL;\n" /* TT */
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL) {\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "last_grtr = (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s*)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "return last_grtr;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_ref_k_argument(op), TT,
|
||||
codegen_rbtree_map__less(op, vcstr("key"), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
TT,
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), vcstr("key")),
|
||||
TT));
|
||||
|
||||
// todo: implement it like i deed in BufRBTree
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
/* This method is unsafe. Arguments key, value will be taken if 0 is returned,
|
||||
* or left on their place if not-0 is returned */
|
||||
"/* UNSAFE */\n"
|
||||
"NODISCARD RBTreeNode_%s* %s_try_insert(%s* self, %v) {\n" /* TT, set, set, taking_t_argument */
|
||||
SPACE "RBTreeNode** surprising = &self->root;\n"
|
||||
SPACE "RBTreeNode* prev = self->NIL;\n"
|
||||
SPACE "RBTreeNode* cur = self->root;\n"
|
||||
SPACE "while (cur != self->NIL){\n"
|
||||
SPACE SPACE "prev = cur;\n"
|
||||
SPACE SPACE "if (%v) {\n" /* key < cur->key */
|
||||
SPACE SPACE SPACE "surprising = &cur->left;\n"
|
||||
SPACE SPACE SPACE "cur = cur->left;\n"
|
||||
SPACE SPACE "} else if (%v) {\n" /* cur->key < key */
|
||||
SPACE SPACE SPACE "surprising = &cur->right;\n"
|
||||
SPACE SPACE SPACE "cur = cur->right;\n"
|
||||
SPACE SPACE "} else {\n"
|
||||
SPACE SPACE SPACE "return (RBTreeNode_%s *)cur;\n" /* TT */
|
||||
SPACE SPACE "}\n"
|
||||
SPACE "}\n"
|
||||
SPACE "RBTreeNode_%s* new_node = (RBTreeNode_%s *)safe_malloc(sizeof(RBTreeNode_%s));\n" /* TT, TT, TT */
|
||||
SPACE "*new_node = (RBTreeNode_%s){ .base.parent = prev,\n" /* TT */
|
||||
SPACE SPACE ".base.left = self->NIL, .base.right = self->NIL, .base.color = RBTREE_RED,\n"
|
||||
SPACE SPACE ".key = key" "%s" "};\n" /* "" / ,.value = value */
|
||||
SPACE "*surprising = (RBTreeNode*)new_node;\n"
|
||||
SPACE "RBTree_fix_after_insert(&self->root, self->NIL, (RBTreeNode*)new_node);\n"
|
||||
SPACE "return NULL;\n"
|
||||
"}\n\n",
|
||||
TT, set, set, codegen_rbtree_map__taking_t_argument(op),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_key_val(op), codegen_rbtree_map__exp_passing_cur_key(op)),
|
||||
codegen_rbtree_map__less(op, codegen_rbtree_map__exp_passing_cur_key(op), codegen_rbtree_map__exp_passing_key_val(op)),
|
||||
TT,
|
||||
TT, TT, TT,
|
||||
TT, op.V.len == 0 ? cstr("") : cstr(", .value = value")));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"bool %s_insert(%s* self, %v){\n" /* set, set, taking_t_argument */
|
||||
SPACE "RBTreeNode_%s* col = %s_try_insert(self, key" "%s" ");\n" /* TT, set, "" /, value */
|
||||
SPACE "if (col == NULL)\n"
|
||||
SPACE SPACE "return true;\n"
|
||||
"%v" "%v" /* "" / dropping key, "" / dropping value */
|
||||
SPACE "return false;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_t_argument(op),
|
||||
TT, set, op.V.len > 0 ? cstr(", value") : cstr(""),
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(key);\n", op.K),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(value);\n", op.V)));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"void %s_erase_by_iter(%s* self, RBTreeNode_%s* it) {\n" /* set, set, TT */
|
||||
SPACE "assert(it != NULL);\n"
|
||||
"%v" /* "" / op.K_drop(it->key) */
|
||||
"%v" /* "" / op.V_drop(it->value) */
|
||||
SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, (RBTreeNode*)it);\n"
|
||||
SPACE "free(it);\n"
|
||||
"}\n\n",
|
||||
set, set, TT,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(it->key);\n", op.K),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(it->value);\n", op.V)));
|
||||
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"bool %s_erase(%s* self, %v key) {\n" /* set, set, taking_ref_k_argument */
|
||||
SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* TT, set */
|
||||
SPACE "if (v == NULL)\n"
|
||||
SPACE SPACE "return false;\n"
|
||||
SPACE "%s_erase_by_iter(self, v);\n" /* set */
|
||||
SPACE "return true;\n"
|
||||
"}\n\n",
|
||||
set, set, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
TT, set, set));
|
||||
}
|
||||
|
||||
|
||||
NODISCARD VecU8 get_name_of_rbtree_set_structure(set_instantiation_op op){
|
||||
if (op.alternative_comp_set_name_embed.len > 0)
|
||||
return VecU8_fmt("RBTreeBy%s_Set%s", op.alternative_comp_set_name_embed, op.T);
|
||||
return VecU8_fmt("RBTree_Set%s", op.T);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_rbtree_Set_template_instantiation(set_instantiation_op op, bool generate_node_struct){
|
||||
set_instantiation_op_fix(&op);
|
||||
map_instantiation_op map_op = {
|
||||
.K = op.T, .k_integer = op.t_integer, .k_primitive = op.t_primitive, .k_clonable = op.t_clonable,
|
||||
.V = cstr(""), .v_primitive = true, .v_clonable = true,
|
||||
.alternative_comp_map_name_embed = op.alternative_comp_set_name_embed, .alternative_less = op.alternative_less,
|
||||
.guest_data_T = op.guest_data_T
|
||||
};
|
||||
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8 set_g = get_name_of_rbtree_set_structure(op);
|
||||
if (generate_node_struct)
|
||||
VecU8_append_vec(&res, codegen_rbtree__node_structure(map_op));
|
||||
codegen_append_rbtree_map__structure_and_simplest_methods(&res, map_op, VecU8_to_span(&set_g), op.T);
|
||||
VecU8_drop(set_g);
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_rbtree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op, bool generate_node_struct) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_rbtree_Set_template_instantiation(op, generate_node_struct), get_name_of_rbtree_set_structure(op));
|
||||
}
|
||||
|
||||
void generate_rbtree_Set_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op, bool generate_node_struct
|
||||
){
|
||||
VecU8 all_dependencies = VecU8_fmt("%v%s",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/rb_tree_node.h")), dependencies);
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies,
|
||||
generate_rbtree_Set_template_instantiation(op, generate_node_struct), get_name_of_rbtree_set_structure(op));
|
||||
}
|
||||
|
||||
|
||||
/* Don't forget to do the map stuff, Set is not enough */
|
||||
|
||||
NODISCARD VecU8 get_name_of_rbtree_map_structure(map_instantiation_op op){
|
||||
if (op.alternative_comp_map_name_embed.len > 0)
|
||||
return VecU8_fmt("RBTreeBy%s_Map%sTo%s", op.alternative_comp_map_name_embed, op.K, op.V);
|
||||
return VecU8_fmt("RBTree_Map%sTo%s", op.K, op.V);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op op, bool generate_node_struct){
|
||||
map_instantiation_op_fix(&op);
|
||||
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8 map_g = get_name_of_rbtree_map_structure(op);
|
||||
SpanU8 map = VecU8_to_span(&map_g);
|
||||
VecU8 kvp_g = VecU8_fmt("KVP%sTo%s", op.K, op.V);
|
||||
SpanU8 kvp = VecU8_to_span(&kvp_g);
|
||||
|
||||
if (generate_node_struct)
|
||||
VecU8_append_vec(&res, codegen_rbtree__node_structure(op));
|
||||
codegen_append_rbtree_map__structure_and_simplest_methods(&res, op, map, kvp);
|
||||
|
||||
if (op.pop_substitute) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"%s" "Option%s %s_pop_substitute(%s* self, %s key, %s value) {\n" /* "" / NODISCARD , op.V, map, map, op.K, op.V */
|
||||
/* Using unsafe method with conditional ownership transfer */
|
||||
SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */
|
||||
SPACE "if (col == NULL) {\n"
|
||||
SPACE SPACE "return None_%s();\n" /* op.V */
|
||||
SPACE "} else {\n"
|
||||
"%v" /* "" / dropping col->key */
|
||||
SPACE SPACE "%s saved = col->value;\n" /* op.V */
|
||||
SPACE SPACE "col->key = key;\n"
|
||||
SPACE SPACE "col->value = value;\n"
|
||||
SPACE SPACE "return Some_%s(saved);\n" /* op.V */
|
||||
SPACE "}\n"
|
||||
"}\n\n",
|
||||
op.v_primitive ? cstr("") : cstr("NODISCARD "), op.V, map, map, op.K, op.V,
|
||||
kvp, map, op.V,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE SPACE"%s_drop(col->key);\n", op.K),
|
||||
op.V, op.V));
|
||||
}
|
||||
if (!op.v_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"bool %s_erase_substitute(%s* self, %s key, %s value) {\n" /* map, map, op.K, op.V */
|
||||
SPACE "RBTreeNode_%s* col = %s_try_insert(self, key, value);\n" /* kvp, map */
|
||||
SPACE "if (col == NULL)\n"
|
||||
SPACE SPACE "return true;\n"
|
||||
"%v" "%v" /* "" / op.K_drop(col->key), "" / op.V_drop(col->value) */
|
||||
SPACE "col->key = key;\n"
|
||||
SPACE "col->value = value;\n"
|
||||
SPACE "return false;\n"
|
||||
"}\n\n",
|
||||
map, map, op.K, op.V, kvp, map,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->key);\n", op.K),
|
||||
op.v_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(col->value);\n", op.V)));
|
||||
}
|
||||
|
||||
if (op.pop){
|
||||
// todo: write _pop_by_it
|
||||
|
||||
// todo: rewrite pop using _pop_by_it
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"Option%s %s_pop(%s* self, %v key) {\n" /* op.V, map, map, taking_ref_k_argument */
|
||||
SPACE "RBTreeNode_%s* v = %s_find(self, key);\n" /* kvp, map */
|
||||
SPACE "if (v == NULL)\n"
|
||||
SPACE SPACE "return None_%s();\n" /* op.V */
|
||||
"%v" /* "" / op.K_drop(v->key) */
|
||||
"%s saved = v->value;\n" /* op.V */
|
||||
SPACE "RBTree_erase_empty_by_iter(&self->root, self->NIL, (RBTreeNode*)v);\n"
|
||||
SPACE "free(v);\n"
|
||||
SPACE "return Some_%s(saved);\n" /* op.V */
|
||||
"}\n\n",
|
||||
op.V, map, map, codegen_rbtree_map__taking_ref_k_argument(op),
|
||||
kvp, map, op.V,
|
||||
op.k_primitive ? vcstr("") : VecU8_fmt(SPACE "%s_drop(v->key);\n", op.K),
|
||||
op.V, op.V));
|
||||
}
|
||||
// todo: write generator for methods _at and _mat
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op,
|
||||
bool generate_node_struct) {
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns,
|
||||
generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op));
|
||||
}
|
||||
|
||||
void generate_rbtree_Map_templ_inst_guarded_header(
|
||||
SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, map_instantiation_op op, bool generate_node_struct
|
||||
){
|
||||
VecU8 all_dependencies = VecU8_fmt("%v%s",
|
||||
codegen_include_relative_to_root(bonus_ns, cstr("src/l1_5/core/rb_tree_node.h")), dependencies);
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns, all_dependencies,
|
||||
generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@ -11,8 +11,6 @@ typedef struct {
|
||||
#include "../../../gen/l1/eve/embassy_l1_5/SpanNamedVariableRecordRef.h"
|
||||
|
||||
typedef struct {
|
||||
bool takes_self;
|
||||
bool takes_mut_self;
|
||||
SpanNamedVariableRecordRef params;
|
||||
SpanU8 return_type;
|
||||
SpanU8 name;
|
||||
@ -22,153 +20,37 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
SpanNamedMethodSignatureRecordRef methods;
|
||||
bool drop_primitive;
|
||||
SpanU8 name;
|
||||
/* It is usually either name or "void" */
|
||||
SpanU8 base_struct_name;
|
||||
} NamedTraitDefRecordRef;
|
||||
|
||||
NODISCARD VecU8 generate_trait_table_structure(NamedTraitDefRecordRef trait){
|
||||
VecU8 res = VecU8_from_cstr("typedef struct {\n");
|
||||
VecU8 res = VecU8_from_cstr("typedef struct {");
|
||||
// todo: add iteration macro
|
||||
for (size_t i = 0; i < trait.methods.len; i++) {
|
||||
NamedMethodSignatureRecordRef method = *SpanNamedMethodSignatureRecordRef_at(trait.methods, i);
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s (*%s)(", c_type_empty_means_void(method.return_type), method.name));
|
||||
if (method.takes_self) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
method.takes_mut_self ? "%s*" : "const %s*",
|
||||
c_type_empty_means_void(trait.base_struct_name)));
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt(SPACE "%s (*%s)(", method.return_type, method.name));
|
||||
for (size_t p = 0; p < method.params.len; p++) {
|
||||
NamedVariableRecordRef param = *SpanNamedVariableRecordRef_at(method.params, p);
|
||||
if (p || method.takes_self)
|
||||
if (p)
|
||||
VecU8_append_span(&res, cstr(", "));
|
||||
VecU8_append_span(&res, param.type);
|
||||
}
|
||||
VecU8_append_span(&res, cstr(");\n"));
|
||||
}
|
||||
if (!trait.drop_primitive) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
SPACE "void (*drop)(%s*);\n",
|
||||
c_type_empty_means_void(trait.base_struct_name)));
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt("} %s_Table;\n\n", trait.name));
|
||||
VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", trait.name));
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
NamedTraitDefRecordRef trait;
|
||||
bool box;
|
||||
bool ref;
|
||||
bool mut_ref;
|
||||
} trait_wrapper_boil_options;
|
||||
|
||||
/* (refkind, mut) in {(Ref, false), (MutRef, true), (Box, true)} */
|
||||
void codegen_append_trait_wrapper_structure_some_refkind(VecU8* res, NamedTraitDefRecordRef trait,
|
||||
SpanU8 refkind, bool mut){
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"typedef struct {\n"
|
||||
SPACE "%s%s* r;\n" /* epsilon / const, op.trait.base_struct_name */
|
||||
SPACE "const %s_Table* t;\n" /* op.trait.name */
|
||||
"} %s%s;\n\n", /* refkind, op.trait.name */
|
||||
mut ? cstr("") : cstr("const "),
|
||||
c_type_empty_means_void(trait.base_struct_name),
|
||||
trait.name, refkind, trait.name));
|
||||
}
|
||||
|
||||
/* (refkind, self_as_ptr) in {(Ref, false), (MutRef, false), (Box, true)} */
|
||||
void codegen_append_trait_wrapper_some_method_some_refkind(VecU8* res, SpanU8 trait_name,
|
||||
NamedMethodSignatureRecordRef method, SpanU8 refkind, bool self_as_ptr){
|
||||
VecU8_append_vec(res, VecU8_fmt(
|
||||
"%s %s%s_%s(%s%s%s self",
|
||||
/* return_type, refkind, trait.name, method.name, refkind, trait.name */
|
||||
c_type_empty_means_void(method.return_type),
|
||||
refkind, trait_name, method.name, refkind, trait_name, self_as_ptr ? cstr("*") : cstr("")));
|
||||
for (size_t p = 0; p < method.params.len; p++) {
|
||||
NamedVariableRecordRef param = method.params.data[p];
|
||||
VecU8_append_vec(res, VecU8_fmt(", %s %s", param.type, param.name));
|
||||
}
|
||||
VecU8_append_span(res, cstr("){\n" SPACE));
|
||||
if (method.return_type.len > 0)
|
||||
VecU8_append_span(res, cstr("return "));
|
||||
VecU8_append_vec(res, VecU8_fmt("self%s""t->%s(",
|
||||
self_as_ptr ? cstr("->") : cstr("."),
|
||||
method.name));
|
||||
if (method.takes_self) {
|
||||
VecU8_append_vec(res, VecU8_fmt("self%s""r", self_as_ptr ? cstr("->") : cstr(".")));
|
||||
}
|
||||
for (size_t p = 0; p < method.params.len; p++) {
|
||||
NamedVariableRecordRef param = method.params.data[p];
|
||||
if (p > 0 || method.takes_self)
|
||||
VecU8_append_span(res, cstr(", "));
|
||||
VecU8_append_span(res, param.name);
|
||||
}
|
||||
VecU8_append_span(res, cstr(");\n}\n\n"));
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_trait_wrapper_boilerplate(trait_wrapper_boil_options op) {
|
||||
/* Checking */
|
||||
for (size_t i = 0; i < op.trait.methods.len; i++) {
|
||||
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
|
||||
assert(!method.takes_mut_self || method.takes_self);
|
||||
}
|
||||
|
||||
NODISCARD VecU8 generate_trait_wrapper_boilerplate(NamedTraitDefRecordRef trait, trait_wrapper_boil_options op) {
|
||||
VecU8 res = VecU8_new();
|
||||
VecU8_append_vec(&res, generate_trait_table_structure(op.trait));
|
||||
if (op.ref) {
|
||||
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("Ref"), false);
|
||||
for (size_t i = 0; i < op.trait.methods.len; i++) {
|
||||
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
|
||||
if (method.takes_mut_self)
|
||||
continue;
|
||||
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Ref"), false);
|
||||
}
|
||||
}
|
||||
if (op.mut_ref) {
|
||||
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("MutRef"), true);
|
||||
for (size_t i = 0; i < op.trait.methods.len; i++) {
|
||||
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
|
||||
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("MutRef"), false);
|
||||
}
|
||||
}
|
||||
if (op.box) {
|
||||
codegen_append_trait_wrapper_structure_some_refkind(&res, op.trait, cstr("Box"), true);
|
||||
for (size_t i = 0; i < op.trait.methods.len; i++) {
|
||||
NamedMethodSignatureRecordRef method = op.trait.methods.data[i];
|
||||
codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Box"), true);
|
||||
}
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"void Box%s_drop(Box%s self){\n" /* trait.name, trait.name */
|
||||
"%s" /* epsilon / calling self.t->drop() */
|
||||
SPACE "free(self.r);\n"
|
||||
"}\n\n",
|
||||
op.trait.name, op.trait.name,
|
||||
op.trait.drop_primitive ? cstr("") : cstr(SPACE "self.t->drop(self.r);\n")));
|
||||
if (op.ref) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"Ref%s Box%s_ref(Box%s *self) {\n"
|
||||
SPACE "return (Ref%s){.r = self->r, .t = self->t};\n"
|
||||
"}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name));
|
||||
}
|
||||
if (op.mut_ref) {
|
||||
VecU8_append_vec(&res, VecU8_fmt(
|
||||
"MutRef%s Box%s_mut_ref(Box%s *self) {\n"
|
||||
SPACE "return (MutRef%s){.r = self->r, .t = self->t};\n"
|
||||
"}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name));
|
||||
}
|
||||
}
|
||||
// todo: write it
|
||||
return res;
|
||||
}
|
||||
|
||||
void generate_trait_wrapper_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, trait_wrapper_boil_options op){
|
||||
generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_trait_wrapper_boilerplate(op),
|
||||
VecU8_from_span(op.trait.name));
|
||||
}
|
||||
|
||||
void generate_trait_wrapper_templ_inst_guarded_header(SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies,
|
||||
trait_wrapper_boil_options op){
|
||||
generate_SOME_templ_inst_guarded_header(layer, bonus_ns,
|
||||
VecU8_fmt("#include <stdlib.h>\n%s", dependencies),
|
||||
generate_trait_wrapper_boilerplate(op), VecU8_from_span(op.trait.name));
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,260 +0,0 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_5_CORE_RB_TREE_NODE_H
|
||||
#define PROTOTYPE1_SRC_L1_5_CORE_RB_TREE_NODE_H
|
||||
|
||||
#include "../../l1/core/util.h"
|
||||
|
||||
typedef enum {
|
||||
RBTree_black = 0,
|
||||
RBTree_red = 1,
|
||||
} RBTreeColor;
|
||||
|
||||
typedef struct {
|
||||
size_t left;
|
||||
size_t right;
|
||||
size_t parent;
|
||||
/* 0 is black, 1 is red */
|
||||
RBTreeColor color;
|
||||
} BufRBTreeNode;
|
||||
|
||||
#include "../../../gen/l1/eve/embassy_l1_5/VecBufRBTreeNode.h"
|
||||
|
||||
void BufRBTree_left_rotate(BufRBTreeNode* tree, U64* root, U64 x){
|
||||
assert(x != 0);
|
||||
U64 y = tree[x].right;
|
||||
assert(y != 0);
|
||||
tree[x].right = tree[y].left;
|
||||
if (tree[x].right != 0)
|
||||
tree[tree[x].right].parent = x;
|
||||
|
||||
tree[y].parent = tree[x].parent;
|
||||
if (tree[y].parent == 0) {
|
||||
*root = y;
|
||||
} else if (x == tree[tree[x].parent].left) {
|
||||
tree[tree[x].parent].left = y;
|
||||
} else {
|
||||
tree[tree[x].parent].right = y;
|
||||
}
|
||||
tree[x].parent = y;
|
||||
tree[y].left = x;
|
||||
}
|
||||
|
||||
void BufRBTree_right_rotate(BufRBTreeNode* tree, U64* root, U64 x){
|
||||
assert(x != 0);
|
||||
U64 y = tree[x].left;
|
||||
assert(y != 0);
|
||||
tree[x].left = tree[y].right;
|
||||
if (tree[x].left != 0)
|
||||
tree[tree[x].left].parent = x;
|
||||
|
||||
tree[y].parent = tree[x].parent;
|
||||
if (tree[y].parent == 0) {
|
||||
*root = y;
|
||||
} else if (x == tree[tree[x].parent].right) {
|
||||
tree[tree[x].parent].right = y;
|
||||
} else {
|
||||
tree[tree[x].parent].left = y;
|
||||
}
|
||||
tree[x].parent = y;
|
||||
tree[y].right = x;
|
||||
}
|
||||
|
||||
/* Helper function. Called in automatically generated code */
|
||||
void BufRBTree_fix_after_insert(BufRBTreeNode* tree, U64* root, U64 me){
|
||||
assert(me);
|
||||
while (true) {
|
||||
U64 mom = tree[me].parent;
|
||||
if (mom == 0)
|
||||
break;
|
||||
if (tree[mom].color == RBTree_black)
|
||||
return;
|
||||
U64 grandma = tree[mom].parent;
|
||||
U64 aunt = tree[grandma].left == mom ? tree[grandma].right : tree[grandma].left;
|
||||
assert(aunt != mom);
|
||||
if (tree[aunt].color == RBTree_red) {
|
||||
/* Easy case */
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[aunt].color = RBTree_black;
|
||||
tree[grandma].color = RBTree_red;
|
||||
me = grandma;
|
||||
} else if (tree[grandma].left == mom) {
|
||||
/* Hard case: firstborn orientation */
|
||||
if (tree[mom].right == me) {
|
||||
BufRBTree_left_rotate(tree, root, mom);
|
||||
tree[me].color = RBTree_black;
|
||||
} else {
|
||||
tree[mom].color = RBTree_black;
|
||||
}
|
||||
BufRBTree_right_rotate(tree, root, grandma);
|
||||
tree[grandma].color = RBTree_red;
|
||||
return;
|
||||
} else {
|
||||
/* Hard case: benjamin orientation */
|
||||
if (tree[mom].left == me) {
|
||||
BufRBTree_right_rotate(tree, root, mom);
|
||||
tree[me].color = RBTree_black;
|
||||
} else {
|
||||
tree[mom].color = RBTree_black;
|
||||
}
|
||||
BufRBTree_left_rotate(tree, root, grandma);
|
||||
tree[grandma].color = RBTree_red;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(*root == me);
|
||||
tree[me].color = RBTree_black;
|
||||
}
|
||||
|
||||
/* fr index will be forgotten. to fields will be overwritten (all fields replaced by fr's values)
|
||||
* If you need the old values of `to` position, you better save them on stack */
|
||||
void BufRBTree_steal_neighbours(BufRBTreeNode* tree, U64* root, U64 fr, U64 to){
|
||||
if (tree[fr].parent == 0)
|
||||
*root = to;
|
||||
else if (tree[tree[fr].parent].left == fr)
|
||||
tree[tree[fr].parent].left = to;
|
||||
else
|
||||
tree[tree[fr].parent].right = to;
|
||||
tree[tree[fr].left].parent = to;
|
||||
tree[tree[fr].right].parent = to;
|
||||
tree[to] = tree[fr];
|
||||
}
|
||||
|
||||
/* helper function (used in _erase, _find_min methods). It is assumed that s is not null.
|
||||
* Guaranteed to return no-null
|
||||
*/
|
||||
U64 BufRBTree_minimum_in_subtree(const BufRBTreeNode* tree, U64 s){
|
||||
assert(s != 0);
|
||||
while (tree[s].left != 0)
|
||||
s = tree[s].left;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* helper function (used in _find_max, _find_prev methods). It is assumed that s is not null.
|
||||
* Guaranteed to return no-null
|
||||
*/
|
||||
U64 BufRBTree_maximum_in_subtree(const BufRBTreeNode* tree, U64 s){
|
||||
assert(s != 0);
|
||||
while (tree[s].right != 0)
|
||||
s = tree[s].right;
|
||||
return s;
|
||||
}
|
||||
|
||||
void BufRBTree_fix_after_delete(BufRBTreeNode* tree, U64* root, U64 me){
|
||||
assert(tree[*root].parent == 0);
|
||||
while (me != *root && tree[me].color == RBTree_black) {
|
||||
U64 mom = tree[me].parent;
|
||||
if (me == tree[mom].left) { /* We are on the left */
|
||||
U64 sister = tree[mom].right;
|
||||
if (tree[sister].color == RBTree_red) { /* Case 1 */
|
||||
tree[mom].color = RBTree_red;
|
||||
tree[sister].color = RBTree_black;
|
||||
BufRBTree_left_rotate(tree, root, mom);
|
||||
/* Reassignation required */
|
||||
sister = tree[mom].right;
|
||||
}
|
||||
/* Cases 2,3,4 (every instance of red-black tree has an itchy substring in source code containing 2,3,4) */
|
||||
assert(sister != 0);
|
||||
U64 nephew_firstborn = tree[sister].left;
|
||||
U64 nephew_benjamin = tree[sister].right;
|
||||
if (tree[nephew_firstborn].color == RBTree_black && tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 2 */
|
||||
tree[sister].color = RBTree_red;
|
||||
me = mom;
|
||||
continue;
|
||||
}
|
||||
/* Cases 3,4 */
|
||||
if (tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 3 */
|
||||
tree[nephew_firstborn].color = RBTree_black;
|
||||
tree[sister].color = RBTree_red;
|
||||
BufRBTree_right_rotate(tree, root, sister);
|
||||
/* Reassignation required */
|
||||
nephew_benjamin = sister;
|
||||
sister = nephew_firstborn;
|
||||
nephew_firstborn = tree[sister].left;
|
||||
}
|
||||
/* Case 4 */
|
||||
tree[sister].color = tree[mom].color;
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[nephew_benjamin].color = RBTree_black;
|
||||
BufRBTree_left_rotate(tree, root, mom);
|
||||
me = *root;
|
||||
} else if (me == tree[mom].right) { /* We are on the right */
|
||||
U64 sister = tree[mom].left;
|
||||
if (tree[sister].color == RBTree_red) { /* Case 1 */
|
||||
tree[mom].color = RBTree_red;
|
||||
tree[sister].color = RBTree_black;
|
||||
BufRBTree_right_rotate(tree, root, mom);
|
||||
/* Reassignation required */
|
||||
sister = tree[mom].left;
|
||||
}
|
||||
/* Cases 2,3,4 (every instance of red-black tree has an itchy substring in source code containing 2,3,4) */
|
||||
assert(sister != 0);
|
||||
U64 nephew_firstborn = tree[sister].left;
|
||||
U64 nephew_benjamin = tree[sister].right;
|
||||
if (tree[nephew_firstborn].color == RBTree_black && tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 2 */
|
||||
tree[sister].color = RBTree_red;
|
||||
me = mom;
|
||||
continue;
|
||||
}
|
||||
/* Cases 3,4 */
|
||||
if (tree[nephew_firstborn].color == RBTree_black) {
|
||||
/* Case 3 */
|
||||
tree[nephew_benjamin].color = RBTree_black;
|
||||
tree[sister].color = RBTree_red;
|
||||
BufRBTree_left_rotate(tree, root, sister);
|
||||
/* Reassignation required */
|
||||
nephew_firstborn = sister;
|
||||
sister = nephew_benjamin;
|
||||
nephew_benjamin = tree[sister].right;
|
||||
}
|
||||
/* Case 4 */
|
||||
tree[sister].color = tree[mom].color;
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[nephew_firstborn].color = RBTree_black;
|
||||
BufRBTree_right_rotate(tree, root, mom);
|
||||
me = *root;
|
||||
}
|
||||
}
|
||||
tree[me].color = RBTree_black;
|
||||
}
|
||||
|
||||
/* UNSAFE. Use when you dropped the symbol that is about to be deleted. Does not shrink the el vector,
|
||||
* do it yourself */
|
||||
void BufRBTree_empty_index_erase(VecBufRBTreeNode* tree, U64* root, U64 z) {
|
||||
assert(z != 0 && z < tree->len);
|
||||
U64 y = (tree->buf[z].left == 0 || tree->buf[z].right == 0) ? z : BufRBTree_minimum_in_subtree(tree->buf, tree->buf[z].right);
|
||||
U64 x = tree->buf[y].left != 0 ? tree->buf[y].left : tree->buf[y].right;
|
||||
assert(x != y && x != z);
|
||||
U64 x_adopter = tree->buf[y].parent;
|
||||
tree->buf[x].parent = x_adopter;
|
||||
if (x_adopter == 0)
|
||||
*root = x;
|
||||
else if (tree->buf[x_adopter].left == y)
|
||||
tree->buf[x_adopter].left = x;
|
||||
else
|
||||
tree->buf[x_adopter].right = x;
|
||||
RBTreeColor y_org_clr = tree->buf[y].color;
|
||||
if (z != y) {
|
||||
BufRBTree_steal_neighbours(tree->buf, root, z, y);
|
||||
if (x_adopter == z)
|
||||
x_adopter = y;
|
||||
}
|
||||
U64 L = tree->len - 1;
|
||||
if (L != z) {
|
||||
BufRBTree_steal_neighbours(tree->buf, root, L, z);
|
||||
if (L == x)
|
||||
x = z;
|
||||
else if (L == x_adopter)
|
||||
x_adopter = z;
|
||||
}
|
||||
tree->buf[x].parent = x_adopter;
|
||||
tree->len--;
|
||||
if (y_org_clr == RBTree_black)
|
||||
BufRBTree_fix_after_delete(tree->buf, root, x);
|
||||
// self->el.buf[z-1] = self->el.buf[L-1];
|
||||
// self->el.len--;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,85 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_core_input_olproga_h
|
||||
#define prototype1_src_l1_5_core_input_olproga_h
|
||||
|
||||
#include "../../../gen/l1/OptionU64.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
|
||||
void stdin_skip_whitespaces(){
|
||||
while (true) {
|
||||
int ch = fgetc(stdin);
|
||||
if (ch == EOF)
|
||||
return;
|
||||
if (ch < 0) {
|
||||
perror("fgetc(stdin)");
|
||||
abort();
|
||||
}
|
||||
if (ch != ' ' && ch != '\t' && ch != '\n') {
|
||||
ungetc(ch, stdin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Aborts on error, skips whitespaces
|
||||
OptionU64 stdin_read_U64(){
|
||||
stdin_skip_whitespaces();
|
||||
U64 x = 0;
|
||||
int i = 0;
|
||||
for (;; i++) {
|
||||
int ch = fgetc(stdin);
|
||||
if (ch == EOF)
|
||||
break;
|
||||
if (ch < 0) {
|
||||
perror("fgetc(stdin)");
|
||||
abort();
|
||||
}
|
||||
if (!('0' <= ch && ch <= '9')) {
|
||||
ungetc(ch, stdin);
|
||||
break;
|
||||
}
|
||||
U64 d = (U64)(ch - '0');
|
||||
if (x == 0 && i > 0)
|
||||
abortf("Bad integer input\n");
|
||||
if (x > UINT64_MAX / 10)
|
||||
abortf("Integer input exceeds UINT64_MAX\n");
|
||||
x *= 10;
|
||||
if (x > UINT64_MAX - d)
|
||||
abortf("Integer input exceeds UINT64_MAX\n");
|
||||
x += d;
|
||||
}
|
||||
if (i > 0)
|
||||
return Some_U64(x);
|
||||
return None_U64();
|
||||
}
|
||||
|
||||
/* If empty string is returned it means EOF was reached */
|
||||
NODISCARD VecU8 stdin_read_VecU8_nospace(){
|
||||
stdin_skip_whitespaces();
|
||||
VecU8 str = VecU8_new();
|
||||
while (true) {
|
||||
int ch = fgetc(stdin);
|
||||
if (ch == EOF)
|
||||
break;
|
||||
if (ch < 0) {
|
||||
perror("fgetc(stdin)");
|
||||
abort();
|
||||
}
|
||||
if (ch == ' ' || ch == '\t' || ch == '\n') {
|
||||
ungetc(ch, stdin);
|
||||
break;
|
||||
}
|
||||
VecU8_append(&str, ch);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Aborts if non-integer input or EOF was encountered before my integer
|
||||
U64 stdin_read_U64_nofail(){
|
||||
OptionU64 x = stdin_read_U64();
|
||||
if (x.variant == Option_None)
|
||||
abortf("No number found\n");
|
||||
return x.some;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,230 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_core_parsing_string_h
|
||||
#define prototype1_src_l1_5_core_parsing_string_h
|
||||
|
||||
#include "../../l1/core/VecU8_as_str.h"
|
||||
#include <math.h>
|
||||
|
||||
void SpanU8_parsing_expect_char(SpanU8* rem, char ch){
|
||||
if (rem->len == 0) {
|
||||
abortf("Unexpected EOF. Syntax error\n");
|
||||
}
|
||||
if (*rem->data != (U8)ch) {
|
||||
abortf("Expected %d, got %d. Syntax error\n", (int)(*rem->data), (int)ch);
|
||||
}
|
||||
rem->data++;
|
||||
rem->len--;
|
||||
}
|
||||
|
||||
/* if `expected` is prefix of `rem`, `rem` will be advanced by |`expected`| and true will be returned.
|
||||
* Otherwise false is returned and `rem` is untouched */
|
||||
bool SpanU8_parsing_try_read_prefix(SpanU8* rem, SpanU8 expected){
|
||||
if (rem->len < expected.len) {
|
||||
return false;
|
||||
}
|
||||
if (SpanU8_cont_equal(SpanU8_span(*rem, 0, expected.len), expected)) {
|
||||
rem->data += expected.len;
|
||||
rem->len -= expected.len;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpanU8_parsing_try_read_char(SpanU8* rem, char ch){
|
||||
if (rem->len == 0) {
|
||||
return false;
|
||||
}
|
||||
if (rem->data[0] == (U8)ch) {
|
||||
rem->data++;
|
||||
rem->len--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SpanU8_parsing_skip_entire_line(SpanU8* rem){
|
||||
while (rem->len > 0) {
|
||||
U8 ch = *(rem->data++);
|
||||
rem->len--;
|
||||
if (ch == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpanU8_parsing_skip_char(SpanU8* rem){
|
||||
assert(rem->len > 0);
|
||||
rem->data++;
|
||||
rem->len--;
|
||||
}
|
||||
|
||||
bool SpanU8_parsing_is_char_ahead(SpanU8* rem, char ch){
|
||||
return rem->len > 0 ? rem->data[0] == (U8)ch : false;
|
||||
}
|
||||
|
||||
/* Time to learn how to read integers */
|
||||
|
||||
/* returns positive on error, returns 0 on success */
|
||||
int SpanU8_read_U64(SpanU8* rem_ret, U64* res_ret){
|
||||
SpanU8 rem = *rem_ret;
|
||||
U64 x = 0;
|
||||
while (rem.len > 0) {
|
||||
U8 ch = *rem.data;
|
||||
if (!('0' <= ch && ch <= '9')) {
|
||||
break;
|
||||
}
|
||||
U64 d = (U64)(ch - '0');
|
||||
if (x == 0 && rem_ret->data != rem.data) {
|
||||
return 1;
|
||||
}
|
||||
if (x > UINT64_MAX / 10) {
|
||||
return 2;
|
||||
}
|
||||
x *= 10;
|
||||
if (x > UINT64_MAX - d) {
|
||||
return 2;
|
||||
}
|
||||
x += d;
|
||||
rem.data++;
|
||||
rem.len--;
|
||||
}
|
||||
if (rem_ret->data == rem.data) {
|
||||
return 1;
|
||||
}
|
||||
*res_ret = x;
|
||||
*rem_ret = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U64 SpanU64_expect_read_U64(SpanU8* rem){
|
||||
U64 x;
|
||||
int code = SpanU8_read_U64(rem, &x);
|
||||
if (code)
|
||||
abortf("Failed to read U64. Syntax error\n");
|
||||
return x;
|
||||
}
|
||||
|
||||
int SpanU8_read_S64(SpanU8* rem_ret, S64* ret){
|
||||
SpanU8 rem = *rem_ret;
|
||||
U64 x = 0;
|
||||
bool saw_minus = false;
|
||||
bool saw_digit = false;
|
||||
while (rem.len > 0) {
|
||||
U8 ch = *rem.data;
|
||||
if ('0' <= ch && ch <= '9') {
|
||||
U64 d = (U64)(ch - '0');
|
||||
if (x == 0 && rem_ret->len - rem.len > (U64)saw_minus) {
|
||||
return 1;
|
||||
}
|
||||
if (x > 9223372036854775808UL / 10) {
|
||||
return 2;
|
||||
}
|
||||
x *= 10;
|
||||
if (x > 9223372036854775808UL - d) {
|
||||
return 2;
|
||||
}
|
||||
x += d;
|
||||
saw_digit = true;
|
||||
} else if (ch == '-') {
|
||||
if (rem_ret->data != rem.data) {
|
||||
break;
|
||||
}
|
||||
saw_minus = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
rem.data++;
|
||||
rem.len--;
|
||||
}
|
||||
if (!saw_digit) {
|
||||
return 1;
|
||||
}
|
||||
assert(x <= 9223372036854775808UL);
|
||||
if (x == 9223372036854775808UL) {
|
||||
if (saw_minus) {
|
||||
*ret = -9223372036854775807L-1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (saw_minus) {
|
||||
*ret = -(S64)x;
|
||||
} else {
|
||||
*ret = (S64)x;
|
||||
}
|
||||
}
|
||||
*rem_ret = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* returns positive int on error, 0 on success */
|
||||
int SpanU8_read_float(SpanU8* rem_ret, float* res_ret){
|
||||
SpanU8 rem = *rem_ret;
|
||||
|
||||
float res = 0;
|
||||
bool saw_minus = false;
|
||||
bool saw_digit = false;
|
||||
bool saw_dot = false;
|
||||
float mul = 1;
|
||||
|
||||
while (rem.len > 0) {
|
||||
U8 ch = *rem.data;
|
||||
if (ch == '.') {
|
||||
if (saw_dot) {
|
||||
return 1;
|
||||
}
|
||||
saw_dot = true;
|
||||
} else if (ch == '-') {
|
||||
if (rem_ret->data != rem.data) {
|
||||
break;
|
||||
}
|
||||
saw_minus = true;
|
||||
} else if ('0' <= ch && ch <= '9') {
|
||||
float d = (float)(ch - '0');
|
||||
if (saw_dot) {
|
||||
mul /= 10.f;
|
||||
res = (res + d * mul);
|
||||
} else {
|
||||
res = (res * 10 + d);
|
||||
}
|
||||
saw_digit = true;
|
||||
} else if (ch == 'e') {
|
||||
SpanU8_parsing_skip_char(&rem);
|
||||
S64 exp;
|
||||
int ret = SpanU8_read_S64(&rem, &exp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (exp > 1000 || exp < -999) {
|
||||
return 2;
|
||||
}
|
||||
/* If compiler won't perform pow optimization here, I will throw my chair out of the window */
|
||||
res = res * powf(10.f, (float)exp);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
rem.data++;
|
||||
rem.len--;
|
||||
}
|
||||
if (!saw_digit) {
|
||||
return 1;
|
||||
}
|
||||
if (saw_dot && mul == 1.f) {
|
||||
return 1;
|
||||
}
|
||||
if (saw_minus) {
|
||||
res = -(res);
|
||||
}
|
||||
*res_ret = res;
|
||||
*rem_ret = rem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
float SpanU8_expect_read_float(SpanU8* rem){
|
||||
float x;
|
||||
int code = SpanU8_read_float(rem, &x);
|
||||
if (code)
|
||||
abortf("Failed to read float. Syntax error\n");
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,278 +1,222 @@
|
||||
#ifndef prototype1_src_l1_5_core_rb_tree_node_h
|
||||
#define prototype1_src_l1_5_core_rb_tree_node_h
|
||||
#ifndef PROTOTYPE1_SRC_L1_5_CORE_RB_TREE_NODE_H
|
||||
#define PROTOTYPE1_SRC_L1_5_CORE_RB_TREE_NODE_H
|
||||
|
||||
#include "../../l1/core/util.h"
|
||||
|
||||
typedef enum {
|
||||
RBTREE_BLACK = 0,
|
||||
RBTREE_RED = 1,
|
||||
} RBTreeClr;
|
||||
RBTree_black = 0,
|
||||
RBTree_red = 1,
|
||||
} RBTreeColor;
|
||||
|
||||
typedef struct RBTreeNode RBTreeNode;
|
||||
struct RBTreeNode{
|
||||
RBTreeNode* parent;
|
||||
RBTreeNode* left;
|
||||
RBTreeNode* right;
|
||||
RBTreeClr color;
|
||||
};
|
||||
typedef struct {
|
||||
size_t left;
|
||||
size_t right;
|
||||
size_t parent;
|
||||
/* 0 is black, 1 is red */
|
||||
RBTreeColor color;
|
||||
} RBTreeNode;
|
||||
|
||||
void RBTree_left_rotate(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* x){
|
||||
assert(x != NIL);
|
||||
RBTreeNode* y = x->right;
|
||||
assert(y != NIL);
|
||||
x->right = y->left;
|
||||
if (y->left != NIL)
|
||||
y->left->parent = x;
|
||||
#include "../../../gen/l1/eve/embassy_l1_5/VecRBTreeNode.h"
|
||||
|
||||
y->parent = x->parent;
|
||||
if (x->parent == NIL)
|
||||
void RBTree_left_rotate(RBTreeNode* tree, U64* root, U64 x){
|
||||
assert(x != 0);
|
||||
U64 y = tree[x].right;
|
||||
assert(y != 0);
|
||||
tree[x].right = tree[y].left;
|
||||
if (tree[x].right != 0)
|
||||
tree[tree[x].right].parent = x;
|
||||
|
||||
tree[y].parent = tree[x].parent;
|
||||
if (tree[y].parent == 0) {
|
||||
*root = y;
|
||||
else if (x == x->parent->left)
|
||||
x->parent->left = y;
|
||||
else
|
||||
x->parent->right = y;
|
||||
|
||||
x->parent = y;
|
||||
y->left = x;
|
||||
} else if (x == tree[tree[x].parent].left) {
|
||||
tree[tree[x].parent].left = y;
|
||||
} else {
|
||||
tree[tree[x].parent].right = y;
|
||||
}
|
||||
tree[x].parent = y;
|
||||
tree[y].left = x;
|
||||
}
|
||||
|
||||
void RBTree_right_rotate(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* x){
|
||||
assert(x != NIL);
|
||||
RBTreeNode* y = x->left;
|
||||
assert(y != NIL);
|
||||
x->left = y->right;
|
||||
if (y->right != NIL)
|
||||
y->right->parent = x;
|
||||
void RBTree_right_rotate(RBTreeNode* tree, U64* root, U64 x){
|
||||
assert(x != 0);
|
||||
U64 y = tree[x].left;
|
||||
assert(y != 0);
|
||||
tree[x].left = tree[y].right;
|
||||
if (tree[x].left != 0)
|
||||
tree[tree[x].left].parent = x;
|
||||
|
||||
y->parent = x->parent;
|
||||
if (x->parent == NIL)
|
||||
tree[y].parent = tree[x].parent;
|
||||
if (tree[y].parent == 0) {
|
||||
*root = y;
|
||||
else if (x->parent->right == x)
|
||||
x->parent->right = y;
|
||||
else
|
||||
x->parent->left = y;
|
||||
|
||||
x->parent = y;
|
||||
y->right = x;
|
||||
} else if (x == tree[tree[x].parent].right) {
|
||||
tree[tree[x].parent].right = y;
|
||||
} else {
|
||||
tree[tree[x].parent].left = y;
|
||||
}
|
||||
tree[x].parent = y;
|
||||
tree[y].right = x;
|
||||
}
|
||||
|
||||
void RBTree_fix_after_insert(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* me){
|
||||
assert(me != NIL);
|
||||
/* Helper function. Called in automatically generated code */
|
||||
void RBTree_fix_after_insert(RBTreeNode* tree, U64* root, U64 me){
|
||||
assert(me);
|
||||
while (true) {
|
||||
RBTreeNode* mom = me->parent;
|
||||
if (mom == NIL)
|
||||
U64 mom = tree[me].parent;
|
||||
if (mom == 0)
|
||||
break;
|
||||
if (mom->color == RBTREE_BLACK)
|
||||
if (tree[mom].color == RBTree_black)
|
||||
return;
|
||||
RBTreeNode* grandma = mom->parent;
|
||||
assert(grandma != NIL);
|
||||
assert(grandma->color == RBTREE_BLACK);
|
||||
RBTreeNode* aunt = grandma->left == mom ? grandma->right : grandma->left;
|
||||
U64 grandma = tree[mom].parent;
|
||||
U64 aunt = tree[grandma].left == mom ? tree[grandma].right : tree[grandma].left;
|
||||
assert(aunt != mom);
|
||||
if (aunt->color == RBTREE_RED) {
|
||||
if (tree[aunt].color == RBTree_red) {
|
||||
/* Easy case */
|
||||
mom->color = RBTREE_BLACK;
|
||||
aunt->color = RBTREE_BLACK;
|
||||
grandma->color = RBTREE_RED;
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[aunt].color = RBTree_black;
|
||||
tree[grandma].color = RBTree_red;
|
||||
me = grandma;
|
||||
} else if (grandma->left == mom) {
|
||||
} else if (tree[grandma].left == mom) {
|
||||
/* Hard case: firstborn orientation */
|
||||
if (mom->right == me) {
|
||||
RBTree_left_rotate(root, NIL, mom);
|
||||
me->color = RBTREE_BLACK;
|
||||
if (tree[mom].right == me) {
|
||||
RBTree_left_rotate(tree, root, mom);
|
||||
tree[me].color = RBTree_black;
|
||||
} else {
|
||||
mom->color = RBTREE_BLACK;
|
||||
tree[mom].color = RBTree_black;
|
||||
}
|
||||
RBTree_right_rotate(root, NIL, grandma);
|
||||
grandma->color = RBTREE_RED;
|
||||
RBTree_right_rotate(tree, root, grandma);
|
||||
tree[grandma].color = RBTree_red;
|
||||
return;
|
||||
} else {
|
||||
/* Hard case: benjamin orientation */
|
||||
if (mom->left == me) {
|
||||
RBTree_right_rotate(root, NIL, mom);
|
||||
me->color = RBTREE_BLACK;
|
||||
if (tree[mom].left == me) {
|
||||
RBTree_right_rotate(tree, root, mom);
|
||||
tree[me].color = RBTree_black;
|
||||
} else {
|
||||
mom->color = RBTREE_BLACK;
|
||||
tree[mom].color = RBTree_black;
|
||||
}
|
||||
RBTree_left_rotate(root, NIL, grandma);
|
||||
grandma->color = RBTREE_RED;
|
||||
RBTree_left_rotate(tree, root, grandma);
|
||||
tree[grandma].color = RBTree_red;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(*root == me);
|
||||
me->color = RBTREE_BLACK;
|
||||
tree[me].color = RBTree_black;
|
||||
}
|
||||
|
||||
|
||||
void RBTree_steal_neighbours(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* fr, RBTreeNode* to){
|
||||
if (fr->parent == NIL)
|
||||
/* fr index will be forgotten. to fields will be overwritten (all fields replaced by fr's values)
|
||||
* If you need the old values of `to` position, you better save them on stack */
|
||||
void RBTree_steal_neighbours(RBTreeNode* tree, U64* root, U64 fr, U64 to){
|
||||
if (tree[fr].parent == 0)
|
||||
*root = to;
|
||||
else if (fr->parent->left == fr)
|
||||
fr->parent->left = to;
|
||||
else if (tree[tree[fr].parent].left == fr)
|
||||
tree[tree[fr].parent].left = to;
|
||||
else
|
||||
fr->parent->right = to;
|
||||
fr->left->parent = to;
|
||||
fr->right->parent = to;
|
||||
*to = *fr;
|
||||
tree[tree[fr].parent].right = to;
|
||||
tree[tree[fr].left].parent = to;
|
||||
tree[tree[fr].right].parent = to;
|
||||
tree[to] = tree[fr];
|
||||
}
|
||||
|
||||
|
||||
RBTreeNode* RBTreeNode_minimum_in_subtree(RBTreeNode* x, RBTreeNode* NIL){
|
||||
assert(x != NIL);
|
||||
while (x->left != NIL)
|
||||
x = x->left;
|
||||
return x;
|
||||
/* helper function (used in _erase, _find_min methods). It is assumed that s is not null.
|
||||
* Guaranteed to return no-null
|
||||
*/
|
||||
U64 RBTree_minimum_in_subtree(RBTreeNode* tree, U64 s){
|
||||
assert(s != 0);
|
||||
while (tree[s].left != 0)
|
||||
s = tree[s].left;
|
||||
return s;
|
||||
}
|
||||
|
||||
RBTreeNode* RBTreeNode_maximum_in_subtree(RBTreeNode* x, RBTreeNode* NIL){
|
||||
assert(x != NIL);
|
||||
while (x->right != NIL)
|
||||
x = x->right;
|
||||
return x;
|
||||
/* helper function (used in _find_max, _find_prev methods). It is assumed that s is not null.
|
||||
* Guaranteed to return no-null
|
||||
*/
|
||||
U64 RBTree_maximum_in_subtree(RBTreeNode* tree, U64 s){
|
||||
assert(s != 0);
|
||||
while (tree[s].right != 0)
|
||||
s = tree[s].right;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Returns NULL instead of NIL */
|
||||
RBTreeNode* RBTreeNode_find_next(RBTreeNode* x, RBTreeNode* NIL){
|
||||
assert(x != NIL);
|
||||
if (x->right != NIL)
|
||||
return RBTreeNode_minimum_in_subtree(x->right, NIL);
|
||||
while (true) {
|
||||
RBTreeNode* p = x->parent;
|
||||
if (p == NIL)
|
||||
return NULL;
|
||||
if (p->left == x)
|
||||
return p;
|
||||
x = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns NULL instead of NIL */
|
||||
RBTreeNode* RBTreeNode_find_prev(RBTreeNode* x, RBTreeNode* NIL){
|
||||
assert(x != NIL);
|
||||
if (x->left != NIL)
|
||||
return RBTreeNode_maximum_in_subtree(x->left, NIL);
|
||||
while (true) {
|
||||
RBTreeNode* p = x->parent;
|
||||
if (p == NIL)
|
||||
return NULL;
|
||||
if (p->right == x)
|
||||
return p;
|
||||
x = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* me may be NIL at the beginning. ->parent field of NIL is meaningful */
|
||||
void RBTree_fix_after_delete(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* me){
|
||||
assert((*root)->parent == NIL);
|
||||
while (me != *root && me->color == RBTREE_BLACK) {
|
||||
RBTreeNode* mom = me->parent;
|
||||
assert(mom != NIL);
|
||||
if (me == mom->left) { /* We are on the left */
|
||||
RBTreeNode* sister = mom->right;
|
||||
assert(sister != NIL);
|
||||
if (sister->color == RBTREE_RED) { /* Case 1 */
|
||||
mom->color = RBTREE_RED;
|
||||
sister->color = RBTREE_BLACK;
|
||||
RBTree_left_rotate(root, NIL, mom);
|
||||
void RBTree_fix_after_delete(RBTreeNode* tree, U64* root, U64 me){
|
||||
assert(tree[*root].parent == 0);
|
||||
while (me != *root && tree[me].color == RBTree_black) {
|
||||
U64 mom = tree[me].parent;
|
||||
if (me == tree[mom].left) { /* We are on the left */
|
||||
U64 sister = tree[mom].right;
|
||||
if (tree[sister].color == RBTree_red) { /* Case 1 */
|
||||
tree[mom].color = RBTree_red;
|
||||
tree[sister].color = RBTree_black;
|
||||
RBTree_left_rotate(tree, root, mom);
|
||||
/* Reassignation required */
|
||||
sister = mom->right;
|
||||
assert(sister != NIL);
|
||||
sister = tree[mom].right;
|
||||
}
|
||||
/* Cases 2,3,4 */
|
||||
RBTreeNode* nephew_firstborn = sister->left;
|
||||
RBTreeNode* nephew_benjamin = sister->right;
|
||||
if (nephew_firstborn->color == RBTREE_BLACK && nephew_benjamin->color == RBTREE_BLACK) {
|
||||
/* Cases 2,3,4 (every instance of red-black tree has an itchy substring in source code containing 2,3,4) */
|
||||
assert(sister != 0);
|
||||
U64 nephew_firstborn = tree[sister].left;
|
||||
U64 nephew_benjamin = tree[sister].right;
|
||||
if (tree[nephew_firstborn].color == RBTree_black && tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 2 */
|
||||
sister->color = RBTREE_RED;
|
||||
tree[sister].color = RBTree_red;
|
||||
me = mom;
|
||||
continue;
|
||||
}
|
||||
/* Cases 3,4 */
|
||||
if (nephew_benjamin->color == RBTREE_BLACK) {
|
||||
if (tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 3 */
|
||||
nephew_firstborn->color = RBTREE_BLACK;
|
||||
sister->color = RBTREE_RED;
|
||||
RBTree_right_rotate(root, NIL, sister);
|
||||
tree[nephew_firstborn].color = RBTree_black;
|
||||
tree[sister].color = RBTree_red;
|
||||
RBTree_right_rotate(tree, root, sister);
|
||||
/* Reassignation required */
|
||||
nephew_benjamin = sister;
|
||||
sister = nephew_firstborn;
|
||||
assert(sister != NIL);
|
||||
/*nephew_firstborn = sister->left;*/
|
||||
nephew_firstborn = tree[sister].left;
|
||||
}
|
||||
/* Case 4 */
|
||||
sister->color = mom->color;
|
||||
mom->color = RBTREE_BLACK;
|
||||
nephew_benjamin->color = RBTREE_BLACK;
|
||||
RBTree_left_rotate(root, NIL, mom);
|
||||
tree[sister].color = tree[mom].color;
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[nephew_benjamin].color = RBTree_black;
|
||||
RBTree_left_rotate(tree, root, mom);
|
||||
me = *root;
|
||||
} else { /* We are on the right */
|
||||
assert(me == mom->right);
|
||||
RBTreeNode* sister = mom->left;
|
||||
assert(sister != NIL);
|
||||
if (sister->color == RBTREE_RED) { /* Case 1 */
|
||||
mom->color = RBTREE_RED;
|
||||
sister->color = RBTREE_BLACK;
|
||||
RBTree_right_rotate(root, NIL, mom);
|
||||
} else if (me == tree[mom].right) { /* We are on the right */
|
||||
U64 sister = tree[mom].left;
|
||||
if (tree[sister].color == RBTree_red) { /* Case 1 */
|
||||
tree[mom].color = RBTree_red;
|
||||
tree[sister].color = RBTree_black;
|
||||
RBTree_right_rotate(tree, root, mom);
|
||||
/* Reassignation required */
|
||||
sister = mom->left;
|
||||
assert(sister != NIL);
|
||||
sister = tree[mom].left;
|
||||
}
|
||||
/* Cases 2,3,4 (every instance of red-black tree has an itchy substring in source code containing 2,3,4) */
|
||||
RBTreeNode* nephew_firstborn = sister->left;
|
||||
RBTreeNode* nephew_benjamin = sister->right;
|
||||
if (nephew_firstborn->color == RBTREE_BLACK && nephew_benjamin->color == RBTREE_BLACK) {
|
||||
assert(sister != 0);
|
||||
U64 nephew_firstborn = tree[sister].left;
|
||||
U64 nephew_benjamin = tree[sister].right;
|
||||
if (tree[nephew_firstborn].color == RBTree_black && tree[nephew_benjamin].color == RBTree_black) {
|
||||
/* Case 2 */
|
||||
sister->color = RBTREE_RED;
|
||||
tree[sister].color = RBTree_red;
|
||||
me = mom;
|
||||
continue;
|
||||
}
|
||||
/* Cases 3,4 */
|
||||
if (nephew_firstborn->color == RBTREE_BLACK) {
|
||||
if (tree[nephew_firstborn].color == RBTree_black) {
|
||||
/* Case 3 */
|
||||
nephew_benjamin->color = RBTREE_BLACK;
|
||||
sister->color = RBTREE_RED;
|
||||
RBTree_left_rotate(root, NIL, sister);
|
||||
tree[nephew_benjamin].color = RBTree_black;
|
||||
tree[sister].color = RBTree_red;
|
||||
RBTree_left_rotate(tree, root, sister);
|
||||
/* Reassignation required */
|
||||
nephew_firstborn = sister;
|
||||
sister = nephew_benjamin;
|
||||
assert(sister != NIL);
|
||||
/*nephew_benjamin = sister->right;*/
|
||||
nephew_benjamin = tree[sister].right;
|
||||
}
|
||||
/* Case 4 */
|
||||
sister->color = mom->color;
|
||||
mom->color = RBTREE_BLACK;
|
||||
nephew_firstborn->color = RBTREE_BLACK;
|
||||
RBTree_right_rotate(root, NIL, mom);
|
||||
tree[sister].color = tree[mom].color;
|
||||
tree[mom].color = RBTree_black;
|
||||
tree[nephew_firstborn].color = RBTree_black;
|
||||
RBTree_right_rotate(tree, root, mom);
|
||||
me = *root;
|
||||
}
|
||||
}
|
||||
me->color = RBTREE_BLACK;
|
||||
tree[me].color = RBTree_black;
|
||||
}
|
||||
|
||||
/* Assumes that z->key and z->value were already dropped properly. Does not free z node */
|
||||
void RBTree_erase_empty_by_iter(RBTreeNode** root, RBTreeNode* NIL, RBTreeNode* z) {
|
||||
assert(z != NULL);
|
||||
assert(z != NIL);
|
||||
RBTreeNode* y = (z->left == NIL || z->right == NIL) ? z : RBTreeNode_minimum_in_subtree(z->right, NIL);
|
||||
RBTreeNode* x = y->left == NIL ? y->right : y->left;
|
||||
assert(x != y && x != z);
|
||||
RBTreeNode* x_adopter = y->parent;
|
||||
x->parent = x_adopter;
|
||||
if (x_adopter == NIL)
|
||||
*root = x;
|
||||
else if (x_adopter->left == y)
|
||||
x_adopter->left = x;
|
||||
else
|
||||
x_adopter->right = x;
|
||||
RBTreeClr y_org_clr = y->color;
|
||||
if (z != y) {
|
||||
RBTree_steal_neighbours(root, NIL, z, y);
|
||||
// if (x_adopter == z)
|
||||
// x_adopter = y;
|
||||
}
|
||||
// x->parent = x_adopter;
|
||||
if (y_org_clr == RBTREE_BLACK)
|
||||
RBTree_fix_after_delete(root, NIL, x);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
#ifndef PROTOTYPE1_SRC_L1_5_CORE_STRINGOP_H
|
||||
#define PROTOTYPE1_SRC_L1_5_CORE_STRINGOP_H
|
||||
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
#include "../../../gen/l1/VecAndSpan_VecU8.h"
|
||||
#include "../../../gen/l1/VecAndSpan_SpanU8.h"
|
||||
#include "../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
#include "../../../gen/l1/VecAndSpan_Vec_int_primitives.h"
|
||||
#include "../../../gen/l1/VecAndSpan_Span_int_primitives.h"
|
||||
#include "../../l1/core/VecU8_as_str.h"
|
||||
|
||||
U8 U8_to_lowercase(U8 ch) {
|
||||
@ -29,7 +29,7 @@ bool string_contains_string_ignorecase(SpanU8 str1, SpanU8 str2) {
|
||||
|
||||
bool is_string_in_string_vec(SpanU8 a, const VecVecU8* B) {
|
||||
for (size_t i = 0; i < B->len; i++) {
|
||||
if (SpanU8_cont_equal(a, VecU8_to_span(VecVecU8_at(B, i))))
|
||||
if (strings_in_spans_equal(a, VecU8_to_span(VecVecU8_at(B, i))))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
#ifndef prototype1_src_l1_5_core_stringsearch_h
|
||||
#define prototype1_src_l1_5_core_stringsearch_h
|
||||
|
||||
#include "../../l1/core/VecU8_as_str.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U64.h"
|
||||
|
||||
NODISCARD VecU64 prefix_function(SpanU8 s){
|
||||
VecU64 prefix = VecU64_new_zeroinit(s.len + 1);
|
||||
for (size_t i = 1; i < s.len; i++) {
|
||||
size_t k = prefix.buf[i];
|
||||
while (k > 0 && s.data[k] != s.data[i])
|
||||
k = prefix.buf[k];
|
||||
if (s.data[k] == s.data[i])
|
||||
k++;
|
||||
prefix.buf[i + 1] = k;
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
NODISCARD VecU64 z_function(SpanU8 s){
|
||||
VecU64 Z = VecU64_new_zeroinit(s.len + 1);
|
||||
Z.buf[0] = s.len;
|
||||
size_t l = 0, r = 0;
|
||||
for (size_t i = 1; i <= s.len; i++) {
|
||||
if (i + 1 < r) {
|
||||
Z.buf[i] = MIN_U64(r - i, Z.buf[i - l]);
|
||||
}
|
||||
while (i + Z.buf[i] < s.len && s.data[Z.buf[i]] == s.data[i + Z.buf[i]]) {
|
||||
Z.buf[i]++;
|
||||
}
|
||||
if (i + Z.buf[i] >= r) {
|
||||
l = i;
|
||||
r = i + Z.buf[i];
|
||||
}
|
||||
}
|
||||
return Z;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,138 +0,0 @@
|
||||
#ifndef prototype1_src_l2_alice_assets_h
|
||||
#define prototype1_src_l2_alice_assets_h
|
||||
|
||||
#include "../marie/graphics_geom.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U32.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
vec2 tex;
|
||||
} GenericMeshVertexInc;
|
||||
|
||||
#include "../../../gen/l1/eve/alice/VecAndSpan_GenericMeshVertexInc.h"
|
||||
|
||||
typedef struct {
|
||||
GenericMeshVertexInc base;
|
||||
vec3 norm;
|
||||
vec3 tang_U;
|
||||
vec3 tang_V;
|
||||
} GenericMeshVertex;
|
||||
|
||||
typedef struct {
|
||||
VecGenericMeshVertexInc vertices;
|
||||
VecU32 indexes;
|
||||
} GenericMeshTopology;
|
||||
|
||||
void GenericMeshTopology_drop(GenericMeshTopology self) {
|
||||
VecGenericMeshVertexInc_drop(self.vertices);
|
||||
VecU32_drop(self.indexes);
|
||||
}
|
||||
|
||||
GenericMeshTopology GenericMeshTopology_clone(const GenericMeshTopology* self) {
|
||||
return (GenericMeshTopology){.vertices = VecGenericMeshVertexInc_clone(&self->vertices), .indexes = VecU32_clone(&self->indexes)};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
VecU8 topology_path;
|
||||
VecU8 diffuse_texture_path;
|
||||
VecU8 normal_texture_path;
|
||||
VecU8 specular_texture_path;
|
||||
} AliceGenericMeshPath;
|
||||
|
||||
void AliceGenericMeshPath_drop(AliceGenericMeshPath self) {
|
||||
VecU8_drop(self.topology_path);
|
||||
VecU8_drop(self.diffuse_texture_path);
|
||||
VecU8_drop(self.normal_texture_path);
|
||||
VecU8_drop(self.specular_texture_path);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
mat4 model_t;
|
||||
} GenericMeshInstanceInc;
|
||||
|
||||
typedef struct {
|
||||
GenericMeshInstanceInc base;
|
||||
mat3 normal_t;
|
||||
} GenericMeshInstance;
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
vec3 color;
|
||||
} ShinyMeshVertexInc;
|
||||
|
||||
typedef struct {
|
||||
ShinyMeshVertexInc base;
|
||||
vec3 normal;
|
||||
} ShinyMeshVertex;
|
||||
#include "../../../gen/l1/eve/alice/VecAndSpan_ShinyMeshVertexInc.h"
|
||||
|
||||
typedef struct {
|
||||
VecShinyMeshVertexInc vertices;
|
||||
VecU32 indexes;
|
||||
} ShinyMeshTopology;
|
||||
|
||||
void ShinyMeshTopology_drop(ShinyMeshTopology self) {
|
||||
VecShinyMeshVertexInc_drop(self.vertices);
|
||||
VecU32_drop(self.indexes);
|
||||
}
|
||||
|
||||
ShinyMeshTopology ShinyMeshTopology_clone(const ShinyMeshTopology* self) {
|
||||
return (ShinyMeshTopology){.vertices = VecShinyMeshVertexInc_clone(&self->vertices),
|
||||
VecU32_clone(&self->indexes)};
|
||||
}
|
||||
|
||||
|
||||
typedef struct{
|
||||
mat4 model_t;
|
||||
vec3 color_on;
|
||||
} ShinyMeshInstanceInc;
|
||||
|
||||
typedef struct {
|
||||
ShinyMeshInstanceInc base;
|
||||
mat3 normal_t;
|
||||
} ShinyMeshInstance;
|
||||
|
||||
typedef struct {
|
||||
vec2 win_scale;
|
||||
} Pipeline1PushRangeVertex;
|
||||
|
||||
typedef struct {
|
||||
float gamma_correction_factor;
|
||||
float hdr_factor;
|
||||
float lsd_factor;
|
||||
float anim_time;
|
||||
} Pipeline1PushRangeFragment;
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
char _padding_0[4];
|
||||
vec3 dir;
|
||||
char _padding_1[4];
|
||||
vec3 color;
|
||||
char _padding_2[4];
|
||||
float d;
|
||||
char _padding_3[12];
|
||||
} Pipeline0Spotlight;
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
char _padding_0[4];
|
||||
vec3 color;
|
||||
char _padding_1[4];
|
||||
} Pipeline0PointLight;
|
||||
|
||||
#define pipeline_0_ubo_point_light_max_count 120
|
||||
#define pipeline_0_ubo_spotlight_max_count 20
|
||||
|
||||
typedef struct {
|
||||
int point_light_count;
|
||||
int spotlight_count;
|
||||
char _padding_1[8];
|
||||
Pipeline0PointLight point_light_arr[pipeline_0_ubo_point_light_max_count];
|
||||
Pipeline0Spotlight spotlight_arr[pipeline_0_ubo_spotlight_max_count];
|
||||
} Pipeline0UBO;
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,244 +0,0 @@
|
||||
#ifndef prototype1_src_l2_alice_model_file_h
|
||||
#define prototype1_src_l2_alice_model_file_h
|
||||
|
||||
#include "../../../gen/l1/VecAndSpan_vec2.h"
|
||||
#include "../../../gen/l1/VecAndSpan_vec3.h"
|
||||
#include "../../l1_5/core/parsing_string.h"
|
||||
#include "../../l1/system/fileio.h"
|
||||
#include "assets.h"
|
||||
#include "stdalign.h"
|
||||
|
||||
static_assert(sizeof(float) == 4, "...");
|
||||
static_assert(sizeof(GenericMeshVertexInc) == 4 * (3 + 2), "...");
|
||||
static_assert(alignof(GenericMeshVertexInc) == 4, "...");
|
||||
static_assert(sizeof(ShinyMeshVertexInc) == 4 * (3 + 3), "...");
|
||||
static_assert(alignof(ShinyMeshVertexInc) == 4, "...");
|
||||
|
||||
/* Yes, at this point I really started thinking that maybe I should have written Alice as a template */
|
||||
|
||||
/* Works only within one machine. todo: rewrite to use .obj after the session is over */
|
||||
void alice_write_generic_mesh_to_file(GenericMeshTopology model, VecU8 file_path){
|
||||
U64 byte_size = sizeof(U64) * 2 +
|
||||
sizeof(GenericMeshVertexInc) * model.vertices.len + sizeof(U32) * model.indexes.len;
|
||||
VecU8 res = VecU8_new_zeroinit(byte_size);
|
||||
U8* buf = res.buf;
|
||||
*(U64*)buf = model.vertices.len;
|
||||
buf += sizeof(U64);
|
||||
*(U64*)buf = model.indexes.len;
|
||||
buf += sizeof(U64);
|
||||
memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(GenericMeshVertexInc));
|
||||
buf += model.vertices.len * sizeof(GenericMeshVertexInc);
|
||||
memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
|
||||
write_file_by_path(file_path, VecU8_to_span(&res));
|
||||
GenericMeshTopology_drop(model);
|
||||
VecU8_drop(res);
|
||||
}
|
||||
|
||||
GenericMeshTopology alice_expect_read_generic_mesh_from_file(VecU8 file_path){
|
||||
VecU8 read = read_file_by_path(file_path);
|
||||
U8* buf = read.buf;
|
||||
U64 remaining = read.len;
|
||||
if (remaining < sizeof(U64) * 2) {
|
||||
abortf("Too short\n");
|
||||
}
|
||||
U64 vertices_len = *(U64*)buf;
|
||||
buf += sizeof(U64);
|
||||
U64 indexes_len = *(U64*)buf;
|
||||
buf += sizeof(U64);
|
||||
if (vertices_len > 1000000 || indexes_len > 1000000) {
|
||||
abortf("Model is too big\n");
|
||||
}
|
||||
remaining -= sizeof(U64) * 2;
|
||||
if (remaining != vertices_len * sizeof(GenericMeshVertexInc) + indexes_len * sizeof(U32)) {
|
||||
abortf("Incorrect file size\n");
|
||||
}
|
||||
VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new_zeroinit(vertices_len);
|
||||
memcpy(vertices.buf, buf, vertices_len * sizeof(GenericMeshVertexInc));
|
||||
buf += vertices_len * sizeof(GenericMeshVertexInc);
|
||||
VecU32 indexes = VecU32_new_zeroinit(indexes_len);
|
||||
memcpy(indexes.buf, buf, indexes_len * sizeof(U32));
|
||||
return (GenericMeshTopology){.vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
void alice_write_shiny_mesh_to_file(ShinyMeshTopology model, VecU8 file_path){
|
||||
U64 byte_size = sizeof(U64) * 2 +
|
||||
sizeof(ShinyMeshVertexInc) * model.vertices.len + sizeof(U32) * model.indexes.len;
|
||||
VecU8 res = VecU8_new_zeroinit(byte_size);
|
||||
U8* buf = res.buf;
|
||||
*(U64*)buf = model.vertices.len;
|
||||
buf += sizeof(U64);
|
||||
*(U64*)buf = model.indexes.len;
|
||||
buf += sizeof(U64);
|
||||
memcpy(buf, model.vertices.buf, model.vertices.len * sizeof(ShinyMeshVertexInc));
|
||||
buf += model.vertices.len * sizeof(ShinyMeshVertexInc);
|
||||
memcpy(buf, model.indexes.buf, model.indexes.len * sizeof(U32));
|
||||
write_file_by_path(file_path, VecU8_to_span(&res));
|
||||
ShinyMeshTopology_drop(model);
|
||||
VecU8_drop(res);
|
||||
}
|
||||
|
||||
ShinyMeshTopology alice_expect_read_shiny_mesh_from_file(VecU8 file_path){
|
||||
VecU8 read = read_file_by_path(file_path);
|
||||
U8* buf = read.buf;
|
||||
U64 remaining = read.len;
|
||||
if (remaining < sizeof(U64) * 2) {
|
||||
abortf("Too short\n");
|
||||
}
|
||||
U64 vertices_len = *(U64*)buf;
|
||||
buf += sizeof(U64);
|
||||
U64 indexes_len = *(U64*)buf;
|
||||
buf += sizeof(U64);
|
||||
if (vertices_len > 10000 || indexes_len > 10000)
|
||||
abortf("Model is too big\n");
|
||||
remaining -= sizeof(U64) * 2;
|
||||
if (remaining != vertices_len * sizeof(ShinyMeshVertexInc) + indexes_len * sizeof(U32)) {
|
||||
abortf("Incorrect file size\n");
|
||||
}
|
||||
VecShinyMeshVertexInc vertices = VecShinyMeshVertexInc_new_zeroinit(vertices_len);
|
||||
memcpy(vertices.buf, buf, vertices_len * sizeof(ShinyMeshVertexInc));
|
||||
buf += vertices_len * sizeof(ShinyMeshVertexInc);
|
||||
VecU32 indexes = VecU32_new_zeroinit(indexes_len);
|
||||
memcpy(indexes.buf, buf, indexes_len * sizeof(U32));
|
||||
return (ShinyMeshTopology){.vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
/* Just read code, okay? Just read source code, I can't explain THAT */
|
||||
int alice_obj_file_parser_try_read_vert_index(SpanU8* rem, U64 limit, S32* ret_ind){
|
||||
SpanU8_parsing_try_read_char(rem, '/');
|
||||
U64 x;
|
||||
if (SpanU8_read_U64(rem, &x)) {
|
||||
*ret_ind = -1;
|
||||
} else {
|
||||
if (x == 0)
|
||||
return 1;
|
||||
x--;
|
||||
if (x >= limit)
|
||||
return 3;
|
||||
*ret_ind = (S32)x;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In wavefront .obj file each face consists of 3 vertices and each vertex in a face
|
||||
* can be specified in the following forms: v, v/vt, v//vn, v/vt/vn. vn is of course ignored,
|
||||
* because only sussies store normal vectors in a file.
|
||||
* Returns positive on error. 0 on success. Don't read source code
|
||||
*/
|
||||
int alice_obj_file_parser_try_read_vertex_data(SpanU8* rem, U64 vertices_pos_limit, U64 vertices_tex_limit,
|
||||
S32* ret_pos_ind, S32* ret_tex_ind){
|
||||
int ret;
|
||||
ret = alice_obj_file_parser_try_read_vert_index(rem, vertices_pos_limit, ret_pos_ind);
|
||||
if (ret) {
|
||||
return 3;
|
||||
}
|
||||
if (*ret_pos_ind < 0) {
|
||||
return 1;
|
||||
}
|
||||
ret = alice_obj_file_parser_try_read_vert_index(rem, vertices_tex_limit, ret_tex_ind);
|
||||
if (ret > 0) {
|
||||
return 3;
|
||||
}
|
||||
S32 who_cares;
|
||||
alice_obj_file_parser_try_read_vert_index(rem, UINT64_MAX, &who_cares);
|
||||
return 0;
|
||||
}
|
||||
|
||||
GenericMeshVertexInc alice_obj_file_parser_retrieve_data_from_vertex_arrays(
|
||||
const Vecvec3* vertex_pos, const Vecvec2* vertex_tex, S32 pos_ind, S32 tex_ind){
|
||||
return (GenericMeshVertexInc){
|
||||
.pos = *Vecvec3_at(vertex_pos, (U64)pos_ind),
|
||||
.tex = tex_ind >= 0 ? *Vecvec2_at(vertex_tex, (U64)tex_ind) : (vec2){0, 0}
|
||||
};
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/alice/OptionGenericMeshTopology.h"
|
||||
|
||||
/* My life f****** sucks so much */
|
||||
OptionGenericMeshTopology alice_read_generic_mesh_from_obj_file(VecU8 file_path){
|
||||
Vecvec3 vertex_pos = Vecvec3_new();
|
||||
Vecvec2 vertex_tex = Vecvec2_new();
|
||||
VecU8 text_buffer = read_file_by_path(file_path);
|
||||
VecGenericMeshVertexInc mesh_vertices = VecGenericMeshVertexInc_new();
|
||||
VecU32 mesh_indexes = VecU32_new();
|
||||
SpanU8 text = VecU8_to_span(&text_buffer);
|
||||
while (text.len > 0) {
|
||||
if (SpanU8_parsing_try_read_prefix(&text, cstr("v "))) {
|
||||
float x, y, z;
|
||||
if (SpanU8_read_float(&text, &x))
|
||||
goto failure;
|
||||
if (!SpanU8_parsing_try_read_char(&text, ' '))
|
||||
goto failure;
|
||||
if (SpanU8_read_float(&text, &y))
|
||||
goto failure;
|
||||
if (!SpanU8_parsing_try_read_char(&text, ' '))
|
||||
goto failure;
|
||||
if (SpanU8_read_float(&text, &z))
|
||||
goto failure;
|
||||
if (!SpanU8_parsing_try_read_char(&text, '\n'))
|
||||
goto failure;
|
||||
Vecvec3_append(&vertex_pos, (vec3){x, y, z});
|
||||
} else if (SpanU8_parsing_try_read_prefix(&text, cstr("vt "))) {
|
||||
float u, v;
|
||||
if (SpanU8_read_float(&text, &u))
|
||||
goto failure;
|
||||
if (!SpanU8_parsing_try_read_char(&text, ' '))
|
||||
goto failure;
|
||||
if (SpanU8_read_float(&text, &v))
|
||||
goto failure;
|
||||
if (!SpanU8_parsing_try_read_char(&text, '\n'))
|
||||
goto failure;
|
||||
Vecvec2_append(&vertex_tex, (vec2){u, v});
|
||||
} else if (SpanU8_parsing_try_read_prefix(&text, cstr("f "))) {
|
||||
S32 pos_ind, tex_ind;
|
||||
if (alice_obj_file_parser_try_read_vertex_data(&text,
|
||||
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
|
||||
goto failure;
|
||||
}
|
||||
GenericMeshVertexInc A = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
|
||||
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
|
||||
if (!SpanU8_parsing_try_read_char(&text, ' '))
|
||||
goto failure;
|
||||
|
||||
if (alice_obj_file_parser_try_read_vertex_data(&text,
|
||||
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
|
||||
goto failure;
|
||||
}
|
||||
GenericMeshVertexInc B = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
|
||||
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
|
||||
if (!SpanU8_parsing_try_read_char(&text, ' '))
|
||||
goto failure;
|
||||
|
||||
if (alice_obj_file_parser_try_read_vertex_data(&text,
|
||||
vertex_pos.len, vertex_tex.len, &pos_ind, &tex_ind)) {
|
||||
goto failure;
|
||||
}
|
||||
GenericMeshVertexInc C = alice_obj_file_parser_retrieve_data_from_vertex_arrays(
|
||||
&vertex_pos, &vertex_tex, pos_ind, tex_ind);
|
||||
if (!SpanU8_parsing_try_read_char(&text, '\n'))
|
||||
goto failure;
|
||||
|
||||
VecGenericMeshVertexInc_append(&mesh_vertices, A);
|
||||
VecGenericMeshVertexInc_append(&mesh_vertices, B);
|
||||
VecGenericMeshVertexInc_append(&mesh_vertices, C);
|
||||
U64 k = mesh_vertices.len;
|
||||
VecU32_append_span(&mesh_indexes, (SpanU32){.data = (U32[]){k - 3, k - 2, k - 1}, .len = 3});
|
||||
} else {
|
||||
SpanU8_parsing_skip_entire_line(&text);
|
||||
}
|
||||
}
|
||||
/* End */
|
||||
return Some_GenericMeshTopology((GenericMeshTopology){.vertices = mesh_vertices, .indexes = mesh_indexes});
|
||||
failure:
|
||||
VecGenericMeshVertexInc_drop(mesh_vertices);
|
||||
VecU32_drop(mesh_indexes);
|
||||
return None_GenericMeshTopology();
|
||||
}
|
||||
|
||||
GenericMeshTopology alice_expect_read_generic_mesh_from_obj_file(VecU8 file_path){
|
||||
OptionGenericMeshTopology option = alice_read_generic_mesh_from_obj_file(file_path);
|
||||
return OptionGenericMeshTopology_expect(option);
|
||||
}
|
||||
|
||||
/* No beauty, just pure brute force */
|
||||
|
||||
#endif
|
||||
@ -1,211 +0,0 @@
|
||||
{-# LANGUAGE ForeignFunctionInterface #-}
|
||||
{-# LANGUAGE DuplicateRecordFields #-}
|
||||
{-# LANGUAGE DisambiguateRecordFields #-}
|
||||
{-# LANGUAGE RecordWildCards #-}
|
||||
{-# LANGUAGE NamedFieldPuns #-}
|
||||
{-# LANGUAGE RankNTypes #-}
|
||||
|
||||
module Allie (WlKeyboardKeyState, LucyFace, LucyFaceFixedSize, AliceGenericMeshHand, AliceShinyMeshHand,
|
||||
AliceGenericMeshInstance(..), AliceShinyMeshInstance(..), AlicePointLight(..), alicePipeline0PointLightMaxCount,
|
||||
Callbacks(..), aliceMainloop, newAlice, aliceSetSkyColor, aliceNewLucyFace,
|
||||
aliceLucyFaceOfSize, lucyFaceAddGlyphs, aliceClearText, aliceAddText,
|
||||
aliceAddGenericMeshHand, aliceGenericMeshResizeInstanceArr, aliceGenericMeshSetInst,
|
||||
aliceAddShinyMeshHand, aliceShinyMeshResizeInstanceArr, aliceShinyMeshSetInst, aliceGetCamBack,
|
||||
aliceGetCamRight, aliceGetCamUp, aliceSetFOV,
|
||||
aliceGetCamPos, aliceSetCamPos, aliceSetPointLightCount, aliceSetPointLight,
|
||||
aliceIsPressed
|
||||
) where
|
||||
|
||||
import Geom
|
||||
|
||||
import Data.Word (Word8, Word16, Word32, Word64)
|
||||
import Data.Int (Int8, Int16, Int32, Int64)
|
||||
import Foreign.Ptr (Ptr, FunPtr, nullPtr, plusPtr, castPtr)
|
||||
import Foreign.Marshal.Alloc (alloca)
|
||||
import Foreign.Storable (Storable(..))
|
||||
import qualified Data.Text
|
||||
import Data.Text.Encoding (encodeUtf8)
|
||||
import Data.ByteString (useAsCStringLen)
|
||||
|
||||
type Alice = Ptr Word8
|
||||
|
||||
-- Ready
|
||||
foreign import ccall "allie_alice_new" newAlice :: IO Alice
|
||||
|
||||
data WlKeyboardKeyState = WlKeyboardKeyStateReleased | WlKeyboardKeyStatePressed | WlKeyboardKeyStateRepeated
|
||||
|
||||
-- data AliceAnotherFrameCap s = AliceAnotherFrameCap Alice
|
||||
|
||||
foreign import ccall "wrapper" allieMkAliceOnWaylandKeyboardKey ::
|
||||
(Ptr () -> Word32 -> Word32 -> IO ()) -> IO (FunPtr (Ptr () -> Word32 -> Word32 -> IO ()))
|
||||
foreign import ccall "wrapper" allieMkAliceOnAnotherFrame ::
|
||||
(Ptr () -> Float -> IO ()) -> IO (FunPtr (Ptr () -> Float -> IO ()))
|
||||
|
||||
-- All of that is inside Alice. They hold pointers to Alice
|
||||
type LucyFace = Ptr Word8
|
||||
-- Actually stores a pointer to rb-tree node in LucyFace tree. Must not be deleted by without caution
|
||||
type LucyFaceFixedSize = Ptr Word8
|
||||
|
||||
type AliceGenericMeshHand = Ptr Word8
|
||||
|
||||
type AliceShinyMeshHand = Ptr Word8
|
||||
|
||||
data AliceGenericMeshInstance = AliceGenericMeshInstance Mat4
|
||||
|
||||
instance Storable AliceGenericMeshInstance where
|
||||
sizeOf _ = sizeOf (undefined :: Mat4)
|
||||
alignment _ = 4
|
||||
peek _ = error "Please don't"
|
||||
poke ptr (AliceGenericMeshInstance modelT) = poke (castPtr ptr :: Ptr Mat4) modelT
|
||||
|
||||
-- model_t color_on
|
||||
data AliceShinyMeshInstance = AliceShinyMeshInstance Mat4 Vec3
|
||||
|
||||
instance Storable AliceShinyMeshInstance where
|
||||
sizeOf _ = sizeOf (undefined :: Mat4) + sizeOf (undefined :: Vec3)
|
||||
alignment _ = 4
|
||||
peek _ = error "Don't do that, please"
|
||||
poke ptr (AliceShinyMeshInstance modelT colorOn) = do
|
||||
poke (castPtr ptr :: Ptr Mat4) modelT
|
||||
poke (castPtr (ptr `plusPtr` (sizeOf (undefined :: Mat4))) :: Ptr Vec3) colorOn
|
||||
|
||||
-- pos color
|
||||
data AlicePointLight = AlicePointLight Vec3 Vec3
|
||||
|
||||
alicePipeline0PointLightMaxCount :: Int
|
||||
alicePipeline0PointLightMaxCount = 120
|
||||
|
||||
data Callbacks = Callbacks {
|
||||
onWaylandKeyboardKey :: (Word32 -> Word32 -> IO ()),
|
||||
onAnotherFrame :: (Float -> IO ())
|
||||
-- onAnotherFrame :: (forall s. AliceAnotherFrameCap s -> IO ())
|
||||
}
|
||||
|
||||
instance Storable Callbacks where
|
||||
sizeOf _ = 8 + 8
|
||||
alignment _ = 8
|
||||
peek _ = error "Зачем тебе?"
|
||||
poke ptr Callbacks{..} = do
|
||||
poke (castPtr ptr) =<< allieMkAliceOnWaylandKeyboardKey (\_ -> onWaylandKeyboardKey)
|
||||
poke (castPtr ptr `plusPtr` 8) =<< allieMkAliceOnAnotherFrame (\_ -> onAnotherFrame)
|
||||
|
||||
foreign import ccall "allie_alice_mainloop" allieAliceMainloop :: Alice -> Ptr Callbacks -> IO ()
|
||||
|
||||
aliceMainloop :: Alice -> Callbacks -> IO ()
|
||||
aliceMainloop alice cb = alloca $ \ptr -> do
|
||||
poke ptr cb
|
||||
allieAliceMainloop alice ptr
|
||||
|
||||
useAsUtf8StringLen :: String -> (Ptr Word8 -> Word64 -> IO a) -> IO a
|
||||
useAsUtf8StringLen str cb = useAsCStringLen (encodeUtf8 $ Data.Text.pack $ str) $ \(cstr, len) -> cb (castPtr cstr) (fromIntegral len)
|
||||
|
||||
foreign import ccall "allie_alice_set_sky_color" allieAliceSetSkyColor :: Alice -> Float -> Float -> Float -> Float -> IO ()
|
||||
|
||||
aliceSetSkyColor :: Alice -> Vec4 -> IO ()
|
||||
aliceSetSkyColor alice (Vec4 x y z w) = allieAliceSetSkyColor alice x y z w
|
||||
|
||||
foreign import ccall "allie_alice_new_lucy_face" allieAliceNewLucyFace :: Alice -> Ptr Word8 -> Word64 -> IO LucyFace
|
||||
|
||||
aliceNewLucyFace :: Alice -> String -> IO LucyFace
|
||||
aliceNewLucyFace alice str = useAsUtf8StringLen str $ \dt len -> allieAliceNewLucyFace alice dt len
|
||||
|
||||
-- Maps one to one. Fine
|
||||
foreign import ccall "allie_alice_lucy_face_of_size" aliceLucyFaceOfSize :: LucyFace -> Word32 -> IO LucyFaceFixedSize
|
||||
|
||||
-- Mapsone to one. Good. Too bad right now this only works with one range at a time
|
||||
-- (which means one range per image)
|
||||
foreign import ccall "allie_lucy_face_add_glyphs" lucyFaceAddGlyphs :: LucyFaceFixedSize -> Word32 -> Word32 -> IO ()
|
||||
|
||||
-- Maps one to one
|
||||
foreign import ccall "allie_alice_clear_text" aliceClearText :: Alice -> IO ()
|
||||
|
||||
foreign import ccall "allie_alice_add_text" allieAliceAddText :: Alice -> LucyFaceFixedSize -> Float -> Float -> Float -> Float ->
|
||||
Ptr Word8 -> Word64 -> Int32 -> Int32 -> IO ()
|
||||
|
||||
aliceAddText :: Alice -> LucyFaceFixedSize -> Vec4 -> String -> Int32 -> Int32 -> IO ()
|
||||
aliceAddText alice ffs (Vec4 cx cy cz cw) str startPosX startPosY = useAsUtf8StringLen str $ \dt len ->
|
||||
allieAliceAddText alice ffs cx cy cz cw dt len startPosX startPosY
|
||||
|
||||
foreign import ccall "allie_alice_add_generic_mesh_hand" allieAliceAddGenericMeshHand :: Alice ->
|
||||
Ptr Word8 -> Word64 -> Ptr Word8 -> Word64 -> Ptr Word8 -> Word64 -> Ptr Word8 -> Word64 -> IO AliceGenericMeshHand
|
||||
|
||||
-- Path to mesh topology file, path to diffuse texture, path to normal texture, path to specular texture
|
||||
aliceAddGenericMeshHand :: Alice -> String -> String -> String -> String -> IO AliceGenericMeshHand
|
||||
aliceAddGenericMeshHand alice p1 p2 p3 p4 = useAsUtf8StringLen p1 $ \d1 l1 ->
|
||||
(useAsUtf8StringLen p2 $ \d2 l2 -> (useAsUtf8StringLen p3 $ \d3 l3 -> (useAsUtf8StringLen p4 $ \d4 l4 ->
|
||||
allieAliceAddGenericMeshHand alice d1 l1 d2 l2 d3 l3 d4 l4)))
|
||||
|
||||
|
||||
foreign import ccall "allie_alice_add_shiny_mesh_hand" allie_alice_add_shiny_mesh_hand :: Alice -> Ptr Word8 -> Word64 -> IO AliceShinyMeshHand
|
||||
|
||||
aliceAddShinyMeshHand :: Alice -> String -> IO AliceShinyMeshHand
|
||||
aliceAddShinyMeshHand alice p = useAsUtf8StringLen p $ \dt len -> allie_alice_add_shiny_mesh_hand alice dt len
|
||||
|
||||
-- Maps well
|
||||
foreign import ccall "allie_alice_generic_mesh_resize_instance_arr" aliceGenericMeshResizeInstanceArr :: Alice -> AliceGenericMeshHand -> Word64 -> IO ()
|
||||
|
||||
foreign import ccall "allie_alice_shiny_mesh_resize_instance_arr" aliceShinyMeshResizeInstanceArr :: Alice -> AliceShinyMeshHand -> Word64 -> IO ()
|
||||
|
||||
foreign import ccall "allie_alice_generic_mesh_set_inst" allieAliceGenericMeshSetInst :: AliceGenericMeshHand -> Word64 -> Ptr AliceGenericMeshInstance -> IO ()
|
||||
|
||||
aliceGenericMeshSetInst :: AliceGenericMeshHand -> Word64 -> AliceGenericMeshInstance -> IO ()
|
||||
aliceGenericMeshSetInst mesh index obj = alloca $ \ptr -> do
|
||||
poke ptr obj
|
||||
allieAliceGenericMeshSetInst mesh index ptr
|
||||
|
||||
foreign import ccall "allie_alice_shiny_mesh_set_inst" allie_alice_shiny_mesh_set_inst :: AliceShinyMeshHand -> Word64 -> Ptr AliceShinyMeshInstance -> IO ()
|
||||
|
||||
aliceShinyMeshSetInst :: AliceShinyMeshHand -> Word64 -> AliceShinyMeshInstance -> IO ()
|
||||
aliceShinyMeshSetInst mesh index obj = alloca $ \ptr -> do
|
||||
poke ptr obj
|
||||
allie_alice_shiny_mesh_set_inst mesh index ptr
|
||||
|
||||
|
||||
foreign import ccall "allie_alice_get_cam_back" allie_alice_get_cam_back :: Alice -> Ptr Vec3 -> IO ()
|
||||
|
||||
aliceGetCamBack :: Alice -> IO Vec3
|
||||
aliceGetCamBack alice = alloca $ \ptr -> do
|
||||
allie_alice_get_cam_back alice ptr
|
||||
peek ptr
|
||||
|
||||
foreign import ccall "allie_alice_get_cam_right" allie_alice_get_cam_right :: Alice -> Ptr Vec3 -> IO ()
|
||||
|
||||
aliceGetCamRight :: Alice -> IO Vec3
|
||||
aliceGetCamRight alice = alloca $ \ptr -> do
|
||||
allie_alice_get_cam_right alice ptr
|
||||
peek ptr
|
||||
|
||||
foreign import ccall "allie_alice_get_cam_up" allie_alice_get_cam_up :: Alice -> Ptr Vec3 -> IO ()
|
||||
|
||||
aliceGetCamUp :: Alice -> IO Vec3
|
||||
aliceGetCamUp alice = alloca $ \ptr -> do
|
||||
allie_alice_get_cam_up alice ptr
|
||||
peek ptr
|
||||
|
||||
|
||||
foreign import ccall "allie_alice_get_cam_pos" allie_alice_get_cam_pos :: Alice -> Ptr Vec3 -> IO ()
|
||||
|
||||
aliceGetCamPos :: Alice -> IO Vec3
|
||||
aliceGetCamPos alice = alloca $ \ptr -> do
|
||||
allie_alice_get_cam_pos alice ptr
|
||||
peek ptr
|
||||
|
||||
foreign import ccall "allie_alice_set_cam_pos" allie_alice_set_cam_pos :: Alice -> Float -> Float -> Float -> IO ()
|
||||
|
||||
aliceSetCamPos :: Alice -> Vec3 -> IO ()
|
||||
aliceSetCamPos alice (Vec3 x y z) = allie_alice_set_cam_pos alice x y z
|
||||
|
||||
-- Easy mapping
|
||||
foreign import ccall "allie_alice_set_fov" aliceSetFOV :: Alice -> Float -> IO ()
|
||||
|
||||
-- Maps well
|
||||
foreign import ccall "allie_alice_set_point_light_count" aliceSetPointLightCount :: Alice -> Int -> IO ()
|
||||
|
||||
foreign import ccall "allie_alice_set_point_light" allie_alice_set_point_light :: Alice -> Int
|
||||
-> Float -> Float -> Float -> Float -> Float -> Float -> IO ()
|
||||
|
||||
aliceSetPointLight :: Alice -> Int -> AlicePointLight -> IO ()
|
||||
aliceSetPointLight alice index (AlicePointLight (Vec3 px py pz) (Vec3 cx cy cz)) =
|
||||
allie_alice_set_point_light alice index px py pz cx cy cz
|
||||
|
||||
foreign import ccall "alice_is_pressed" aliceIsPressed :: Alice -> Word32 -> IO Bool
|
||||
@ -1,139 +0,0 @@
|
||||
module Geom(Vec2(..), Vec3(..), Vec4(..), Mat4(..), Addable(..), Multipliable(..), mat4Transit, mat4rot3d,
|
||||
HasLength, normalize) where
|
||||
|
||||
import Foreign.Storable(Storable(..))
|
||||
import Foreign.Ptr (Ptr, castPtr, plusPtr)
|
||||
|
||||
data Vec2 = Vec2 !Float !Float
|
||||
deriving (Eq, Show)
|
||||
|
||||
data Vec3 = Vec3 !Float !Float !Float
|
||||
deriving (Eq, Show)
|
||||
|
||||
data Vec4 = Vec4 !Float !Float !Float !Float
|
||||
deriving (Eq, Show)
|
||||
|
||||
infixl 6 ^+^
|
||||
class Addable a where
|
||||
(^+^) :: a -> a -> a
|
||||
|
||||
instance Addable Vec2 where
|
||||
(Vec2 ax ay) ^+^ (Vec2 bx by) = Vec2 (ax + bx) (ay + by)
|
||||
|
||||
instance Addable Vec3 where
|
||||
(Vec3 ax ay az) ^+^ (Vec3 bx by bz) =
|
||||
Vec3 (ax + bx) (ay + by) (az + bz)
|
||||
|
||||
instance Addable Vec4 where
|
||||
(Vec4 a1 a2 a3 a4) ^+^ (Vec4 b1 b2 b3 b4) =
|
||||
Vec4 (a1 + b1) (a2 + b2) (a3 + b3) (a4 + b4)
|
||||
|
||||
|
||||
infixl 7 ^*^
|
||||
class Multipliable a b c where
|
||||
(^*^) :: a -> b -> c
|
||||
|
||||
instance Multipliable Vec2 Float Vec2 where
|
||||
(Vec2 ax ay) ^*^ b = Vec2 (ax * b) (ay * b)
|
||||
|
||||
instance Multipliable Vec3 Float Vec3 where
|
||||
(Vec3 ax ay az) ^*^ b = Vec3 (ax * b) (ay * b) (az * b)
|
||||
|
||||
instance Multipliable Vec4 Float Vec4 where
|
||||
(Vec4 ax ay az aw) ^*^ b = Vec4 (ax * b) (ay * b) (az * b) (aw * b)
|
||||
|
||||
data Mat4 = Mat4 !Vec4 !Vec4 !Vec4 !Vec4
|
||||
|
||||
instance Multipliable Mat4 Vec4 Vec4 where
|
||||
(Mat4 vx vy vz vw) ^*^ (Vec4 ax ay az aw) = (vx ^*^ ax ^+^ vy ^*^ ay ^+^ vz ^*^ az ^+^ vw ^*^ aw)
|
||||
|
||||
instance Multipliable Mat4 Mat4 Mat4 where
|
||||
m ^*^ (Mat4 bx by bz bw) = Mat4 (m ^*^ bx) (m ^*^ by) (m ^*^ bz) (m ^*^ bw)
|
||||
|
||||
mat4Transit :: Vec3 -> Mat4
|
||||
mat4Transit (Vec3 x y z) = Mat4 (Vec4 1 0 0 0) (Vec4 0 1 0 0) (Vec4 0 0 1 0) (Vec4 x y z 1)
|
||||
|
||||
mat4rot3d :: Vec3 -> Float -> Mat4
|
||||
mat4rot3d (Vec3 rx ry rz) a = let cosa = cos(a) in let sina = sin(a) in
|
||||
Mat4
|
||||
(Vec4 (rx * rx * (1 - cosa) + cosa) (rx * ry * (1 - cosa) + sina * rz) (rx * rz * (1 - cosa) - sina * ry) 0)
|
||||
(Vec4 (rx * ry * (1 - cosa) - sina * rz) (ry * ry * (1 - cosa) + cosa) (ry * rz * (1 - cosa) + sina * rx) 0)
|
||||
(Vec4 (rx * rz * (1 - cosa) + sina * ry) (ry * rz * (1 - cosa) - sina * rx) (rz * rz * (1 - cosa) + cosa) 0)
|
||||
|
||||
(Vec4 0 0 0 1)
|
||||
|
||||
|
||||
instance Storable Vec2 where
|
||||
sizeOf _ = 2 * sizeOf (undefined :: Float)
|
||||
alignment _ = 4
|
||||
peek ptr = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
x <- peek fptr
|
||||
y <- peek (fptr `plusPtr` sizeOf (undefined :: Float))
|
||||
return $ Vec2 x y
|
||||
poke ptr (Vec2 x y) = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
poke fptr x
|
||||
poke (fptr `plusPtr` sizeOf (undefined :: Float)) y
|
||||
|
||||
instance Storable Vec3 where
|
||||
sizeOf _ = 3 * sizeOf (undefined :: Float)
|
||||
alignment _ = 4
|
||||
peek ptr = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
let floatSize = sizeOf (undefined :: Float)
|
||||
x <- peek fptr
|
||||
y <- peek (fptr `plusPtr` floatSize)
|
||||
z <- peek (fptr `plusPtr` (2 * floatSize))
|
||||
return $ Vec3 x y z
|
||||
poke ptr (Vec3 x y z) = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
let floatSize = sizeOf (undefined :: Float)
|
||||
poke fptr x
|
||||
poke (fptr `plusPtr` floatSize) y
|
||||
poke (fptr `plusPtr` (2 * floatSize)) z
|
||||
|
||||
instance Storable Vec4 where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Float)
|
||||
alignment _ = 4
|
||||
peek ptr = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
let floatSize = sizeOf (undefined :: Float)
|
||||
x <- peek fptr
|
||||
y <- peek (fptr `plusPtr` floatSize)
|
||||
z <- peek (fptr `plusPtr` (2 * floatSize))
|
||||
w <- peek (fptr `plusPtr` (3 * floatSize))
|
||||
return $ Vec4 x y z w
|
||||
poke ptr (Vec4 x y z w) = do
|
||||
let fptr = castPtr ptr :: Ptr Float
|
||||
let floatSize = sizeOf (undefined :: Float)
|
||||
poke fptr x
|
||||
poke (fptr `plusPtr` floatSize) y
|
||||
poke (fptr `plusPtr` (2 * floatSize)) z
|
||||
poke (fptr `plusPtr` (3 * floatSize)) w
|
||||
|
||||
instance Storable Mat4 where
|
||||
sizeOf _ = 4 * sizeOf (undefined :: Vec4)
|
||||
alignment _ = 4
|
||||
peek ptr = do
|
||||
let vec4Size = sizeOf (undefined :: Vec4)
|
||||
v1 <- peek (castPtr ptr)
|
||||
v2 <- peek (ptr `plusPtr` vec4Size)
|
||||
v3 <- peek (ptr `plusPtr` (2 * vec4Size))
|
||||
v4 <- peek (ptr `plusPtr` (3 * vec4Size))
|
||||
return $ Mat4 v1 v2 v3 v4
|
||||
poke ptr (Mat4 v1 v2 v3 v4) = do
|
||||
let vec4Size = sizeOf (undefined :: Vec4)
|
||||
poke (castPtr ptr) v1
|
||||
poke (ptr `plusPtr` vec4Size) v2
|
||||
poke (ptr `plusPtr` (2 * vec4Size)) v3
|
||||
poke (ptr `plusPtr` (3 * vec4Size)) v4
|
||||
|
||||
class HasLength a where
|
||||
vlength :: a -> Float
|
||||
|
||||
normalize :: (Multipliable a Float a, HasLength a) => a -> a
|
||||
normalize v = v ^*^ (1 / (vlength v))
|
||||
|
||||
instance HasLength Vec2 where
|
||||
vlength (Vec2 a b) = sqrt (a * a + b * b)
|
||||
2198
src/l2/allie/allie.c
2198
src/l2/allie/allie.c
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
/* This file generates l2 stuff, but not code. It generates assets. For example: normal textures for simple models */
|
||||
|
||||
#include "r4.h"
|
||||
#include "../../l1/codegen/codegen.h"
|
||||
|
||||
int main(){
|
||||
mkdir_nofail("l2");
|
||||
gen_assets_for_r4();
|
||||
finish_layer(cstr("l2"));
|
||||
}
|
||||
910
src/l2/anne/r4.h
910
src/l2/anne/r4.h
@ -1,910 +0,0 @@
|
||||
#ifndef prototype1_src_l2_anne_r4_h
|
||||
#define prototype1_src_l2_anne_r4_h
|
||||
|
||||
#include "../alice/assets.h"
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "../marie/rasterization.h"
|
||||
#include "../marie/texture_processing.h"
|
||||
#include <math.h>
|
||||
|
||||
/* generating my cool textures2 */
|
||||
|
||||
#include "../../../gen/l1/VecAndSpan_vec2.h"
|
||||
// todo: move to marie
|
||||
void TextureDataR8_pixel_maxing(TextureDataR8* self, S32 x, S32 y, U8 val) {
|
||||
if (x < 0 || y < 0 || (size_t)x >= self->width)
|
||||
return;
|
||||
size_t p = (size_t)x + (size_t)y * self->width;
|
||||
if (p >= self->pixels.len)
|
||||
return;
|
||||
U8 b = *TextureDataR8_at(self, x, y);
|
||||
*TextureDataR8_mat(self, x, y) = MAX_U8(b, val);
|
||||
}
|
||||
|
||||
// todo: move to marie
|
||||
U8 a_small_cute_gradient(float r_cut, float r_decay, float dist) {
|
||||
return dist > r_cut ? 0 : (dist < r_decay) ? 255 : (U8)roundf( 255.f * (r_cut - dist) / (r_cut - r_decay) );
|
||||
}
|
||||
|
||||
// todo: move it to marie
|
||||
void TextureDataR8_draw_spot_maxing(TextureDataR8* self, vec2 v, float r_cut, float r_decay) {
|
||||
S32 sx = (S32)roundf(v.x - .5f);
|
||||
S32 sy = (S32)roundf(v.y - .5f);
|
||||
S32 k = (S32)ceilf(r_cut);
|
||||
for (S32 i = sx-k; i <= sx+k; i++) {
|
||||
for (S32 j = sy-k; j <= sy+k; j++) {
|
||||
float dx = 0.5f + (float)i - v.x;
|
||||
float dy = 0.5f + (float)j - v.y;
|
||||
float dist = sqrtf(dx*dx + dy*dy);
|
||||
TextureDataR8_pixel_maxing(self, i, j, a_small_cute_gradient(r_cut, r_decay, dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// todo: move to marie, not used here
|
||||
vec2 perimeter_line_get_thorn_on_vertex(Spanvec2 P, size_t i, float thickness) {
|
||||
assert(P.len >= 3 && i < P.len);
|
||||
vec2 A = *Spanvec2_at(P, i ? i - 1 : P.len - 1);
|
||||
vec2 B = *Spanvec2_at(P, i);
|
||||
vec2 C = *Spanvec2_at(P, i == P.len - 1 ? 0 : i + 1);
|
||||
vec2 b = vec2_normalize(vec2_minus_vec2(A, B));
|
||||
vec2 f = vec2_minus_vec2(C, B);
|
||||
float cr = b.x * f.y - b.y * f.x;
|
||||
float dt = b.x * f.x + b.y * f.y;
|
||||
float a = M_PIf + atan2f(cr, dt);
|
||||
float t = M_PI_2f + a / 2;
|
||||
return vec2_mul_scal(mat2_mul_vec2(marie_2d_rot_mat2(t), b), thickness / sinf(t));
|
||||
}
|
||||
|
||||
// todo: move to marie
|
||||
/* It is assumed that A != B */
|
||||
float distance_to_segment(vec2 A, vec2 B, vec2 P) {
|
||||
vec2 seg = vec2_minus_vec2(B, A);
|
||||
vec2 tg = vec2_minus_vec2(P, A);
|
||||
float t = vec2_dot(seg, tg) / vec2_dot(seg, seg);
|
||||
float c = marie_clamp_float(t, 0, 1);
|
||||
vec2 closest = vec2_add_vec2(A, vec2_mul_scal(seg, c));
|
||||
float len = vec2_length(vec2_minus_vec2(P, closest));
|
||||
return len;
|
||||
}
|
||||
|
||||
// todo: move to marie
|
||||
typedef struct {
|
||||
TextureDataR8* texture;
|
||||
vec2 A;
|
||||
vec2 B;
|
||||
float r_cut;
|
||||
float r_decay;
|
||||
} TextureDataR8_draw_perimeter_maxing_H_DrawGuest;
|
||||
|
||||
// todo: move to marie
|
||||
void TextureDataR8_draw_perimeter_maxing_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest* g = ug;
|
||||
if (TextureDataR8_is_inside(g->texture, x, y)) {
|
||||
vec2 P = {attr.x, attr.y};
|
||||
U8 clr = a_small_cute_gradient(g->r_cut, g->r_decay, distance_to_segment(g->A, g->B, P));
|
||||
TextureDataR8_pixel_maxing(g->texture, x, y, clr);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: move to marie
|
||||
void TextureDataR8_draw_perimeter_maxing_h_draw_triangle(
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest* aboba, vec2 a, vec2 b, vec2 c
|
||||
) {
|
||||
marie_rasterize_triangle_with_attr((MariePlaneVertAttr){a, {a.x, a.y, 0, 0}},
|
||||
(MariePlaneVertAttr){b, {b.x, b.y, 0, 0}}, (MariePlaneVertAttr){c, {c.x, c.y, 0, 0}},
|
||||
(FnMarieRasterizerCallback){TextureDataR8_draw_perimeter_maxing_h_draw_guest, aboba});
|
||||
}
|
||||
|
||||
|
||||
// todo: move to marie
|
||||
/* It is assumed that P[i] != P[i + 1] foreach i from 0 to P.len - 1 */
|
||||
void TextureDataR8_draw_perimeter_maxing(TextureDataR8* self, Spanvec2 P) {
|
||||
float r_cut = 5;
|
||||
float r_decay = 2;
|
||||
for (size_t i = 0; i < P.len; i++) {
|
||||
size_t ia = i == P.len - 1 ? 0 : i + 1;
|
||||
vec2 A = *Spanvec2_at(P, i);
|
||||
vec2 B = *Spanvec2_at(P, ia);
|
||||
vec2 hA = perimeter_line_get_thorn_on_vertex(P, i, r_cut);
|
||||
vec2 hB = perimeter_line_get_thorn_on_vertex(P, ia, r_cut);
|
||||
vec2 q0 = vec2_add_vec2(A, hA);
|
||||
vec2 q1 = vec2_add_vec2(B, hB);
|
||||
vec2 q2 = vec2_minus_vec2(B, hB);
|
||||
vec2 q3 = vec2_minus_vec2(A, hA);
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest aboba = { self, A, B, r_cut, r_decay };
|
||||
TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q1, q2);
|
||||
TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q2, q3);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
vec2 bl;
|
||||
vec2 tr;
|
||||
float height;
|
||||
float brd;
|
||||
} Wimbzle;
|
||||
|
||||
#include "../../../gen/l1/eve/r0/VecWimbzle.h"
|
||||
|
||||
typedef struct {
|
||||
vec2 center;
|
||||
float rad;
|
||||
float hc;
|
||||
} Nibzle;
|
||||
|
||||
#include "../../../gen/l1/eve/r0/VecNibzle.h"
|
||||
|
||||
typedef struct {
|
||||
VecWimbzle wimbzles;
|
||||
VecNibzle nibzles;
|
||||
} Bublazhuzhka;
|
||||
|
||||
Bublazhuzhka Bublazhuzhka_new() {
|
||||
return (Bublazhuzhka){.wimbzles = VecWimbzle_new(), .nibzles = VecNibzle_new()};
|
||||
}
|
||||
|
||||
void Bublazhuzhka_drop(Bublazhuzhka self) {
|
||||
VecWimbzle_drop(self.wimbzles);
|
||||
VecNibzle_drop(self.nibzles);
|
||||
}
|
||||
|
||||
void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDataR8* canvas, mat3x2 trop) {
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
|
||||
vec2 p1[4] = {mat3x2_mul_vec3(trop, vec2_and_one(A)), mat3x2_mul_vec3(trop, vec2_and_one(B)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(D)), mat3x2_mul_vec3(trop, vec2_and_one(C))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p1, ARRAY_SIZE(p1)});
|
||||
vec2 p2[4] = {mat3x2_mul_vec3(trop, vec2_and_one(E)), mat3x2_mul_vec3(trop, vec2_and_one(F)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(H)), mat3x2_mul_vec3(trop, vec2_and_one(G))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p2, ARRAY_SIZE(p2)});
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_at(&self->nibzles, i);
|
||||
Vecvec2 p = Vecvec2_new_zeroinit(13);
|
||||
for (int j = 0; j < 13; j++) {
|
||||
float a = (float)j * 2 * M_PIf / 13;
|
||||
*Vecvec2_mat(&p, j) = mat3x2_mul_vec3(trop, vec2_and_one(vec2_add_vec2(sphere.center,
|
||||
vec2_mul_scal(marie_trigonom_circle(a), sphere.rad))));
|
||||
}
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, Vecvec2_to_span(&p));
|
||||
Vecvec2_drop(p);
|
||||
TextureDataR8_draw_spot_maxing(canvas, mat3x2_mul_vec3(trop, vec2_and_one(sphere.center)), 3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Bublazhuzhka fill_rectangle_with_crap(float w, float h) {
|
||||
S32 k = MAX_S32(0, (S32)floorf((w/h + 0.1f) / 0.7f));
|
||||
VecWimbzle wimbzles = VecWimbzle_new_zeroinit(k);
|
||||
VecNibzle nibzles = VecNibzle_new_zeroinit(2 * k);
|
||||
float start = k != 1 ? h * 0.2f : ((w - 0.2f * h) / 2);
|
||||
float d = k > 1 ? ((w - h * 0.4f - h * 0.2f * (float)k) / (float)(k - 1)) : 0;
|
||||
for (S32 i = 0; i < k; i++) {
|
||||
float x = start + (d + h * 0.2f) * (float)i;
|
||||
*VecWimbzle_mat(&wimbzles, i) = (Wimbzle){.bl = {x + 0.02f * h, 0.27f * h}, .tr = {x + 0.18f * h, h * 0.73f}, .height = h * 0.03f, .brd = h * 0.03f};
|
||||
/* hc is a height coefficient*/
|
||||
*VecNibzle_mat(&nibzles, 2 * i) = (Nibzle){.center = {x + 0.10f * h, 0.11f * h}, .rad = h * 0.05f, .hc = 0.75f};
|
||||
*VecNibzle_mat(&nibzles, 2 * i + 1) = (Nibzle){.center = {x + 0.10f * h, 0.89f * h}, .rad = h * 0.05f, .hc = 0.75f};
|
||||
}
|
||||
return (Bublazhuzhka){.wimbzles = wimbzles, .nibzles = nibzles};
|
||||
}
|
||||
|
||||
vec2 Bublazhuzhka_get_derivative(const Bublazhuzhka* self, vec2 v) {
|
||||
vec2 sum = { 0 };
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
float slp = rect.height / rect.brd;
|
||||
if (A.x < v.x && v.x < E.x && marie_surface(E, A, v) > 0 && marie_surface(C, G, v) > 0) {
|
||||
sum.x += slp;
|
||||
} else if (F.x < v.x && v.x < B.x && marie_surface(B, F, v) > 0 && marie_surface(H, D, v) > 0) {
|
||||
sum.x -= slp;
|
||||
} else if (C.y < v.y && v.y < G.y && marie_surface(G, C, v) > 0 && marie_surface(D, H, v) > 0) {
|
||||
sum.y += slp;
|
||||
} else if (F.y < v.y && v.y < B.y && marie_surface(A, E, v) > 0 && marie_surface(F, B, v) > 0) {
|
||||
sum.y -= slp;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_at(&self->nibzles, i);
|
||||
float sq_h = pow2f(sphere.rad) - pow2f(v.x - sphere.center.x) - pow2f(v.y - sphere.center.y);
|
||||
if (sq_h <= 0)
|
||||
continue;
|
||||
float w = sphere.hc / sqrtf(sq_h);
|
||||
sum = vec2_add_vec2(sum, vec2_mul_scal(vec2_minus_vec2(sphere.center, v), w));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
cvec3 Bublazhuzhka_get_color(const Bublazhuzhka* self, vec2 v) {
|
||||
float flats = 0;
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
float slp = rect.height / rect.brd;
|
||||
if (A.x < v.x && v.x < E.x && marie_surface(E, A, v) > 0 && marie_surface(C, G, v) > 0) {
|
||||
return (cvec3){100, 30, 40};
|
||||
} else if (F.x < v.x && v.x < B.x && marie_surface(B, F, v) > 0 && marie_surface(H, D, v) > 0) {
|
||||
return (cvec3){70, 60, 45};
|
||||
} else if (C.y < v.y && v.y < G.y && marie_surface(G, C, v) > 0 && marie_surface(D, H, v) > 0) {
|
||||
return (cvec3){10, 100, 70};
|
||||
} else if (F.y < v.y && v.y < B.y && marie_surface(A, E, v) > 0 && marie_surface(F, B, v) > 0) {
|
||||
return (cvec3){25, 50, 110};
|
||||
} else if (E.x <= v.x && v.x <= F.x && G.y <= v.y && v.y <= F.y) {
|
||||
flats += rect.height;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_at(&self->nibzles, i);
|
||||
float sq_h = pow2f(sphere.rad) - pow2f(v.x - sphere.center.x) - pow2f(v.y - sphere.center.y);
|
||||
if (sq_h >= 0)
|
||||
return (cvec3){120, 120, 120};
|
||||
}
|
||||
U8 p = (U8)roundf((1.f - expf(flats)) * 60);
|
||||
return (cvec3){121 - p * 2, 30 + p, 65 - p};
|
||||
}
|
||||
|
||||
cvec4 compress_normal_vec_into_norm_texel(vec3 n) {
|
||||
return (cvec4){(U32)roundf(255 * (n.x + 1) / 2), (U32)roundf(255 * (n.y + 1) / 2), (U32)roundf(255 * (n.z + 1) / 2), 255};
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnNormalVectorGenCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* tex;
|
||||
FnNormalVectorGenCallback my_client;
|
||||
} draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec2){attr.x, attr.y});
|
||||
*TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal);
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf(
|
||||
TextureDataR8G8B8A8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop, FnNormalVectorGenCallback cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb};
|
||||
// todo: generate rasterization function (with different precision + different attributes)
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pa)), .attr = {pa.x, pa.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pb)), .attr = {pb.x, pb.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pc)), .attr = {pc.x, pc.y, 0, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb, (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec3);
|
||||
void* guest;
|
||||
} FnNormalVectorGenExaggParamCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* tex;
|
||||
FnNormalVectorGenExaggParamCallback my_client;
|
||||
mat3 BNT_trans;
|
||||
} draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec3){attr.x, attr.y, attr.z});
|
||||
vec3 tang_normal = mat3_mul_vec3(g->BNT_trans, normal);
|
||||
*TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(tang_normal);
|
||||
}
|
||||
|
||||
/* We can't derive texture coordinates from parameter space coordinates, you have to do it yourself.
|
||||
* Also, we have to convert normal vector in world space to normal space in tangent space.
|
||||
* You specify an orthogonal basis of tangent space of that triangle: BNT - { tangent_U, normal vector tangent_ } */
|
||||
void draw_polygon_on_normal_texture_nat_cords_exaggerated_param_surf(
|
||||
TextureDataR8G8B8A8* tex, vec2 ta, vec2 tb, vec2 tc, vec3 pa, vec3 pb, vec3 pc, FnNormalVectorGenExaggParamCallback cb,
|
||||
mat3 BNT
|
||||
) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb,
|
||||
.BNT_trans = mat3_transpose(BNT)};
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = ta, .attr = {pa.x, pa.y, pa.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tb, .attr = {pb.x, pb.y, pb.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tc, .attr = {pc.x, pc.y, pc.z, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb, (void*)&aboba});
|
||||
}
|
||||
// todo: add a version for that function with non-native coordinate system (on vertex) (like I did with absolutely flat surface)
|
||||
// todo: also, maybe, add a function to derive BNT and do cool stuff with trop mat3x2
|
||||
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* tex;
|
||||
} draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest* g = ug;
|
||||
*TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0});
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_nat_cords_absolutely_flat(TextureDataR8G8B8A8* tex,
|
||||
vec2 ta, vec2 tb, vec2 tc
|
||||
) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest aboba = {tex};
|
||||
marie_rasterize_triangle_with_attr((MariePlaneVertAttr){.pos = ta}, (MariePlaneVertAttr){.pos = tb},
|
||||
(MariePlaneVertAttr){.pos = tc}, (FnMarieRasterizerCallback){
|
||||
.fn = draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
// todo: replace it with a "color everything in one color" function
|
||||
void draw_polygon_on_normal_texture_absolutely_flat(TextureDataR8G8B8A8* tex,
|
||||
vec2 pa, vec2 pb, vec2 pc, mat3x2 trop
|
||||
) {
|
||||
draw_polygon_on_normal_texture_nat_cords_absolutely_flat(tex, mat3x2_mul_vec3(trop, vec2_and_one(pa)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(pb)), mat3x2_mul_vec3(trop, vec2_and_one(pc)));
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> height gradient */
|
||||
vec2 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnHeightMapGradFlatSurfCallback;
|
||||
|
||||
typedef struct {
|
||||
FnHeightMapGradFlatSurfCallback my_client;
|
||||
} draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest;
|
||||
|
||||
vec3 draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb(void* ug, vec2 p) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest* g = ug;
|
||||
vec2 grad = g->my_client.fn(g->my_client.guest, p);
|
||||
return marie_normal_from_tang_space_gradient(grad.x, grad.y); // todo: remove this cluster, while leaving only this function where it's nee
|
||||
}
|
||||
|
||||
/* The simplest case of normal texture generation: for a smooth flat surface of a polygon */
|
||||
void draw_polygon_on_normal_texture_flat_param_surf(TextureDataR8G8B8A8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop,
|
||||
FnHeightMapGradFlatSurfCallback height_map_cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest aboba = {height_map_cb};
|
||||
draw_polygon_on_normal_texture_smooth_param_surf(tex, pa, pb, pc, trop, (FnNormalVectorGenCallback){
|
||||
.fn = draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* self;
|
||||
const Bublazhuzhka* bublazhuzhka;
|
||||
} TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest;
|
||||
|
||||
void TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest *g = ug;
|
||||
cvec3 clr = Bublazhuzhka_get_color(g->bublazhuzhka, (vec2){attr.x, attr.y});
|
||||
if (TextureDataR8G8B8A8_is_inside(g->self, x, y))
|
||||
*TextureDataR8G8B8A8_mat(g->self, x, y) = (cvec4){clr.x, clr.y, clr.z, 255};
|
||||
}
|
||||
|
||||
/* Not natural coordinates. Needs translation operator to convert
|
||||
* from parameter space*/
|
||||
void TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(
|
||||
TextureDataR8G8B8A8* self, const Bublazhuzhka* bublazhuzhka, MarieTriangle param_triangle, mat3x2 trop
|
||||
) {
|
||||
TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest aboba =
|
||||
{self, bublazhuzhka};
|
||||
MarieTriangleAttr natural = MarieTriangle_goto_nat_cords_pres_par(param_triangle, trop);
|
||||
// todo: continue from here
|
||||
marie_rasterize_triangle_with_attr(
|
||||
natural.v0, natural.v1, natural.v2,
|
||||
(FnMarieRasterizerCallback){.fn = TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_h_draw_guest, .guest = &aboba});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// todo: rewrite this crrp (again)
|
||||
TextureDataR8G8B8A8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w));
|
||||
size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l));
|
||||
vec2 cord_resol = {(float)width_pix / (2 * r + w), (float)height_pix / (2 * r + (float)k * l)};
|
||||
const vec2 v0tex = {r, r};
|
||||
const vec2 v1tex = {r + w, r};
|
||||
const vec2 v4tex = {r, 0};
|
||||
const vec2 v5tex = {r + w, 0};
|
||||
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width_pix, height_pix);
|
||||
mat3x2 cord_resol_trop = (mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y};
|
||||
|
||||
vec3 color_1 = (vec3){0.3f, 0.5f, 0.1f};
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, color_1, (MarieTriangle){v0tex, v4tex, v5tex}, cord_resol_trop);
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, color_1, (MarieTriangle){v0tex, v5tex, v1tex}, cord_resol_trop);
|
||||
vec3 color_2 = (vec3){0.1f, 0.2f, 0.8f};
|
||||
vec3 color_3 = (vec3){0.2f, 0.3f, 0.9f};
|
||||
vec3 color_4 = (vec3){0.1f, 0.5f, 0.7f};
|
||||
vec3 color_5 = (vec3){0.7f, 0.05f, 0.2f};
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
vec2 A = (vec2){r - r * sinf(a * (float)i), r + r * cosf(a * (float)i)};
|
||||
vec2 B = (vec2){r - r * sinf(a * (float)(i-1)), r + r * cosf(a * (float)(i-1))};
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, color_2, (MarieTriangle){v0tex, B, A}, cord_resol_trop);
|
||||
}
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
vec2 A = (vec2){r + w + r * sinf(a * (float)i), r + r * cosf(a * (float)i)};
|
||||
vec2 B = (vec2){r + w + r * sinf(a * (float)(i-1)), r + r * cosf(a * (float)(i-1))};
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, color_3, (MarieTriangle){v1tex, A, B}, cord_resol_trop);
|
||||
}
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
vec2 A = (vec2){r, 2 * r + (float)(i) * l};
|
||||
vec2 B = (vec2){r, 2 * r + (float)(i-1) * l};
|
||||
vec2 C = (vec2){r + w, 2 * r + (float)(i-1) * l};
|
||||
vec2 D = (vec2){r + w, 2 * r + (float)(i) * l};
|
||||
vec3 c = i % 2 ? color_4 : color_5;
|
||||
// todo: replace this crrp with something more normal
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, c, (MarieTriangle){A, B, C}, cord_resol_trop);
|
||||
TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, c, (MarieTriangle){A, C, D}, cord_resol_trop);
|
||||
}
|
||||
|
||||
Bublazhuzhka crap_on_back_side = fill_rectangle_with_crap(w, r);
|
||||
mat3x2 back_side_trop = (mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)};
|
||||
TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&res, &crap_on_back_side, (MarieTriangle){{0, r}, {0, 0}, {w, 0}}, back_side_trop);
|
||||
TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&res, &crap_on_back_side, (MarieTriangle){{0, r}, {w, 0}, {w, r}}, back_side_trop);
|
||||
Bublazhuzhka_drop(crap_on_back_side);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Use it as a callback in normal map drawing functions that work with smooth (smooth / flat / cylindrical)
|
||||
* height maps. Guest pointer is of type Bublazhuzhka* */
|
||||
vec2 height_map_cb_that_uses_bublazhuzhka(void* ug, vec2 v) {
|
||||
Bublazhuzhka* bzh = ug;
|
||||
return Bublazhuzhka_get_derivative(bzh, v);
|
||||
}
|
||||
|
||||
// todo: rewrite this crrp and merge it with other one-fourth-of-a-cylinder generiting functions
|
||||
TextureDataR8G8B8A8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w));
|
||||
size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l));
|
||||
vec2 cord_resol = {(float)width_pix / (2 * r + w), (float)height_pix / (2 * r + (float)k * l)};
|
||||
const vec2 v0tex = {r, r};
|
||||
const vec2 v1tex = {r + w, r};
|
||||
// const vec2 v2tex = {r, 2 * r};
|
||||
// const vec2 v3tex = {r + w, 2 * r};
|
||||
const vec2 v4tex = {r, 0};
|
||||
const vec2 v5tex = {r + w, 0};
|
||||
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width_pix, height_pix);
|
||||
|
||||
Bublazhuzhka crap_on_the_back_side = fill_rectangle_with_crap(w, r);
|
||||
mat3x2 trop_back_side = {.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)};
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){w, 0}, (vec2){w, r}, trop_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){0, r}, (vec2){w, r}, trop_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
Bublazhuzhka_drop(crap_on_the_back_side);
|
||||
|
||||
mat3x2 str = {.x.x = cord_resol.x, .y.y = cord_resol.y};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v0tex, v1tex, v4tex, str);
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v1tex, v4tex, v5tex, str);
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r - sinf((float)i * a) * r, r + cosf((float)i * a) * r};
|
||||
vec2 B = {r - sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r, r}, str);
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r + w + sinf((float)i * a) * r, r + cosf((float)i * a) * r};
|
||||
vec2 B = {r + w + sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r + w, r}, str);
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r, 2 * r + (float)i * l};
|
||||
vec2 B = {r + w, 2 * r + (float)i * l};
|
||||
vec2 C = {r, 2 * r + (float)i * l + l};
|
||||
vec2 D = {r + w, 2 * r + (float)i * l + l};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, C, str);
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, D, B, C, str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GenericMeshTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
float tex_width = 2 * r + w;
|
||||
float tex_height = 2 * r + (float)k * l;
|
||||
|
||||
const vec2 v0tex = {r / tex_width, r / tex_height};
|
||||
const vec2 v1tex = {(r + w) / tex_width, r / tex_height};
|
||||
const vec2 v2tex = {r / tex_width, 2 * r / tex_height};
|
||||
const vec2 v3tex = {(r + w) / tex_width, 2 * r / tex_height};
|
||||
VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new_reserved(8 + 4 * k + (k + 2) * 2);
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, r, 0}, .tex = v2tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, r, 0}, .tex = v3tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, -r}, .tex = {r / tex_width, 0}});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, -r}, .tex = {(r + w) / tex_width, 0}});
|
||||
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {0, cosf(a * (float)(i + j)) * r, -sinf(a * (float)(i + j)) * r},
|
||||
.tex = {v2tex.x, v2tex.y + (float)(i + j) * l / tex_height}
|
||||
});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {w, cosf(a * (float)(i + j)) * r, -sinf(a * (float)(i + j)) * r},
|
||||
.tex = {v3tex.x, v3tex.y + (float)(i + j) * l / tex_height}
|
||||
});
|
||||
}
|
||||
}
|
||||
assert(vertices.len == 8 + 4 * k);
|
||||
|
||||
for (U32 i = 0; i <= k; i++) {
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {0, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = (vec2){ (r - r *sinf(a * (float)i)) / tex_width, (r + r * cosf(a * (float)i)) / tex_height},
|
||||
});
|
||||
}
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex});
|
||||
for (U32 i = 0; i <= k; i++) {
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {w, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = (vec2){ (r + w + r * sinf(a * (float)i)) / tex_width, (r + r * cosf(a * (float)i)) / tex_height},
|
||||
});
|
||||
}
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex});
|
||||
assert(vertices.len == 8 + 4 * k + (k + 2) * 2);
|
||||
|
||||
VecU32 indexes = VecU32_new_reserved(3*(4+2*k+2*k));
|
||||
U32 _span_0[] = {7, 5, 4, 7, 4, 6, 1, 3, 0, 3, 2, 0};
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)});
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
U32 _span_1[] = {
|
||||
8 + 4 * k + k + 1, 8 + 4 * k + i, 8 + 4 * k + i + 1,
|
||||
8 + 4 * k + 2 * k + 3, 8 + 4 * k + (k + 2) + i + 1, 8 + 4 * k + (k + 2) + i,
|
||||
8 + 4 * i + 0, 8 + 4 * i + 1, 8 + 4 * i + 3,
|
||||
8 + 4 * i + 0, 8 + 4 * i + 3, 8 + 4 * i + 2,
|
||||
};
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)});
|
||||
}
|
||||
return (GenericMeshTopology){.vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
U32 quad_to_triangles_conv_arr[6] = {0, 1, 2, 0, 2, 3};
|
||||
|
||||
ShinyMeshTopology generate_shiny_cube(vec3 color) {
|
||||
ShinyMeshVertexInc vert[24] = {
|
||||
{{+1, +1, +1}, color},
|
||||
{{+1, -1, +1}, color},
|
||||
{{+1, -1, -1}, color},
|
||||
{{+1, +1, -1}, color},
|
||||
|
||||
{{-1, -1, -1}, color},
|
||||
{{-1, -1, +1}, color},
|
||||
{{-1, +1, +1}, color},
|
||||
{{-1, +1, -1}, color},
|
||||
|
||||
{{+1, +1, +1}, color},
|
||||
{{+1, +1, -1}, color},
|
||||
{{-1, +1, -1}, color},
|
||||
{{-1, +1, +1}, color},
|
||||
|
||||
{{-1, -1, -1}, color},
|
||||
{{+1, -1, -1}, color},
|
||||
{{+1, -1, +1}, color},
|
||||
{{-1, -1, +1}, color},
|
||||
|
||||
{{+1, +1, +1}, color},
|
||||
{{-1, +1, +1}, color},
|
||||
{{-1, -1, +1}, color},
|
||||
{{+1, -1, +1}, color},
|
||||
|
||||
{{-1, -1, -1}, color},
|
||||
{{-1, +1, -1}, color},
|
||||
{{+1, +1, -1}, color},
|
||||
{{+1, -1, -1}, color},
|
||||
};
|
||||
VecShinyMeshVertexInc vertices_vec = VecShinyMeshVertexInc_from_span(
|
||||
(SpanShinyMeshVertexInc){ .data = vert, .len = ARRAY_SIZE(vert) });
|
||||
VecU32 indexes_vec = VecU32_new_reserved(36);
|
||||
for (U32 f = 0; f < 6; f++) {
|
||||
for (U32 j = 0; j < 6; j++)
|
||||
VecU32_append(&indexes_vec, f * 4 + quad_to_triangles_conv_arr[j]);
|
||||
}
|
||||
return (ShinyMeshTopology){ .vertices = vertices_vec, .indexes = indexes_vec};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int face;
|
||||
/* There is a counterclockwise one-to-one correspondence between vertexes of face and edges of face */
|
||||
int vert_on_it;
|
||||
} CubeVertOfFace;
|
||||
|
||||
CubeVertOfFace CubeVertOfFace_jump(CubeVertOfFace vert) {
|
||||
const CubeVertOfFace cube_detour_get_neighbour_face[6][4] = {
|
||||
{{4, 3}, {3, 1}, {5, 2}, {2, 0}},
|
||||
{{3, 3}, {4, 1}, {2, 2}, {5, 0}},
|
||||
{{0, 3}, {5, 1}, {1, 2}, {4, 0}},
|
||||
{{5, 3}, {0, 1}, {4, 2}, {1, 0}},
|
||||
{{2, 3}, {1, 1}, {3, 2}, {0, 0}},
|
||||
{{1, 3}, {2, 1}, {0, 2}, {3, 0}}
|
||||
};
|
||||
return cube_detour_get_neighbour_face[vert.face][vert.vert_on_it];
|
||||
}
|
||||
|
||||
U32 CubeVertOfFace_to_vid(CubeVertOfFace vert) {
|
||||
return 4 * vert.face + vert.vert_on_it;
|
||||
}
|
||||
|
||||
CubeVertOfFace CubeVertOfFace_next(CubeVertOfFace vert) {
|
||||
return (CubeVertOfFace){vert.face, (vert.vert_on_it + 1) % 4};
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/margaret/png_pixel_masses.h"
|
||||
#include "../marie/texture_processing.h"
|
||||
#include "../../l1/system/fsmanip.h"
|
||||
#include "../alice/model_file.h"
|
||||
|
||||
/* Situation: we generated vertices array of generic mesh, we filled .tex attribute (scaled pixel pos)
|
||||
* Now I want the normally scaled stuff back */
|
||||
MarieTriangle restore_triangle_from_mesh_topology(const VecGenericMeshVertexInc* vertices,
|
||||
U32 texture_width, U32 texture_height, U32 vi1, U32 vi2, U32 vi3){
|
||||
vec2 tex1 = VecGenericMeshVertexInc_at(vertices, vi1)->tex;
|
||||
vec2 tex2 = VecGenericMeshVertexInc_at(vertices, vi2)->tex;
|
||||
vec2 tex3 = VecGenericMeshVertexInc_at(vertices, vi3)->tex;
|
||||
return (MarieTriangle){
|
||||
.v0 = {tex1.x * (float)texture_width, tex1.y * (float)texture_height},
|
||||
.v1 = {tex2.x * (float)texture_width, tex2.y * (float)texture_height},
|
||||
.v2 = {tex3.x * (float)texture_width, tex3.y * (float)texture_height},
|
||||
};
|
||||
}
|
||||
|
||||
void r4_generate_flat_normal_map(VecU8 save_path){
|
||||
TextureDataR8G8B8A8 normal = TextureDataR8G8B8A8_new(1, 1);
|
||||
*TextureDataR8G8B8A8_mat(&normal, 0, 0) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0});
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&normal, VecU8_to_span(&save_path));
|
||||
VecU8_drop(save_path);
|
||||
TextureDataR8G8B8A8_drop(normal);
|
||||
}
|
||||
|
||||
void generate_single_pixel_gray_tex(VecU8 save_path, U8 clr){
|
||||
TextureDataR8 tex = TextureDataR8_new(1, 1);
|
||||
*TextureDataR8_mat(&tex, 0, 0) = clr;
|
||||
TextureDataR8_write_to_png_nofail(&tex, VecU8_to_span(&save_path));
|
||||
VecU8_drop(save_path);
|
||||
TextureDataR8_drop(tex);
|
||||
}
|
||||
|
||||
/* r is radius, w is length of cylinder. Will write everything into files for us */
|
||||
void r4_asset_gen_generic_mesh_cylinder(float s_resol, float r, float w, U32 k,
|
||||
VecU8 path_to_mesh, VecU8 path_to_template_tex, VecU8 path_to_normal_tex){
|
||||
assert(k >= 3);
|
||||
VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new_reserved(6 * k);
|
||||
VecU32 indexes = VecU32_new_reserved(3 * (2 * (k - 2) + 2 * k));
|
||||
|
||||
U32 uber_square_takes_px = (U32)ceilf(2 * r * s_resol);
|
||||
float r_px = (float)uber_square_takes_px / 2;
|
||||
|
||||
vec2 ubs_front_center = (vec2){r_px, r_px};
|
||||
|
||||
U32 back_ubs_x = uber_square_takes_px + 1;
|
||||
vec2 ubs_back_center = (vec2){(float)back_ubs_x + r_px, r_px};
|
||||
|
||||
U32 belt_y = uber_square_takes_px + 1;
|
||||
|
||||
/* l is a length of a side. I am 100 % that there is a simpler formula for that */
|
||||
float l = r * sqrtf(2 - 2 * cosf(2 * M_PIf / (float)k));
|
||||
U32 belt_takes_px = (U32)ceilf(l * (float)k * s_resol);
|
||||
float l_px = (float)belt_takes_px / (float)k;
|
||||
|
||||
U32 cyl_length_takes_px = (U32)ceilf(w * s_resol);
|
||||
U32 texture_width = MAX_U32(back_ubs_x + uber_square_takes_px, belt_takes_px);
|
||||
U32 texture_height = belt_y + cyl_length_takes_px;
|
||||
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
float angle = (float)i * 2 * M_PIf / (float)k;
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(angle), r * sinf(angle), w / 2},
|
||||
.tex = {
|
||||
(ubs_front_center.x + cosf(angle) * r_px) / (float)texture_width,
|
||||
(ubs_front_center.y - sinf(angle) * r_px) / (float)texture_height},
|
||||
});
|
||||
}
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
float angle = (float)i * 2 * M_PIf / (float)k;
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(angle), r * sinf(angle), -w / 2},
|
||||
.tex = {
|
||||
(ubs_back_center.x - cosf(angle) * r_px) / (float)texture_width,
|
||||
(ubs_back_center.y - sinf(angle) * r_px) / (float)texture_height},
|
||||
});
|
||||
}
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
float angle = (float)i * 2 * M_PIf / (float)k;
|
||||
float anext = (float)(i + 1) * 2 * M_PIf / (float)k;
|
||||
|
||||
vec2 tex0 = {l_px * (float)i / (float)texture_width, (float)belt_y / (float)texture_height};
|
||||
vec2 tex4 = {l_px * (float)(i + 1) / (float)texture_width,
|
||||
(float)(belt_y + cyl_length_takes_px) / (float)texture_height};
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(angle), r * sinf(angle), w / 2},
|
||||
.tex = tex0
|
||||
});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(anext), r * sinf(anext), w / 2},
|
||||
.tex = (vec2){tex4.x, tex0.y}
|
||||
});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(angle), r * sinf(angle), -w / 2},
|
||||
.tex = (vec2){tex0.x, tex4.y}
|
||||
});
|
||||
VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){
|
||||
.pos = {r * cosf(anext), r * sinf(anext), -w / 2},
|
||||
.tex = tex4
|
||||
});
|
||||
}
|
||||
TextureDataR8G8B8A8 template = TextureDataR8G8B8A8_new(texture_width, texture_height);
|
||||
|
||||
for (U32 i = 1; i + 1 < k; i++) {
|
||||
U32 vis = i;
|
||||
U32 vin = i + 1;
|
||||
U32 vic = 0;
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = (U32[]){vis, vin, vic}, .len = 3});
|
||||
MarieTriangle tex_trig = restore_triangle_from_mesh_topology(&vertices, texture_width, texture_height,
|
||||
vis, vin, vic);
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color(&template, (vec3){0.5f, 0.9f, 0.5f}, tex_trig);
|
||||
}
|
||||
for (U32 i = 1; i + 1 < k; i++) {
|
||||
U32 vis = k + i;
|
||||
U32 vin = k + i + 1;
|
||||
U32 vic = k;
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = (U32[]){vin, vis, vic}, .len = 3});
|
||||
MarieTriangle tex_trig = restore_triangle_from_mesh_topology(&vertices, texture_width, texture_height,
|
||||
vis, vin, vic);
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color(&template, (vec3){0.2f, 0.1f, 0.9f}, tex_trig);
|
||||
}
|
||||
for (U32 i = 0; i < k; i++) {
|
||||
vec3 color = (i % 3 == 0) ? (vec3){0.8f, 0.8f, 0} :
|
||||
((i % 3 == 1) ? (vec3){0.6f, 0.2f, 0.7f} : (vec3){0.3f, 0, 0.95f});
|
||||
U32 v0 = 2 * k + 4 * i;
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = (U32[]){v0 + 1, v0, v0 + 2, v0 + 1, v0 + 2, v0 + 3}, .len = 6});
|
||||
MarieTriangle tex_trig_1 = restore_triangle_from_mesh_topology(&vertices, texture_width, texture_height,
|
||||
v0 + 1, v0, v0 + 2);
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color(&template, color, tex_trig_1);
|
||||
MarieTriangle tex_trig_2 = restore_triangle_from_mesh_topology(&vertices, texture_width, texture_height,
|
||||
v0 + 1, v0 + 2, v0 + 3);
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color(&template, color, tex_trig_2);
|
||||
}
|
||||
|
||||
alice_write_generic_mesh_to_file((GenericMeshTopology){.vertices = vertices, .indexes = indexes}, path_to_mesh);
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&template, VecU8_to_span(&path_to_template_tex));
|
||||
VecU8_drop(path_to_template_tex);
|
||||
TextureDataR8G8B8A8_drop(template);
|
||||
|
||||
/* Right now it's just a pixel... */
|
||||
r4_generate_flat_normal_map(path_to_normal_tex);
|
||||
}
|
||||
|
||||
void r4_asset_gen_generic_mesh_quad(float width, float length, VecU8 path_to_save){
|
||||
VecGenericMeshVertexInc vert = VecGenericMeshVertexInc_from_span((SpanGenericMeshVertexInc){
|
||||
.data = (GenericMeshVertexInc[]){
|
||||
{.pos = {0, 0, 0}, .tex = {0, 0}},
|
||||
{.pos = {width, 0, 0}, .tex = {1, 0}},
|
||||
{.pos = {0, 0, length}, .tex = {0, 1}},
|
||||
{.pos = {width, 0, length}, .tex = {1, 1}}
|
||||
}, .len = 4});
|
||||
VecU32 indexes = VecU32_from_span((SpanU32){.data = (U32[]){1, 0, 2, 1, 2, 3}, .len = 6});
|
||||
alice_write_generic_mesh_to_file((GenericMeshTopology){.vertices = vert, .indexes = indexes}, path_to_save);
|
||||
}
|
||||
|
||||
/* a is r at bottom, b is r on top. y is in [0, height]. Shape is symmetrical from Oy */
|
||||
ShinyMeshTopology generate_shiny_lamp(float height, float a, float b){
|
||||
ShinyMeshVertexInc vert[24] = {
|
||||
{{+b, height, +b}},
|
||||
{{+b, 0, +b}},
|
||||
{{+b, 0, -b}},
|
||||
{{+b, height, -b}},
|
||||
|
||||
{{-b, 0, -b}},
|
||||
{{-b, 0, +b}},
|
||||
{{-b, height, +b}},
|
||||
{{-b, height, -b}},
|
||||
|
||||
{{+b, height, +b}},
|
||||
{{+b, height, -b}},
|
||||
{{-b, height, -b}},
|
||||
{{-b, height, +b}},
|
||||
|
||||
{{-b, 0, -b}},
|
||||
{{+b, 0, -b}},
|
||||
{{+b, 0, +b}},
|
||||
{{-b, 0, +b}},
|
||||
|
||||
{{+b, height, +b}},
|
||||
{{-b, height, +b}},
|
||||
{{-b, 0, +b}},
|
||||
{{+b, 0, +b}},
|
||||
|
||||
{{-b, 0, -b}},
|
||||
{{-b, height, -b}},
|
||||
{{+b, height, -b}},
|
||||
{{+b, 0, -b}},
|
||||
};
|
||||
VecShinyMeshVertexInc vertices = VecShinyMeshVertexInc_from_span(
|
||||
(SpanShinyMeshVertexInc){ .data = vert, .len = ARRAY_SIZE(vert) });
|
||||
VecU32 indexes = VecU32_new_reserved(36);
|
||||
for (U32 f = 0; f < 6; f++) {
|
||||
for (U32 j = 0; j < 6; j++)
|
||||
VecU32_append(&indexes, f * 4 + quad_to_triangles_conv_arr[j]);
|
||||
}
|
||||
return (ShinyMeshTopology){ .vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
void generate_one_forth_of_a_cylinder_with_bublazhuzhka(U64 w, U64 r, U64 k) {
|
||||
{
|
||||
TextureDataR8G8B8A8 tex = generate_tex_template_for_one_fourth_of_a_cylinder(120, (float)w, (float)r, k);
|
||||
TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex);
|
||||
VecU8 name = VecU8_fmt("l2/textures/log_%u_%u_%u_TEMPLATE.png", w, r, k);
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, VecU8_to_span(&name));
|
||||
VecU8_drop(name);
|
||||
TextureDataR8G8B8A8_drop(fixed_tex);
|
||||
TextureDataR8G8B8A8_drop(tex);
|
||||
}
|
||||
{
|
||||
TextureDataR8G8B8A8 tex = generate_normal_tex_for_one_fourth_of_a_cylinder(120, (float)w, (float)r, k);
|
||||
TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex);
|
||||
VecU8 name = VecU8_fmt("l2/textures/log_%u_%u_%u_NORMAL.png", w, r, k);
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, VecU8_to_span(&name));
|
||||
VecU8_drop(name);
|
||||
TextureDataR8G8B8A8_drop(fixed_tex);
|
||||
TextureDataR8G8B8A8_drop(tex);
|
||||
}
|
||||
GenericMeshTopology top = generate_one_fourth_of_a_cylinder((float)w, (float)r, k);
|
||||
alice_write_generic_mesh_to_file(top, VecU8_fmt("l2/models/log_%u_%u_%u.AliceGenericMesh", w, r, k));
|
||||
}
|
||||
|
||||
/* We are on l2 */
|
||||
int gen_assets_for_r4() {
|
||||
mkdir_nofail("l2/models");
|
||||
mkdir_nofail("l2/textures");
|
||||
mkdir_nofail("l2/textures/r4");
|
||||
generate_one_forth_of_a_cylinder_with_bublazhuzhka(10, 2, 6);
|
||||
alice_write_shiny_mesh_to_file(generate_shiny_cube((vec3){0.6f, 0.6f, 0.7f}), vcstr("l2/models/cube.AliceShinyMesh"));
|
||||
alice_write_shiny_mesh_to_file(generate_shiny_lamp(0.3f, 0.13f, 0.19f), vcstr("l2/models/lamp.AliceShinyMesh"));
|
||||
r4_asset_gen_generic_mesh_quad(10, 10, vcstr("l2/models/quad.AliceGenericMesh"));
|
||||
r4_asset_gen_generic_mesh_cylinder(200, 0.4f, 0.17f, 30, vcstr("l2/models/puck.AliceGenericMesh"),
|
||||
vcstr("l2/textures/puck_TEMPLATE.png"), vcstr("l2/textures/puck_NORMAL.png"));
|
||||
r4_asset_gen_generic_mesh_cylinder(100, 0.04f, 1.5f, 4, vcstr("l2/models/stick.AliceGenericMesh"),
|
||||
vcstr("l2/textures/stick_TEMPLATE.png"), vcstr("l2/textures/stick_NORMAL.png"));
|
||||
r4_generate_flat_normal_map(vcstr("l2/textures/flat_NORMAL.png"));
|
||||
generate_single_pixel_gray_tex(vcstr("l2/textures/no_SPECULAR.png"), 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,7 +0,0 @@
|
||||
#ifndef prototype1_src_l2_gui_label_h
|
||||
#define prototype1_src_l2_gui_label_h
|
||||
|
||||
#include "../lucy/glyph_render.h"
|
||||
|
||||
|
||||
#endif
|
||||
@ -1,104 +0,0 @@
|
||||
#ifndef prototype1_src_l2_gui_widget_h
|
||||
#define prototype1_src_l2_gui_widget_h
|
||||
|
||||
#include "../../../gen/l1/geom.h"
|
||||
#include "../../l1/core/util.h"
|
||||
|
||||
#define WIDGET_DIM_INF 1000000
|
||||
|
||||
bool is_widget_size_limit_contain_inf(uvec2 max_limits){
|
||||
return max_limits.x >= WIDGET_DIM_INF || max_limits.y >= WIDGET_DIM_INF;
|
||||
}
|
||||
|
||||
void assert_sane_widget_size(uvec2 sz){
|
||||
assert(sz.x < WIDGET_DIM_INF || sz.y < WIDGET_DIM_INF);
|
||||
}
|
||||
|
||||
void assert_sane_widget_size_limits(uvec2 max_limits){
|
||||
assert(max_limits.x <= WIDGET_DIM_INF || max_limits.y <= WIDGET_DIM_INF);
|
||||
}
|
||||
|
||||
typedef struct{
|
||||
ivec2 lt, rb;
|
||||
} BorderS32;
|
||||
|
||||
bool BorderS32_empty(BorderS32 self){
|
||||
return self.lt.x >= self.rb.x || self.lt.y >= self.rb.y;
|
||||
}
|
||||
|
||||
BorderS32 BorderS32_intersect(BorderS32 a, BorderS32 b){
|
||||
return (BorderS32){
|
||||
{MAX_S32(a.lt.x, b.lt.x), MAX_S32(a.lt.y, b.lt.y)},
|
||||
{MAX_S32(a.rb.x, b.rb.x), MAX_S32(a.rb.y, b.rb.y)},
|
||||
};
|
||||
}
|
||||
|
||||
uvec2 widget_size_max_of_all(uvec2 a, uvec2 b){
|
||||
return (uvec2){MAX_U32(a.x, b.x), MAX_U32(a.y, b.y)};
|
||||
}
|
||||
|
||||
uvec2 widget_size_min_of_all(uvec2 a, uvec2 b){
|
||||
return (uvec2){MIN_U32(a.x, b.x), MIN_U32(a.y, b.y)};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/* .x == WIDGET_DIM_INF indicates that no preparation was made before the draw operation.
|
||||
* Calling draw at that state will cause abort. draw operation will reset this flag. This makes framework foolproof.
|
||||
* Initialize and reset with {WIDGET_DIM_INF, 0} */
|
||||
uvec2 sz_my_choice;
|
||||
} Widget;
|
||||
|
||||
Widget Widget_new(){
|
||||
return (Widget){.sz_my_choice = {WIDGET_DIM_INF, 0}};
|
||||
}
|
||||
|
||||
#include "../../../gen/l1_5/eve/gui/Widget.h"
|
||||
|
||||
uvec2 MutRefWidget_draw_prepare(MutRefWidget self, uvec2 max_limits){
|
||||
if (!self.r)
|
||||
return (uvec2){0};
|
||||
self.r->sz_my_choice = MutRefWidget_DRAW_PREPARE(self, max_limits);
|
||||
assert_sane_widget_size(self.r->sz_my_choice);
|
||||
return self.r->sz_my_choice;
|
||||
}
|
||||
|
||||
void MutRefWidget_draw(MutRefWidget self, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){
|
||||
if (!self.r)
|
||||
return;
|
||||
if (self.r->sz_my_choice.x >= WIDGET_DIM_INF)
|
||||
abortf("Drawing widget before negotiating it's size\n");
|
||||
MutRefWidget_draw(self, drawing_offset, surface_sz, border);
|
||||
self.r->sz_my_choice = (uvec2){WIDGET_DIM_INF, 0};
|
||||
}
|
||||
|
||||
/* Some very simple widgets */
|
||||
|
||||
typedef struct {
|
||||
Widget base;
|
||||
U32 width;
|
||||
U32 height;
|
||||
} EmptyWidget;
|
||||
|
||||
uvec2 Widget_Table_EmptyWidget_DRAW_PREPARE(Widget* ug, uvec2 limits){
|
||||
EmptyWidget* self = (EmptyWidget*)ug;
|
||||
uvec2 R = widget_size_min_of_all((uvec2){self->width, self->height}, limits);
|
||||
return is_widget_size_limit_contain_inf(R) ? (uvec2){0, 0} : R;
|
||||
}
|
||||
|
||||
void Widget_Table_EmptyWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){}
|
||||
|
||||
void Widget_Table_EmptyWidget_drop(Widget* ug){}
|
||||
|
||||
const Widget_Table Widget_Table_EmptyWidget = {
|
||||
.DRAW_PREPARE = Widget_Table_EmptyWidget_DRAW_PREPARE,
|
||||
.DRAW = Widget_Table_EmptyWidget_DRAW,
|
||||
.drop = Widget_Table_EmptyWidget_drop,
|
||||
};
|
||||
|
||||
BoxWidget EmptyWidget_new_box(U32 width, U32 height){
|
||||
EmptyWidget* r = safe_malloc(sizeof(EmptyWidget));
|
||||
*r = (EmptyWidget){.base = Widget_new(), .width = width, .height = height};
|
||||
return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_EmptyWidget};
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -3,7 +3,35 @@
|
||||
|
||||
#include "playing_sound_loop.h"
|
||||
|
||||
#include "../../../gen/l1_5/eve/liza/LizaInstrument.h"
|
||||
// todo: rewrite with the help of l1_5
|
||||
|
||||
typedef struct {
|
||||
/* self (takes ownership) */
|
||||
void (*drop)(void*);
|
||||
/* self, frequency, time, returns: new sound box */
|
||||
BoxLizaSound (*ding)(const void*, double, double);
|
||||
// todo: request options for instrument
|
||||
} LizaInstrument_Table;
|
||||
|
||||
typedef struct {
|
||||
const void* r;
|
||||
const LizaInstrument_Table* t;
|
||||
} RefLizaInstrument;
|
||||
|
||||
typedef struct {
|
||||
void* r;
|
||||
const LizaInstrument_Table* t;
|
||||
} MutLizaInstrument;
|
||||
|
||||
typedef struct {
|
||||
void* m;
|
||||
const LizaInstrument_Table* t;
|
||||
} BoxLizaInstrument;
|
||||
|
||||
void BoxLizaInstrument_drop(BoxLizaInstrument self) {
|
||||
self.t->drop(self.m);
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/liza/VecBoxLizaInstrument.h"
|
||||
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
// todo: move loop here and rewrite with l1_5 help
|
||||
|
||||
#include "../../l1/core/int_primitives.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
/* self (takes ownership) */
|
||||
|
||||
@ -1,422 +0,0 @@
|
||||
#ifndef prototype1_src_l2_lucy_glyph_cache_h
|
||||
#define prototype1_src_l2_lucy_glyph_cache_h
|
||||
|
||||
#include "../margaret/vulkan_utils.h"
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include "../../../gen/l1/VecAndSpan_U32Segment.h"
|
||||
#include "../../../gen/l1/vulkan/VecVkDescriptorImageInfo.h"
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "../../../gen/l1/VecAndSpan_U32.h"
|
||||
|
||||
#include "../../l1_5/core/buff_rb_tree_node.h"
|
||||
#include "../../l1_5/core/rb_tree_node.h"
|
||||
|
||||
#define LUCY_MAX_DESCRIPTOR_COUNT 100
|
||||
|
||||
typedef U32 lucy_image_index_t;
|
||||
|
||||
typedef struct {
|
||||
/* This value is actually Option<MargaretSubbuf>. If staging_buffer is already deleted (after it is no longer used),
|
||||
* staging_buffer.len will be 0 */
|
||||
MargaretSubbuf staging_buffer;
|
||||
MargaretImg img;
|
||||
VkImageView img_view;
|
||||
U64 usage;
|
||||
/* 0 if this image isn't scheduled for deletion on th next cycle.
|
||||
* 1 if it is */
|
||||
int scheduled_for_deletion;
|
||||
} LucyImage;
|
||||
|
||||
#include "../../../gen/l1/eve/lucy/OptionLucyImage.h"
|
||||
#include "../../../gen/l1/eve/lucy/VecOptionLucyImage.h"
|
||||
|
||||
typedef struct {
|
||||
U32 img_slot_id;
|
||||
U32 w, h;
|
||||
U32 advance_x;
|
||||
ivec2 bearing;
|
||||
uvec2 pos_on_atlas;
|
||||
} LucyStoredGlyph;
|
||||
|
||||
typedef struct {
|
||||
U32 key;
|
||||
LucyStoredGlyph value;
|
||||
} KVPU32ToLucyStoredGlyph;
|
||||
#include "../../../gen/l1/eve/lucy/VecKVPU32ToLucyStoredGlyph.h"
|
||||
#include "../../../gen/l1_5/eve/lucy/BufRBTree_MapU32ToLucyStoredGlyph.h"
|
||||
|
||||
typedef struct LucyFace LucyFace;
|
||||
|
||||
typedef struct{
|
||||
LucyFace* p;
|
||||
BufRBTree_MapU32ToLucyStoredGlyph glyphs;
|
||||
} LucyFaceFixedSize;
|
||||
|
||||
void LucyFaceFixedSize_drop(LucyFaceFixedSize self){
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_drop(self.glyphs);
|
||||
}
|
||||
|
||||
#include "../../../gen/l1_5/eve/lucy/RBTree_MapU32ToLucyFaceFixedSize.h"
|
||||
|
||||
// This is a very useful alias
|
||||
typedef RBTreeNode_KVPU32ToLucyFaceFixedSize RBTreeNodeLucyFaceFixedSize;
|
||||
|
||||
typedef struct LucyGlyphCache LucyGlyphCache;
|
||||
|
||||
struct LucyFace {
|
||||
LucyGlyphCache* p;
|
||||
FT_Face ft_face;
|
||||
RBTree_MapU32ToLucyFaceFixedSize sizes;
|
||||
};
|
||||
|
||||
struct LucyGlyphCache {
|
||||
MargaretEngineReference ve;
|
||||
VecOptionLucyImage image_slots;
|
||||
VkDescriptorSetLayout descriptor_set_layout;
|
||||
VkDescriptorSet descriptor_set;
|
||||
|
||||
/* to_be_freed_of_old_staging_next_cycle never intersect with to_be_copied_to_device_next_cycle */
|
||||
VecU32 to_be_freed_of_old_staging_next_cycle;
|
||||
VecU32 to_be_copied_to_device_next_cycle;
|
||||
/* deletion will be performed last */
|
||||
VecU32 to_be_deleted;
|
||||
};
|
||||
|
||||
|
||||
LucyGlyphCache LucyGlyphCache_new(MargaretEngineReference ve){
|
||||
VkDescriptorSetLayout my_desc_set_layout;
|
||||
VkDescriptorSetLayoutBindingFlagsCreateInfo set_layout_crinfo_flags = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
|
||||
.bindingCount = 1,
|
||||
.pBindingFlags = (VkDescriptorBindingFlags[]){ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT }
|
||||
};
|
||||
check(vkCreateDescriptorSetLayout(ve.device, &(VkDescriptorSetLayoutCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||
.pNext = &set_layout_crinfo_flags,
|
||||
.bindingCount = 1,
|
||||
.pBindings = (VkDescriptorSetLayoutBinding[]){{
|
||||
.binding = 0,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = LUCY_MAX_DESCRIPTOR_COUNT,
|
||||
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
}},
|
||||
}, NULL, &my_desc_set_layout) == VK_SUCCESS);
|
||||
VkDescriptorSet descriptor_set = margaret_allocate_descriptor_set(ve.device, ve.descriptor_pool,
|
||||
my_desc_set_layout);
|
||||
VecOptionLucyImage image_slots = VecOptionLucyImage_new_zeroinit(LUCY_MAX_DESCRIPTOR_COUNT);
|
||||
for (size_t i = 0; i < LUCY_MAX_DESCRIPTOR_COUNT; i++) {
|
||||
image_slots.buf[i].variant = Option_None;
|
||||
}
|
||||
return (LucyGlyphCache){
|
||||
.ve = ve, .image_slots = image_slots,
|
||||
.descriptor_set_layout = my_desc_set_layout, .descriptor_set = descriptor_set,
|
||||
.to_be_freed_of_old_staging_next_cycle = VecU32_new(),
|
||||
.to_be_copied_to_device_next_cycle = VecU32_new(),
|
||||
.to_be_deleted = VecU32_new()};
|
||||
}
|
||||
|
||||
void LucyFaceFixedSize_get_rid_of_myself(LucyFaceFixedSize* self){
|
||||
LucyGlyphCache* cache = self->p->p;
|
||||
BufRBTree_MapU32ToLucyStoredGlyph* glyphs = &self->glyphs;
|
||||
for (size_t gid = 0; gid < glyphs->el.len; gid++) {
|
||||
U32 slot_id = glyphs->el.buf[gid].value.img_slot_id;
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
if (--img->usage) {
|
||||
assert(!img->scheduled_for_deletion);
|
||||
img->scheduled_for_deletion = 1;
|
||||
VecU32_append(&cache->to_be_deleted, slot_id);
|
||||
}
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_sink(glyphs);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
RBTreeNodeLucyFaceFixedSize* sized_face;
|
||||
VecU32Segment codepoint_ranges;
|
||||
} LucyGlyphCachingRequest;
|
||||
|
||||
void LucyGlyphCachingRequest_drop(LucyGlyphCachingRequest self){
|
||||
VecU32Segment_drop(self.codepoint_ranges);
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/lucy/VecAndSpan_LucyGlyphCachingRequest.h"
|
||||
|
||||
/* Helper structure */
|
||||
typedef struct {
|
||||
LucyFaceFixedSize* sized_face;
|
||||
U32 codepoint;
|
||||
TextureDataR8 bitmap;
|
||||
/* Will be determined in the next phase */
|
||||
uvec2 pos;
|
||||
U32 img_slot_id;
|
||||
} LucyPositionedStagingGlyph;
|
||||
|
||||
bool LucyPositionedStagingGlyph_less_LucyPositionedStagingGlyph(
|
||||
const LucyPositionedStagingGlyph* A, const LucyPositionedStagingGlyph* B){
|
||||
return A->bitmap.height < B->bitmap.height;
|
||||
}
|
||||
|
||||
void LucyPositionedStagingGlyph_drop(LucyPositionedStagingGlyph self){
|
||||
TextureDataR8_drop(self.bitmap);
|
||||
}
|
||||
|
||||
/* Instantiation for helper type */
|
||||
#include "../../../gen/l1/eve/lucy/VecLucyPositionedStagingGlyph.h"
|
||||
|
||||
/* Helper function */
|
||||
U32 LucyGlyphCache_add_glyphs__find_image_slot(LucyGlyphCache* cache){
|
||||
for (U32 i = 0; i < cache->image_slots.len; i++) {
|
||||
OptionLucyImage* slot = &cache->image_slots.buf[i];
|
||||
if (slot->variant == Option_None) {
|
||||
slot->variant = Option_Some;
|
||||
slot->some.scheduled_for_deletion = 0;
|
||||
slot->some.usage = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
abortf("LucyCache run out of image descriptor in a descriptor set (dictated by layout).\n"
|
||||
"You better add up on them\n");
|
||||
}
|
||||
|
||||
/* Helper function */
|
||||
void LucyGlyphCache_add_glyphs__close_img(
|
||||
LucyGlyphCache* cache, U32 img_slot_id, U32 img_width, U32 img_height
|
||||
){
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&cache->image_slots, img_slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->usage > 0);
|
||||
assert(!img->scheduled_for_deletion);
|
||||
img_width = MAX_U32(img_width, 10); // Just a precaution. empty buffers aren't supported by Margaret
|
||||
img_height = MAX_U32(img_height, 10);
|
||||
VecU32_append(&cache->to_be_copied_to_device_next_cycle, img_slot_id);
|
||||
img->staging_buffer = MargaretBufAllocator_alloc(cache->ve.staging_buffers, img_width * img_height * 1);
|
||||
img->img = MargaretImgAllocator_alloc(cache->ve.dev_local_images, img_width, img_height, VK_FORMAT_R8_UNORM,
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
img->img_view = margaret_create_view_for_image(cache->ve.device, img->img.a.image,
|
||||
VK_FORMAT_R8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
void LucyGlyphCache_add_glyphs(VecLucyGlyphCachingRequest requests_for_faces){
|
||||
if (requests_for_faces.len == 0)
|
||||
return;
|
||||
LucyGlyphCache* cache = requests_for_faces.buf[0].sized_face->value.p->p;
|
||||
for (size_t fi = 0; fi < requests_for_faces.len; fi++) {
|
||||
assert(cache == requests_for_faces.buf[fi].sized_face->value.p->p);
|
||||
}
|
||||
VkPhysicalDeviceProperties properties;
|
||||
vkGetPhysicalDeviceProperties(cache->ve.physical_device, &properties);
|
||||
U32 max_dim = properties.limits.maxImageDimension2D;
|
||||
check(max_dim >= 10);
|
||||
|
||||
|
||||
VecLucyPositionedStagingGlyph ready = VecLucyPositionedStagingGlyph_new();
|
||||
for (size_t fi = 0; fi < requests_for_faces.len; fi++) {
|
||||
LucyGlyphCachingRequest req = requests_for_faces.buf[fi];
|
||||
FT_Face ft_face = req.sized_face->value.p->ft_face;
|
||||
U32 font_height = req.sized_face->key;
|
||||
check(FT_Set_Pixel_Sizes(ft_face, 0, font_height) == 0);
|
||||
BufRBTree_MapU32ToLucyStoredGlyph* glyph_set = &req.sized_face->value.glyphs;
|
||||
/* Phase 1, where we add some elements to glyph_set, but we don't
|
||||
* know how many image we will have and we don't know where new glyphs will be placed */
|
||||
for (size_t ri = 0; ri < req.codepoint_ranges.len; ri++) {
|
||||
U32 range_start = req.codepoint_ranges.buf[ri].start;
|
||||
U32 range_end = range_start + req.codepoint_ranges.buf[ri].len;
|
||||
for (U32 codepoint = range_start; codepoint < range_end; codepoint++) {
|
||||
if (BufRBTree_MapU32ToLucyStoredGlyph_find(glyph_set, codepoint) != 0)
|
||||
continue;
|
||||
FT_UInt glyph_index = FT_Get_Char_Index(ft_face, (FT_ULong)codepoint);
|
||||
check(FT_Load_Glyph(ft_face, glyph_index, 0) == 0);
|
||||
FT_GlyphSlot slot = ft_face->glyph;
|
||||
FT_Bitmap* bitmap = &slot->bitmap;
|
||||
TextureDataR8 my_bitmap = TextureDataR8_new(bitmap->width, bitmap->rows);
|
||||
check(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (slot->format != FT_GLYPH_FORMAT_BITMAP) {
|
||||
check(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL) == 0);
|
||||
}
|
||||
/* Here we dismiss very big glyphs. This guarantees that each glyph on it's own fits into VkImage */
|
||||
check(bitmap->width <= max_dim && bitmap->rows <= max_dim);
|
||||
assert(bitmap->rows == 0 || bitmap->width != 0 || bitmap->buffer != NULL);
|
||||
for (S64 y = 0; y < bitmap->rows; y++) {
|
||||
for (S64 x = 0; x < bitmap->width; x++) {
|
||||
*TextureDataR8_mat(&my_bitmap, x, y) = *(bitmap->buffer + y * bitmap->pitch + x * sizeof(U8));
|
||||
}
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph_insert(glyph_set, codepoint, (LucyStoredGlyph){
|
||||
.w = bitmap->width, .h = bitmap->rows,
|
||||
.advance_x = slot->advance.x >> 6,
|
||||
.bearing = (ivec2){ slot->bitmap_left, -slot->bitmap_top },
|
||||
/* x_on_atlas, y_on_atlas and img will be set later, when `ready` vector is ready */
|
||||
});
|
||||
VecLucyPositionedStagingGlyph_append(&ready, (LucyPositionedStagingGlyph){
|
||||
.sized_face = &req.sized_face->value, .codepoint = codepoint, .bitmap = my_bitmap,
|
||||
/* pos and img will be filled later by packing algorithm */
|
||||
});
|
||||
}
|
||||
}
|
||||
/* Phase 2. Here we determine (in ready vector) where each new glyph sits (atlas image + pos).
|
||||
* But we won't copy TextureDataR8 to staging buffer before everything is known */
|
||||
VecLucyPositionedStagingGlyph_sort(&ready);
|
||||
/* Variables, that have to be reset after each image overflow */
|
||||
U32 starting_x = 0;
|
||||
VecU32 landscape = VecU32_new_reserved(200);
|
||||
U32 img_width = 0, img_height = 0;
|
||||
U32 img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache);
|
||||
for (size_t j = 0; j < ready.len; j++) {
|
||||
LucyPositionedStagingGlyph* p_glyph;
|
||||
one_more_chance:
|
||||
{}
|
||||
int s = 23123;
|
||||
p_glyph = &ready.buf[j];
|
||||
LucyImage* img = &VecOptionLucyImage_mat(&cache->image_slots, img_slot_id)->some;
|
||||
U64 new_width_required = p_glyph->bitmap.width + starting_x;
|
||||
if (new_width_required > max_dim) {
|
||||
/* Resetting row */
|
||||
starting_x = 0;
|
||||
goto one_more_chance;
|
||||
}
|
||||
for (U32 h = img_width; h < new_width_required; h++) {
|
||||
VecU32_append(&landscape, 0);
|
||||
}
|
||||
img_width = MAX_U64(img_width, new_width_required);
|
||||
U32 height_here = 0;
|
||||
for (size_t x = 0; x < p_glyph->bitmap.width; x++) {
|
||||
height_here = MAX_U32(height_here, *VecU32_at(&landscape, starting_x + x));
|
||||
}
|
||||
U64 new_height_required = height_here + p_glyph->bitmap.height;
|
||||
if (new_height_required > max_dim) {
|
||||
/* Resetting image */
|
||||
LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height);
|
||||
starting_x = 0;
|
||||
landscape.len = 0;
|
||||
img_width = 0;
|
||||
img_height = 0;
|
||||
img_slot_id = LucyGlyphCache_add_glyphs__find_image_slot(cache);
|
||||
goto one_more_chance;
|
||||
}
|
||||
/* Success */
|
||||
for (size_t x = 0; x < p_glyph->bitmap.width; x++) {
|
||||
*VecU32_mat(&landscape, starting_x + x) = new_height_required;
|
||||
}
|
||||
img_height = MAX_U64(img_height, new_height_required);
|
||||
p_glyph->img_slot_id = img_slot_id;
|
||||
p_glyph->pos = (uvec2){starting_x, height_here};
|
||||
img->usage++; /* p_glyph uses it, that's a rock fact */
|
||||
BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &p_glyph->sized_face->glyphs;
|
||||
U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, p_glyph->codepoint);
|
||||
assert(map_it > 0 && map_it < glyphs->tree.len);
|
||||
LucyStoredGlyph* actual_glyph = &glyphs->el.buf[map_it - 1].value;
|
||||
actual_glyph->pos_on_atlas = (uvec2){starting_x, height_here};
|
||||
actual_glyph->img_slot_id = img_slot_id;
|
||||
starting_x += p_glyph->bitmap.width;
|
||||
}
|
||||
LucyGlyphCache_add_glyphs__close_img(cache, img_slot_id, img_width, img_height);
|
||||
/* Phase 3. We have all the data. Now what?
|
||||
* Now we fill staging buffers with glyphs bitsets from `ready` vector */
|
||||
for (size_t j = 0; j < ready.len; j++) {
|
||||
LucyPositionedStagingGlyph* p_glyph = &ready.buf[j];
|
||||
LucyImage* image = &VecOptionLucyImage_mat(&cache->image_slots, p_glyph->img_slot_id)->some;
|
||||
U64 staging_width = image->img.width;
|
||||
U8* staging = (U8*)MargaretSubbuf_get_mapped(&image->staging_buffer);
|
||||
for (U64 y = 0; y < p_glyph->bitmap.height; y++) {
|
||||
U64 Y = y + p_glyph->pos.y;
|
||||
for (U64 x = 0; x < p_glyph->bitmap.width; x++) {
|
||||
U64 X = x + p_glyph->pos.x;
|
||||
staging[Y * staging_width + X] = *TextureDataR8_at(&p_glyph->bitmap, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VecLucyPositionedStagingGlyph_drop(ready);
|
||||
VecLucyGlyphCachingRequest_drop(requests_for_faces);
|
||||
}
|
||||
|
||||
/* This must not happen before all the LucyFaceFixedSizes are destroyed */
|
||||
void LucyGlyphCache_drop(LucyGlyphCache self){
|
||||
for (size_t i = 0; i < self.image_slots.len; i++) {
|
||||
assert(self.image_slots.buf[i].variant == Option_None);
|
||||
}
|
||||
VecU32_drop(self.to_be_freed_of_old_staging_next_cycle);
|
||||
VecU32_drop(self.to_be_copied_to_device_next_cycle);
|
||||
VecU32_drop(self.to_be_deleted);
|
||||
}
|
||||
|
||||
void LucyGlyphCache_another_frame(LucyGlyphCache* self){
|
||||
for (size_t i = 0; i < self->to_be_freed_of_old_staging_next_cycle.len; i++) {
|
||||
U32 slot_id = self->to_be_freed_of_old_staging_next_cycle.buf[i];
|
||||
LucyImage* img = &self->image_slots.buf[slot_id].some;
|
||||
assert(img->staging_buffer.len != 0);
|
||||
MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer);
|
||||
img->staging_buffer.len = 0;
|
||||
}
|
||||
for (size_t i = 0; i < self->to_be_copied_to_device_next_cycle.len; i++) {
|
||||
U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i];
|
||||
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->staging_buffer.len != 0);
|
||||
if (img->scheduled_for_deletion)
|
||||
continue;
|
||||
margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(self->ve.transfer_cmd_buffer,
|
||||
&img->staging_buffer, &img->img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
VecU32_append(&self->to_be_freed_of_old_staging_next_cycle, slot_id);
|
||||
|
||||
vkUpdateDescriptorSets(self->ve.device, 1, &(VkWriteDescriptorSet){
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = self->descriptor_set, .dstBinding = 0, .dstArrayElement = slot_id,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &(VkDescriptorImageInfo){
|
||||
.sampler = self->ve.nearest_sampler, .imageView = img->img_view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
}
|
||||
}, 0, NULL);
|
||||
}
|
||||
/* We technically could carry out each deletion request in O(1) and each img creation request in O(1),
|
||||
* but who cares, it's no problem going over the entire descriptor set when something get's added or deleted */
|
||||
for (size_t i = 0; i < self->to_be_deleted.len; i++) {
|
||||
U32 slot_id = self->to_be_copied_to_device_next_cycle.buf[i];
|
||||
OptionLucyImage* img_slot = &self->image_slots.buf[slot_id];
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
assert(img->scheduled_for_deletion);
|
||||
assert(img->usage == 0);
|
||||
if (img->staging_buffer.len != 0)
|
||||
MargaretBufAllocator_free(self->ve.staging_buffers, img->staging_buffer);
|
||||
MargaretImgAllocator_free(self->ve.dev_local_images, img->img.a);
|
||||
img_slot->variant = Option_None;
|
||||
}
|
||||
self->to_be_freed_of_old_staging_next_cycle.len = 0;
|
||||
self->to_be_copied_to_device_next_cycle.len = 0;
|
||||
self->to_be_deleted.len = 0;
|
||||
}
|
||||
|
||||
/* This function does not check font file for correctness, use only with trusted fonts */
|
||||
LucyFace* LucyFace_new(FT_Library lib, LucyGlyphCache* cache, VecU8 path){
|
||||
VecU8_append(&path, 0); // Making it null-terminated
|
||||
FT_Face face;
|
||||
FT_Error ret = FT_New_Face(lib, (const char*)path.buf, 0, &face);
|
||||
check(ret == 0);
|
||||
VecU8_drop(path);
|
||||
LucyFace* hand = safe_malloc(sizeof(LucyFace));
|
||||
*hand = (LucyFace){.p = cache, .ft_face = face, .sizes = RBTree_MapU32ToLucyFaceFixedSize_new()};
|
||||
return hand;
|
||||
}
|
||||
|
||||
RBTreeNodeLucyFaceFixedSize* LucyFace_of_size(LucyFace* self, U32 size){
|
||||
RBTreeNodeLucyFaceFixedSize* nahodka = RBTree_MapU32ToLucyFaceFixedSize_find(&self->sizes, size);
|
||||
if (nahodka)
|
||||
return nahodka;
|
||||
RBTree_MapU32ToLucyFaceFixedSize_insert(&self->sizes, size, (LucyFaceFixedSize){
|
||||
.p = self, .glyphs = BufRBTree_MapU32ToLucyStoredGlyph_new()
|
||||
});
|
||||
// todo: add a method to RBTree for proper node insertion. This is just pure crap
|
||||
return RBTree_MapU32ToLucyFaceFixedSize_find(&self->sizes, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,190 +0,0 @@
|
||||
#ifndef prototype1_src_l2_lucy_rendering_h
|
||||
#define prototype1_src_l2_lucy_rendering_h
|
||||
|
||||
#include "glyph_cache.h"
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "../../../gen/l1/geom.h"
|
||||
|
||||
// todo: rewrite this crrp crap using instances
|
||||
// typedef struct{
|
||||
// vec4 color;
|
||||
// vec2 pos;
|
||||
// vec2 tex_cord;
|
||||
// U32 tex_ind;
|
||||
// } LucyVertex;
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec4 color;
|
||||
vec2 lt_pos;
|
||||
vec2 br_pos;
|
||||
vec2 lt_tex;
|
||||
vec2 br_tex;
|
||||
U32 tex_ind;
|
||||
} LucyRenderInstance;
|
||||
|
||||
typedef struct {
|
||||
MargaretEngineReference ve;
|
||||
LucyGlyphCache* cache;
|
||||
VkPipelineLayout pipeline_layout;
|
||||
VkPipeline pipeline;
|
||||
|
||||
U64 glyphs_count;
|
||||
MargaretSubbuf staging_vbo;
|
||||
MargaretSubbuf vbo;
|
||||
bool need_to_transfer;
|
||||
} LucyRenderer;
|
||||
|
||||
typedef struct {
|
||||
float width, height;
|
||||
} LucyRendererPushConstants;
|
||||
|
||||
LucyRenderer LucyRenderer_new(
|
||||
MargaretEngineReference ve, LucyGlyphCache* cache, SpanU8 root_dir,
|
||||
VkRenderPass render_pass, U32 renderpass_subpass){
|
||||
|
||||
VkPipelineLayout pipeline_layout;
|
||||
check(vkCreatePipelineLayout(ve.device, &(VkPipelineLayoutCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||
.setLayoutCount = 1,
|
||||
.pSetLayouts = &cache->descriptor_set_layout,
|
||||
.pushConstantRangeCount = 1,
|
||||
.pPushConstantRanges = (VkPushConstantRange[]){{
|
||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT, .offset = 0, .size = sizeof(LucyRendererPushConstants)
|
||||
}},
|
||||
}, NULL, &pipeline_layout) == VK_SUCCESS);
|
||||
|
||||
VkPipeline pipeline = margaret_create_triangle_pipeline_one_attachment(ve.device,
|
||||
render_pass, renderpass_subpass, (MargaretMostImportantPipelineOptions){
|
||||
.pipeline_layout = pipeline_layout,
|
||||
.vertex_shader_code = read_file_by_path(VecU8_fmt("%s/gen/l_adele/lucy/vert.spv", root_dir)),
|
||||
.fragment_shader_code = read_file_by_path(VecU8_fmt("%s/gen/l_adele/lucy/frag.spv", root_dir)),
|
||||
.vertexBindingDescriptionCount = 1,
|
||||
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]){
|
||||
{ .binding = 0, .stride = sizeof(LucyRenderInstance), .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE } },
|
||||
.vertexAttributeDescriptionCount = 6,
|
||||
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]){
|
||||
{.location = 0, .binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(LucyRenderInstance, color)},
|
||||
{.location = 1, .binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_pos)},
|
||||
{.location = 2, .binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_pos)},
|
||||
{.location = 3, .binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_tex)},
|
||||
{.location = 4, .binding = 0,
|
||||
.format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_tex)},
|
||||
{.location = 5, .binding = 0,
|
||||
.format = VK_FORMAT_R32_UINT, .offset = offsetof(LucyRenderInstance, tex_ind)},
|
||||
},
|
||||
.depthTestEnable = false, .depthWriteEnable = false, .blendEnable = true,
|
||||
});
|
||||
|
||||
return (LucyRenderer){.ve = ve, .cache = cache, .pipeline_layout = pipeline_layout, .pipeline = pipeline,
|
||||
.glyphs_count = 0, .staging_vbo = MargaretBufAllocator_alloc(ve.staging_buffers, 67),
|
||||
.vbo = MargaretBufAllocator_alloc(ve.dev_local_buffers, 67)
|
||||
};
|
||||
}
|
||||
|
||||
/* When another_frame starts, you are safe to call this function, but you also have to call it
|
||||
* before LucyRenderer_another_frame
|
||||
*/
|
||||
void LucyRenderer_clear(LucyRenderer* self){
|
||||
self->glyphs_count = 0;
|
||||
}
|
||||
|
||||
void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, LucyStoredGlyph* glyph){
|
||||
if (glyph->w > 0 && glyph->h > 0) {
|
||||
OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id);
|
||||
assert(img_slot->variant == Option_Some);
|
||||
LucyImage* img = &img_slot->some;
|
||||
float atlas_w = (float)img->img.width;
|
||||
float atlas_h = (float)img->img.height;
|
||||
ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing);
|
||||
|
||||
U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance);
|
||||
if (self->staging_vbo.len < needed_vbo_length) {
|
||||
printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n",
|
||||
self->staging_vbo.len, needed_vbo_length);
|
||||
MargaretBufAllocator_expand_or_move_old_host_visible(
|
||||
self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length);
|
||||
}
|
||||
|
||||
LucyRenderInstance* vbo_data = (LucyRenderInstance*)MargaretSubbuf_get_mapped(&self->staging_vbo);
|
||||
vbo_data[self->glyphs_count++] = (LucyRenderInstance){
|
||||
.color = color,
|
||||
.lt_pos = (vec2){(float)positioned.x, (float)positioned.y},
|
||||
.br_pos = (vec2){(float)(positioned.x + glyph->w), (float)(positioned.y + glyph->h)},
|
||||
.lt_tex = (vec2){
|
||||
(float)(glyph->pos_on_atlas.x) / atlas_w,
|
||||
(float)(glyph->pos_on_atlas.y) / atlas_h
|
||||
},
|
||||
.br_tex = (vec2){
|
||||
(float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w,
|
||||
(float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h
|
||||
}, .tex_ind = glyph->img_slot_id
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* When another_frame starts, you are safe to call this function, but you also have to call it
|
||||
* before LucyRenderer_another_frame, because _another_frame method records transfer of data
|
||||
*/
|
||||
void LucyRenderer_add_simple_label(
|
||||
LucyRenderer* self, RBTreeNodeLucyFaceFixedSize* ffs, vec4 color,
|
||||
U32 additional_y_advance, SpanU8 text, ivec2 start_pos
|
||||
){
|
||||
self->need_to_transfer = true;
|
||||
U32 font_height = ffs->key;
|
||||
ivec2 pos = (ivec2){start_pos.x, start_pos.y + (S32)font_height};
|
||||
/* `text` variable will be modified during decoding */
|
||||
while (text.len > 0) {
|
||||
U32 codepoint = SpanU8_decode_as_utf8(&text);
|
||||
if (codepoint == (U32)'\n') {
|
||||
pos = (ivec2){start_pos.x, pos.y + (S32)font_height + (S32)additional_y_advance};
|
||||
continue;
|
||||
}
|
||||
BufRBTree_MapU32ToLucyStoredGlyph *glyphs = &ffs->value.glyphs;
|
||||
U64 map_it = BufRBTree_MapU32ToLucyStoredGlyph_find(glyphs, codepoint);
|
||||
if (map_it == 0) {
|
||||
/* We probably should have requested LucyCache to load more glyphs or draw 'unknown character'
|
||||
* character, but we just skip things. We will force someone else to do that job */
|
||||
continue;
|
||||
}
|
||||
assert(map_it > 0 && map_it < glyphs->tree.len);
|
||||
LucyStoredGlyph* glyph = &glyphs->el.buf[map_it - 1].value;
|
||||
LucyRenderer_draw_char_glyph(self, color, pos, glyph);
|
||||
pos.x += (S32)glyph->advance_x;
|
||||
}
|
||||
}
|
||||
|
||||
/* It only records transfer commands (transfer command buffer is passed in MargaretEngineReference object) */
|
||||
void LucyRenderer_another_frame(LucyRenderer* self){
|
||||
U64 needed_vbo_length = self->glyphs_count * sizeof(LucyRenderInstance);
|
||||
if (self->vbo.len < needed_vbo_length) {
|
||||
MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length);
|
||||
}
|
||||
if ((self->need_to_transfer) && self->glyphs_count > 0) {
|
||||
printf("LucyRenderer: we are doing copying\n");
|
||||
|
||||
self->need_to_transfer = false;
|
||||
margaret_rec_cmd_copy_buffer_one_to_one_part(self->ve.transfer_cmd_buffer,
|
||||
&self->staging_vbo, &self->vbo, 0, needed_vbo_length);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: merge with the function above. In the future all the crrp will be recorded simultaneously
|
||||
void LucyRenderer_another_frame_rec_drawing(
|
||||
LucyRenderer* self, VkCommandBuffer drawing_cmd_buf, VkExtent2D image_extent){
|
||||
vkCmdBindPipeline(drawing_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, self->pipeline);
|
||||
vkCmdPushConstants(drawing_cmd_buf, self->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
0, sizeof(LucyRendererPushConstants),
|
||||
&(LucyRendererPushConstants){ .width = (float)image_extent.width, .height = (float)image_extent.height });
|
||||
vkCmdBindVertexBuffers(drawing_cmd_buf, 0, 1,
|
||||
(VkBuffer[]){MargaretSubbuf_get_buffer(&self->vbo)}, (VkDeviceSize[]){self->vbo.start});
|
||||
vkCmdBindDescriptorSets(drawing_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, self->pipeline_layout, 0,
|
||||
1, (VkDescriptorSet[]){self->cache->descriptor_set}, 0, NULL);
|
||||
vkCmdDraw(drawing_cmd_buf, 6, self->glyphs_count, 0, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1 +0,0 @@
|
||||
|
||||
254
src/l2/margaret/png_pixel_masses.h
Normal file
254
src/l2/margaret/png_pixel_masses.h
Normal file
@ -0,0 +1,254 @@
|
||||
#ifndef PROTOTYPE1_SRC_L2_MARGARET_PNG_PIXEL_MASSES_H
|
||||
#define PROTOTYPE1_SRC_L2_MARGARET_PNG_PIXEL_MASSES_H
|
||||
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "../../l1/core/util.h"
|
||||
#include "../../l1/core/VecU8_as_str.h"
|
||||
#include <png.h>
|
||||
|
||||
// todo: generate all of this automaticcally
|
||||
|
||||
void margaret_libpng_h_error_cb(png_structp pngshka, png_const_charp err) {
|
||||
printf("[!] %s\n", err);
|
||||
}
|
||||
|
||||
void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) {
|
||||
printf("[.] %s\n", warning);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Result_variant variant;
|
||||
VecU8 err;
|
||||
} ResultVoidOrVecU8;
|
||||
|
||||
void ResultVoidOrVecU8_drop(ResultVoidOrVecU8 self) {
|
||||
if (self.variant == Result_Err)
|
||||
VecU8_drop(self.err);
|
||||
}
|
||||
|
||||
ResultVoidOrVecU8 TextureDataR8G8B8A8_write_to_png(const TextureDataR8G8B8A8* self, SpanU8 filename) {
|
||||
VecU8 nt_filename = VecU8_fmt("%s%c", filename, 0);
|
||||
FILE *fp = fopen((CSTR)nt_filename.buf, "wb");
|
||||
VecU8_drop(nt_filename);
|
||||
if (!fp) {
|
||||
return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_fmt("Unable to open file %s", filename)};
|
||||
}
|
||||
png_structp pngshka = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);
|
||||
if (!pngshka)
|
||||
abortf("png_create_write_struct");
|
||||
png_infop info = png_create_info_struct(pngshka);
|
||||
if (!info)
|
||||
abortf("png_create_info_struct");
|
||||
|
||||
png_bytep* row_pointers = NULL;
|
||||
|
||||
if (setjmp(png_jmpbuf(pngshka))){
|
||||
png_destroy_write_struct(&pngshka, &info);
|
||||
fclose(fp);
|
||||
free(row_pointers);
|
||||
return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr("Some png error happened")};
|
||||
}
|
||||
png_init_io(pngshka, fp);
|
||||
|
||||
U32 width = self->width;
|
||||
U32 height = TextureDataR8G8B8A8_get_height(self);
|
||||
|
||||
png_set_IHDR(pngshka, info, width, height, 8, PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
row_pointers = calloc(height, sizeof(row_pointers));
|
||||
for (U32 y = 0; y < height; y++) {
|
||||
row_pointers[height - 1 - y] = (png_bytep)((TextureDataR8G8B8A8_at(self, 0, y)));
|
||||
}
|
||||
png_set_rows(pngshka, info, row_pointers);
|
||||
png_write_png(pngshka, info, 0, NULL);
|
||||
/* No more errors */
|
||||
free(row_pointers);
|
||||
png_destroy_write_struct(&pngshka, &info);
|
||||
fclose(fp);
|
||||
return (ResultVoidOrVecU8){.variant = Result_Ok};
|
||||
}
|
||||
|
||||
/* Aborts on error */
|
||||
void TextureDataR8G8B8A8_write_to_png_nofail(const TextureDataR8G8B8A8* self, SpanU8 filename) {
|
||||
ResultVoidOrVecU8 res = TextureDataR8G8B8A8_write_to_png(self, filename);
|
||||
if (res.variant == Result_Err) {
|
||||
SpanU8_fprint(VecU8_to_span(&res.err), stderr);
|
||||
abortf(" TextureDataR8G8B8A8_write_to_png\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* This structure will be pinned */
|
||||
typedef struct {
|
||||
FILE* fp;
|
||||
png_structp pngshka;
|
||||
png_infop info;
|
||||
png_infop end_info;
|
||||
} MargaretPromisedPngR8G8B8A8;
|
||||
|
||||
void MargaretPromisedPngR8G8B8A8_drop(MargaretPromisedPngR8G8B8A8 self) {
|
||||
png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);
|
||||
fclose(self.fp);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Result_variant variant;
|
||||
union {
|
||||
MargaretPromisedPngR8G8B8A8 ok;
|
||||
VecU8 err;
|
||||
};
|
||||
} ResultMargaretPromisedPngR8G8B8A8OrVecU8;
|
||||
|
||||
void ResultMargaretPromisedPngR8G8B8A8OrVecU8_drop(ResultMargaretPromisedPngR8G8B8A8OrVecU8 self) {
|
||||
if (self.variant == Result_Ok)
|
||||
MargaretPromisedPngR8G8B8A8_drop(self.ok);
|
||||
else
|
||||
VecU8_drop(self.err);
|
||||
}
|
||||
|
||||
ResultMargaretPromisedPngR8G8B8A8OrVecU8 MargaretPromisedPngR8G8B8A8_begin(SpanU8 filename) {
|
||||
VecU8 nt_filename = VecU8_fmt("%s%c", filename, 0);
|
||||
FILE* fp = fopen((CSTR)nt_filename.buf, "rb");
|
||||
VecU8_drop(nt_filename);
|
||||
if (!fp) {
|
||||
return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Err,
|
||||
.err = VecU8_fmt("Unable to open file %s", filename)};
|
||||
}
|
||||
png_structp pngshka = png_create_read_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);
|
||||
if (!pngshka)
|
||||
abortf("png_create_read_struct");
|
||||
png_infop info = png_create_info_struct(pngshka);
|
||||
if (!info)
|
||||
abortf("png_create_info_struct");
|
||||
png_infop end_info = png_create_info_struct(pngshka);
|
||||
if (!end_info)
|
||||
abortf("png_create_info_struct");
|
||||
if (setjmp(png_jmpbuf(pngshka))) {
|
||||
png_destroy_read_struct(&pngshka, &info, &end_info);
|
||||
fclose(fp);
|
||||
return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Err,
|
||||
.err = VecU8_from_cstr("Some png error happened")};
|
||||
}
|
||||
png_init_io(pngshka, fp);
|
||||
png_read_info(pngshka, info);
|
||||
U32 width, height;
|
||||
int bit_depth, color_type;
|
||||
assert(png_get_IHDR(pngshka, info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));
|
||||
|
||||
if (bit_depth == 16) {
|
||||
png_set_strip_16(pngshka);
|
||||
}
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY) {
|
||||
if (bit_depth == 1 || bit_depth == 2 || bit_depth == 4) {
|
||||
png_set_expand_gray_1_2_4_to_8(pngshka);
|
||||
}
|
||||
png_set_gray_to_rgb(pngshka);
|
||||
if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(pngshka);
|
||||
} else {
|
||||
png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER);
|
||||
}
|
||||
} else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_set_gray_to_rgb(pngshka);
|
||||
} else if (color_type == PNG_COLOR_TYPE_RGB) {
|
||||
if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(pngshka);
|
||||
} else {
|
||||
png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER);
|
||||
}
|
||||
} else if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(pngshka);
|
||||
|
||||
if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(pngshka);
|
||||
} else {
|
||||
png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER);
|
||||
}
|
||||
}
|
||||
png_read_update_info(pngshka, info);
|
||||
|
||||
return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Ok,
|
||||
.ok = (MargaretPromisedPngR8G8B8A8){.fp = fp, .pngshka = pngshka, .info = info, .end_info = end_info}};
|
||||
}
|
||||
|
||||
SizeOfRectangleU32 MargaretPromisedPngR8G8B8A8_get_extent(const MargaretPromisedPngR8G8B8A8* self) {
|
||||
U32 width, height;
|
||||
int bit_depth, color_type;
|
||||
assert(png_get_IHDR(self->pngshka, self->info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));
|
||||
return (SizeOfRectangleU32){width, height};
|
||||
}
|
||||
|
||||
|
||||
size_t MargaretPromisedPngR8G8B8A8_get_needed_buffer_size(const MargaretPromisedPngR8G8B8A8* self) {
|
||||
SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(self);
|
||||
return 4 * dim.width * dim.height;
|
||||
}
|
||||
|
||||
ResultVoidOrVecU8 MargaretPromisedPngR8G8B8A8_finish(MargaretPromisedPngR8G8B8A8 self, void* buffer) {
|
||||
SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(&self);
|
||||
|
||||
png_bytep* row_pointers = NULL;
|
||||
if (setjmp(png_jmpbuf(self.pngshka))) {
|
||||
png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);
|
||||
fclose(self.fp);
|
||||
free(row_pointers);
|
||||
return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr("Some png error happened")};
|
||||
}
|
||||
|
||||
row_pointers = calloc(dim.height, sizeof(row_pointers));
|
||||
for (U32 y = 0; y < dim.height; y++) {
|
||||
row_pointers[dim.height - 1 - y] = ((png_bytep)buffer) + 4 * dim.width * y;
|
||||
}
|
||||
png_read_image(self.pngshka, row_pointers);
|
||||
png_read_end(self.pngshka, self.end_info);
|
||||
/* No more errors */
|
||||
png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);
|
||||
fclose(self.fp);
|
||||
free(row_pointers);
|
||||
return (ResultVoidOrVecU8){.variant = Result_Ok};
|
||||
}
|
||||
|
||||
// todo: move it to pixel_masses.h (and also generate result types automatically
|
||||
typedef struct {
|
||||
Result_variant variant;
|
||||
union {
|
||||
TextureDataR8G8B8A8 ok;
|
||||
VecU8 err;
|
||||
};
|
||||
} ResultTextureDataR8G8B8A8OrVecU8;
|
||||
|
||||
void ResultTextureDataR8G8B8A8OrVecU8_drop(ResultTextureDataR8G8B8A8OrVecU8 self) {
|
||||
if (self.variant == Result_Ok)
|
||||
TextureDataR8G8B8A8_drop(self.ok);
|
||||
else
|
||||
VecU8_drop(self.err);
|
||||
}
|
||||
|
||||
ResultTextureDataR8G8B8A8OrVecU8 MargaretPromisedPngR8G8B8A8_finish_into_TextureDataR8G8B8A8(MargaretPromisedPngR8G8B8A8 self) {
|
||||
SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(&self);
|
||||
TextureDataR8G8B8A8 tex = TextureDataR8G8B8A8_new(dim.width, dim.height);
|
||||
ResultVoidOrVecU8 res = MargaretPromisedPngR8G8B8A8_finish(self, tex.pixels.buf);
|
||||
if (res.variant == Result_Err)
|
||||
return (ResultTextureDataR8G8B8A8OrVecU8){.variant = Result_Err, .err = res.err};
|
||||
return (ResultTextureDataR8G8B8A8OrVecU8){.variant = Result_Ok, .ok = tex};
|
||||
}
|
||||
|
||||
/* aborts on error */
|
||||
TextureDataR8G8B8A8 TextureDataR8G8B8A8_read_from_png_nofail(SpanU8 name) {
|
||||
ResultMargaretPromisedPngR8G8B8A8OrVecU8 res_1 = MargaretPromisedPngR8G8B8A8_begin(name);
|
||||
if (res_1.variant == Result_Err) {
|
||||
SpanU8_fprint(VecU8_to_span(&res_1.err), stderr);
|
||||
abortf(" MargaretPromisedPngR8G8B8A8_begin\n");
|
||||
}
|
||||
/* res_1 invalidated, we moved ownership to _finish methos */
|
||||
ResultTextureDataR8G8B8A8OrVecU8 res_2 = MargaretPromisedPngR8G8B8A8_finish_into_TextureDataR8G8B8A8(res_1.ok);
|
||||
if (res_2.variant == Result_Err) {
|
||||
SpanU8_fprint(VecU8_to_span(&res_2.err), stderr);
|
||||
abortf(" MargaretPromisedPngR8G8B8A8_finish (into TextureData)\n");
|
||||
}
|
||||
return res_2.ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,361 +0,0 @@
|
||||
// Same dependencies as vulkan memory allocator
|
||||
#include "../../l1/core/uint_segments.h"
|
||||
#include "../../l1/core/util.h"
|
||||
#include "../../l1_5/core/buff_rb_tree_node.h"
|
||||
#include "../../../gen/l1_5/BufRBTree_MapU64ToU64.h"
|
||||
|
||||
typedef struct MargaretBufAllocatorOneBlock MargaretBufAllocatorOneBlock;
|
||||
|
||||
typedef struct {
|
||||
MargaretBufAllocatorOneBlock* block;
|
||||
U64 start;
|
||||
U64 len;
|
||||
} MargaretBAFreeSegment;
|
||||
|
||||
bool MargaretBAFreeSegment_less_len(const MargaretBAFreeSegment* A, const MargaretBAFreeSegment* B){
|
||||
if (A->len == B->len) {
|
||||
if (A->block == B->block) {
|
||||
return A->start < B->start;
|
||||
}
|
||||
return (uintptr_t)A->block < (uintptr_t)B->block;
|
||||
}
|
||||
return A->len < B->len;
|
||||
}
|
||||
|
||||
U64 margaret_bump_buffer_size_to_alignment(U64 A, U8 alignment_exp){
|
||||
if (A & ((1ull << alignment_exp) - 1))
|
||||
A = A - (A & ((1ull << alignment_exp) - 1)) + (1ull << alignment_exp);
|
||||
return A;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
MargaretBufAllocatorOneBlock* block;
|
||||
U64 start;
|
||||
U64 len;
|
||||
} MargaretSubbuf;
|
||||
|
||||
struct MargaretBufAllocatorOneBlock{
|
||||
BufRBTree_MapU64ToU64 occupants;
|
||||
U64 capacity;
|
||||
U64 occupation_counter;
|
||||
VkDeviceMemory mem_hand;
|
||||
VkBuffer buf_hand;
|
||||
void* mapped_memory;
|
||||
};
|
||||
|
||||
void MargaretBufAllocatorOneBlock_drop(MargaretBufAllocatorOneBlock self){
|
||||
BufRBTree_MapU64ToU64_drop(self.occupants);
|
||||
}
|
||||
#include "../../../gen/l1/eve/margaret/ListMargaretBufAllocatorOneBlock.h"
|
||||
|
||||
#include "../../../gen/l1/eve/margaret/OptionMargaretBAFreeSegment.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretBAFreeSegment.h"
|
||||
#include "../../../gen/l1_5/eve/margaret/BufRBTreeByLen_SetMargaretBAFreeSegment.h"
|
||||
|
||||
typedef struct {
|
||||
ListMargaretBufAllocatorOneBlock blocks;
|
||||
BufRBTreeByLen_SetMargaretBAFreeSegment mem_free_space;
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physical_device;
|
||||
VkBufferUsageFlags usage;
|
||||
U8 memory_type_id;
|
||||
U8 alignment_exp;
|
||||
bool host_visible;
|
||||
} MargaretBufAllocator;
|
||||
|
||||
|
||||
void MargaretBufAllocator__erase_gap(
|
||||
MargaretBufAllocator* self, MargaretBufAllocatorOneBlock* block, U64 start, U64 len){
|
||||
if (len == 0)
|
||||
return;
|
||||
bool eret = BufRBTreeByLen_SetMargaretBAFreeSegment_erase(&self->mem_free_space,
|
||||
&(MargaretBAFreeSegment){.block = block, .start = start, .len = len});
|
||||
assert(eret);
|
||||
block->occupation_counter += len;
|
||||
assert(block->occupation_counter <= block->capacity);
|
||||
}
|
||||
|
||||
void MargaretBufAllocator__insert_gap(
|
||||
MargaretBufAllocator* self, MargaretBufAllocatorOneBlock* block, U64 start, U64 len){
|
||||
if (len == 0)
|
||||
return;
|
||||
bool iret = BufRBTreeByLen_SetMargaretBAFreeSegment_insert(&self->mem_free_space,
|
||||
(MargaretBAFreeSegment){.block = block, .start = start, .len = len});
|
||||
assert(iret);
|
||||
assert(len <= block->occupation_counter);
|
||||
block->occupation_counter -= len;
|
||||
}
|
||||
|
||||
OptionMargaretBAFreeSegment MargaretBufAllocator__search_gap(MargaretBufAllocator* self, U64 req_size){
|
||||
assert(req_size % (1ull << self->alignment_exp) == 0);
|
||||
U64 sit = BufRBTreeByLen_SetMargaretBAFreeSegment_find_min_grtr_or_eq(&self->mem_free_space,
|
||||
&(MargaretBAFreeSegment){.len = req_size});
|
||||
if (sit == 0)
|
||||
return None_MargaretBAFreeSegment();
|
||||
return Some_MargaretBAFreeSegment(*BufRBTreeByLen_SetMargaretBAFreeSegment_at_iter(&self->mem_free_space, sit));
|
||||
}
|
||||
|
||||
void MargaretBufAllocator__add_block(MargaretBufAllocator* self, U64 capacity){
|
||||
VkBuffer buffer;
|
||||
check(vkCreateBuffer(self->device, &(VkBufferCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = capacity,
|
||||
.usage = self->usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE
|
||||
}, NULL, &buffer) == VK_SUCCESS);
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetBufferMemoryRequirements(self->device, buffer, &memory_requirements);
|
||||
VkDeviceMemory memory;
|
||||
check(vkAllocateMemory(self->device, &(VkMemoryAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = memory_requirements.size,
|
||||
.memoryTypeIndex = self->memory_type_id
|
||||
}, NULL, &memory) == VK_SUCCESS);
|
||||
check(vkBindBufferMemory(self->device, buffer, memory, 0) == VK_SUCCESS);
|
||||
void* mapped_memory = NULL;
|
||||
if (self->host_visible) {
|
||||
check(vkMapMemory(self->device, memory, 0, capacity, 0, &mapped_memory) == VK_SUCCESS);
|
||||
}
|
||||
ListMargaretBufAllocatorOneBlock_insert(&self->blocks, (MargaretBufAllocatorOneBlock){
|
||||
.occupants = BufRBTree_MapU64ToU64_new_reserved(1),
|
||||
.capacity = capacity,
|
||||
.occupation_counter = capacity,
|
||||
.mem_hand = memory, .buf_hand = buffer, .mapped_memory = mapped_memory
|
||||
});
|
||||
}
|
||||
|
||||
MargaretBufAllocator MargaretBufAllocator_new(
|
||||
VkDevice device, VkPhysicalDevice physical_device,
|
||||
VkBufferUsageFlags usage, U8 memory_type_id, U8 alignment_exp, bool host_visible, U64 initial_block_size
|
||||
){
|
||||
MargaretBufAllocator self = {
|
||||
.blocks = ListMargaretBufAllocatorOneBlock_new(),
|
||||
.mem_free_space = BufRBTreeByLen_SetMargaretBAFreeSegment_new_reserved(1),
|
||||
.device = device, .physical_device = physical_device, .usage = usage, .memory_type_id = memory_type_id,
|
||||
.alignment_exp = alignment_exp, .host_visible = host_visible
|
||||
};
|
||||
MargaretBufAllocator__add_block(&self, initial_block_size);
|
||||
MargaretBufAllocator__insert_gap(&self, &self.blocks.first->el, 0, initial_block_size);
|
||||
return self;
|
||||
}
|
||||
|
||||
void MargaretBufAllocator__put_buf_to_a_gap(MargaretBufAllocator* self, MargaretBAFreeSegment segment, U64 req_size){
|
||||
assert(req_size <= segment.len);
|
||||
MargaretBufAllocator__erase_gap(self, segment.block, segment.start, segment.len);
|
||||
MargaretBufAllocator__insert_gap(self, segment.block,
|
||||
segment.start + req_size, segment.len - req_size);
|
||||
BufRBTree_MapU64ToU64* occupants = &segment.block->occupants;
|
||||
bool iret = BufRBTree_MapU64ToU64_insert(occupants, segment.start, req_size);
|
||||
assert(iret);
|
||||
}
|
||||
|
||||
U64Segment MargaretBufAllocator__get_left_free_space(
|
||||
const MargaretBufAllocator* self, const MargaretSubbuf* allocation){
|
||||
U64 occ_start = allocation->start;
|
||||
U64 prev_occ_it = BufRBTree_MapU64ToU64_find_max_less(&allocation->block->occupants, allocation->start);
|
||||
if (prev_occ_it != 0) {
|
||||
U64 prev_occ_start;
|
||||
U64 prev_occ_taken_size;
|
||||
BufRBTree_MapU64ToU64_at_iter(&allocation->block->occupants, prev_occ_it, &prev_occ_start, &prev_occ_taken_size);
|
||||
|
||||
assert(prev_occ_start + prev_occ_taken_size <= occ_start);
|
||||
return (U64Segment){
|
||||
.start = prev_occ_start + prev_occ_taken_size,
|
||||
.len = occ_start - (prev_occ_start + prev_occ_taken_size)};
|
||||
}
|
||||
return (U64Segment){.start = 0, .len = occ_start};
|
||||
}
|
||||
|
||||
U64Segment MargaretBufAllocator__get_right_free_space(
|
||||
const MargaretBufAllocator* self, const MargaretSubbuf* allocation){
|
||||
U64 occ_start = allocation->start;
|
||||
U64 occ_taken_size = allocation->len;
|
||||
|
||||
U64 next_occ_it = BufRBTree_MapU64ToU64_find_min_grtr(&allocation->block->occupants, allocation->start);
|
||||
if (next_occ_it != 0) {
|
||||
U64 next_occ_start;
|
||||
U64 next_occ_taken_size;
|
||||
BufRBTree_MapU64ToU64_at_iter(&allocation->block->occupants, next_occ_it, &next_occ_start, &next_occ_taken_size);
|
||||
assert(occ_start + occ_taken_size <= next_occ_start);
|
||||
return (U64Segment){.start = occ_start + occ_taken_size, .len = next_occ_start - (occ_start + occ_taken_size)};
|
||||
}
|
||||
return (U64Segment){.start = occ_start + occ_taken_size, .len = allocation->block->capacity - (occ_start + occ_taken_size)};
|
||||
}
|
||||
|
||||
|
||||
void MargaretBufAllocator_drop(MargaretBufAllocator self){
|
||||
for (ListNodeMargaretBufAllocatorOneBlock* bi = self.blocks.first; bi; bi = bi->next) {
|
||||
vkDestroyBuffer(self.device, bi->el.buf_hand, NULL);
|
||||
vkFreeMemory(self.device, bi->el.mem_hand, NULL);
|
||||
}
|
||||
ListMargaretBufAllocatorOneBlock_drop(self.blocks);
|
||||
BufRBTreeByLen_SetMargaretBAFreeSegment_drop(self.mem_free_space);
|
||||
}
|
||||
|
||||
/* Idk how to hide this monster */
|
||||
void MargaretBufAllocator_debug(const MargaretBufAllocator* self){
|
||||
if (!self->host_visible)
|
||||
return;
|
||||
printf(" ======== MargaretBufAllocator state ======== \n");
|
||||
int n_segments = (int)self->mem_free_space.el.len;
|
||||
printf("Blocks:\n");
|
||||
for (ListNodeMargaretBufAllocatorOneBlock* block_it = self->blocks.first; block_it; block_it = block_it->next) {
|
||||
U64 free_space_acc_segs = 0;
|
||||
U64 occ_space_acc_occ = 0;
|
||||
MargaretBufAllocatorOneBlock* block = &block_it->el;
|
||||
int n_occupants = (int)block->occupants.el.len;
|
||||
printf("-*- occupied: %lu/%lu, occupants: %d\n", block->occupation_counter, block->capacity, n_occupants);
|
||||
for (int si = 0; si < n_segments; si++) {
|
||||
MargaretBAFreeSegment fseg = self->mem_free_space.el.buf[si];
|
||||
if (fseg.block == block) {
|
||||
assert(fseg.start + fseg.len <= block->capacity);
|
||||
free_space_acc_segs += fseg.len;
|
||||
}
|
||||
}
|
||||
for (int oi = 0; oi < n_occupants; oi++) {
|
||||
KVPU64ToU64 occ = block->occupants.el.buf[oi];
|
||||
assert(occ.key + occ.value <= block->capacity);
|
||||
occ_space_acc_occ += occ.value;
|
||||
for (int sc = 0; sc < n_occupants; sc++) {
|
||||
KVPU64ToU64 occ2 = block->occupants.el.buf[sc];
|
||||
if (sc != oi) {
|
||||
assert(occ.key + occ.value <= occ2.key || occ2.key + occ2.value <= occ.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(free_space_acc_segs == block->capacity - block->occupation_counter);
|
||||
assert(occ_space_acc_occ == block->occupation_counter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free one subbuffer, not a whole MBA :) */
|
||||
void MargaretBufAllocator_free(MargaretBufAllocator* self, MargaretSubbuf allocation){
|
||||
U64Segment left_free_space = MargaretBufAllocator__get_left_free_space(self, &allocation);
|
||||
U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, &allocation);
|
||||
|
||||
MargaretBufAllocator__erase_gap(self, allocation.block, left_free_space.start, left_free_space.len);
|
||||
MargaretBufAllocator__erase_gap(self, allocation.block, right_free_space.start, right_free_space.len);
|
||||
MargaretBufAllocator__insert_gap(self, allocation.block,
|
||||
left_free_space.start,
|
||||
right_free_space.start + right_free_space.len - left_free_space.start);
|
||||
|
||||
bool eret = BufRBTree_MapU64ToU64_erase(&allocation.block->occupants, allocation.start);
|
||||
assert(eret);
|
||||
// MargaretBufAllocator_debug(self);
|
||||
}
|
||||
|
||||
NODISCARD MargaretSubbuf MargaretBufAllocator_alloc(MargaretBufAllocator* self, U64 req_size){
|
||||
// MargaretBufAllocator_debug(self);
|
||||
req_size = margaret_bump_buffer_size_to_alignment(req_size, self->alignment_exp);
|
||||
|
||||
VkPhysicalDeviceMaintenance3Properties maintenance3_properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,
|
||||
};
|
||||
VkPhysicalDeviceProperties2 properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &maintenance3_properties,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(self->physical_device, &properties);
|
||||
|
||||
check(req_size <= maintenance3_properties.maxMemoryAllocationSize);
|
||||
OptionMargaretBAFreeSegment free_gap = MargaretBufAllocator__search_gap(self, req_size);
|
||||
if (free_gap.variant == Option_None) {
|
||||
assert(self->blocks.first != NULL);
|
||||
U64 pitch = self->blocks.first->el.capacity;
|
||||
// Old blocks remain intact
|
||||
U64 new_capacity = MAX_U64(req_size, MIN_U64(2 * pitch, maintenance3_properties.maxMemoryAllocationSize));
|
||||
MargaretBufAllocator__add_block(self, new_capacity);
|
||||
MargaretBufAllocatorOneBlock* new_block = &self->blocks.first->el;
|
||||
MargaretBufAllocator__insert_gap(self, new_block, req_size, new_capacity - req_size);
|
||||
new_block->occupation_counter = req_size;
|
||||
bool iret = BufRBTree_MapU64ToU64_insert(&new_block->occupants, 0, req_size);
|
||||
assert(iret);
|
||||
// MargaretBufAllocator_debug(self);
|
||||
return (MargaretSubbuf){.block = &self->blocks.first->el, 0, req_size};
|
||||
}
|
||||
MargaretBufAllocator__put_buf_to_a_gap(self, free_gap.some, req_size);
|
||||
// MargaretBufAllocator_debug(self);
|
||||
return (MargaretSubbuf){.block = free_gap.some.block, .start = free_gap.some.start, req_size};
|
||||
}
|
||||
|
||||
void MargaretBufAllocator_shrink(MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 smaller_size){
|
||||
smaller_size = margaret_bump_buffer_size_to_alignment(smaller_size, self->alignment_exp);
|
||||
assert(smaller_size > 0);
|
||||
assert(smaller_size <= allocation->len);
|
||||
|
||||
U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, allocation);
|
||||
MargaretBufAllocator__erase_gap(self, allocation->block, right_free_space.start, right_free_space.len);
|
||||
MargaretBufAllocator__insert_gap(self, allocation->block,
|
||||
allocation->start + smaller_size,
|
||||
right_free_space.len + (allocation->len - smaller_size));
|
||||
|
||||
allocation->len = smaller_size;
|
||||
}
|
||||
|
||||
/* It actually may returns a 'null-MargaretBuf-allocation' : if return value .len field is zero it means
|
||||
* that expansion in-place was possible and the allocator argument was updated with a new size and nothing was returned.
|
||||
* But if ret value .len field is non-zero it means a valid MargaretSubbuf object was returned and the
|
||||
* `allocation` argument was untouched. It remains a valid object, you need to deallocate it yourself
|
||||
*/
|
||||
NODISCARD MargaretSubbuf MargaretBufAllocator_expand(
|
||||
MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size){
|
||||
bigger_size = margaret_bump_buffer_size_to_alignment(bigger_size, self->alignment_exp);
|
||||
|
||||
U64Segment right_free_space = MargaretBufAllocator__get_right_free_space(self, allocation);
|
||||
if (allocation->start + bigger_size > right_free_space.start + right_free_space.len){
|
||||
return MargaretBufAllocator_alloc(self, bigger_size);
|
||||
}
|
||||
// MargaretBufAllocator_debug(self);
|
||||
MargaretBufAllocator__erase_gap(self, allocation->block, right_free_space.start, right_free_space.len);
|
||||
MargaretBufAllocator__insert_gap(self, allocation->block,
|
||||
allocation->start + bigger_size,
|
||||
right_free_space.len + (allocation->len - bigger_size));
|
||||
|
||||
allocation->len = bigger_size;
|
||||
U64 my_it = BufRBTree_MapU64ToU64_find(&allocation->block->occupants, allocation->start);
|
||||
assert(my_it > 0 && my_it <= allocation->block->occupants.el.len);
|
||||
allocation->block->occupants.el.buf[my_it - 1].value = bigger_size;
|
||||
// MargaretBufAllocator_debug(self);
|
||||
return (MargaretSubbuf){0};
|
||||
}
|
||||
|
||||
char* MargaretSubbuf_get_mapped(const MargaretSubbuf* allocation){
|
||||
assert(allocation->block->mapped_memory);
|
||||
assert(allocation->start + allocation->len <= allocation->block->capacity);
|
||||
return (char*)allocation->block->mapped_memory + allocation->start;
|
||||
}
|
||||
|
||||
VkBuffer MargaretSubbuf_get_buffer(const MargaretSubbuf* allocation){
|
||||
assert(allocation->start + allocation->len <= allocation->block->capacity);
|
||||
return allocation->block->buf_hand;
|
||||
}
|
||||
|
||||
/* It tries to expand buffer, but if it fails, it creates a freshly-new buffer. It copies all
|
||||
* the data from old buffer to new one and frees the old buffer, while replacing
|
||||
* info in `allocation` variable with info about new allocation.
|
||||
*/
|
||||
void MargaretBufAllocator_expand_or_move_old_host_visible(
|
||||
MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size){
|
||||
assert(self->host_visible);
|
||||
MargaretSubbuf maybe_bigger = MargaretBufAllocator_expand(self, allocation, bigger_size);
|
||||
if (maybe_bigger.len > 0) {
|
||||
memcpy(MargaretSubbuf_get_mapped(&maybe_bigger), MargaretSubbuf_get_mapped(allocation), allocation->len);
|
||||
MargaretBufAllocator_free(self, *allocation);
|
||||
*allocation = maybe_bigger;
|
||||
// MargaretBufAllocator_debug(self);
|
||||
}
|
||||
// MargaretBufAllocator_debug(self);
|
||||
}
|
||||
|
||||
/* It tries to expand buffer, but if it fails, it creates a freshly-new buffer. It
|
||||
* frees the old buffer, while replacing
|
||||
* info in `allocation` variable with info about new allocation. Old data gets lost
|
||||
*/
|
||||
void MargaretBufAllocator_expand_or_free_old(
|
||||
MargaretBufAllocator* self, MargaretSubbuf* allocation, U64 bigger_size){
|
||||
MargaretSubbuf maybe_bigger = MargaretBufAllocator_expand(self, allocation, bigger_size);
|
||||
if (maybe_bigger.len > 0) {
|
||||
MargaretBufAllocator_free(self, *allocation);
|
||||
*allocation = maybe_bigger;
|
||||
}
|
||||
}
|
||||
@ -1,556 +0,0 @@
|
||||
/* This is a Claire header. Do not include it in more that one place.
|
||||
* This Claire requires vulkan api:
|
||||
*
|
||||
*
|
||||
* typedef integer VkResult
|
||||
*
|
||||
* const VkResult VK_SUCCESS
|
||||
*
|
||||
* typedef integer VkStructureType
|
||||
*
|
||||
* const VkStructureType VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
|
||||
* const VkStructureType VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
|
||||
* const VkStructureType VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
|
||||
*
|
||||
* typedef integer VkBufferCreateFlags
|
||||
* typedef integer VkDeviceSize
|
||||
* typedef integer VkBufferUsageFlags
|
||||
* typedef integer VkSharingMode
|
||||
*
|
||||
* const VkSharingMode VK_SHARING_MODE_EXCLUSIVE
|
||||
*
|
||||
*
|
||||
* typedef handler VkPhysicalDevice
|
||||
* typedef handler VkDevice
|
||||
* typedef handler VkBuffer
|
||||
* typedef handler VkImage
|
||||
* typedef handler VkDeviceMemory
|
||||
* typedef handler VkCommandBuffer
|
||||
*
|
||||
* typedef struct {
|
||||
* VkStructureType sType;
|
||||
* const void* pNext;
|
||||
* VkBufferCreateFlags flags;
|
||||
* VkDeviceSize size;
|
||||
* VkBufferUsageFlags usage;
|
||||
* VkSharingMode sharingMode;
|
||||
* uint32_t queueFamilyIndexCount;
|
||||
* const uint32_t* pQueueFamilyIndices;
|
||||
* } VkBufferCreateInfo
|
||||
*
|
||||
* typedef integer VkMemoryPropertyFlags
|
||||
*
|
||||
* const VkMemoryPropertyFlags VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
*
|
||||
* typedef struct {
|
||||
* VkMemoryPropertyFlags propertyFlags;
|
||||
* ...
|
||||
* } VkMemoryType
|
||||
*
|
||||
* #define VK_MAX_MEMORY_TYPES 32
|
||||
*
|
||||
* typedef struct {
|
||||
* uint32_t memoryTypeCount;
|
||||
* VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES];
|
||||
* ...
|
||||
* } VkPhysicalDeviceMemoryProperties
|
||||
*
|
||||
* void vkGetPhysicalDeviceMemoryProperties(
|
||||
* VkPhysicalDevice physicalDevice,
|
||||
* VkPhysicalDeviceMemoryProperties* pMemoryProperties)
|
||||
*
|
||||
* typedef void VkAllocationCallbacks
|
||||
* (seriously, this type is only used as a pointer in an exposed api function, and it always takes NULL value)
|
||||
*
|
||||
* VkResult vkCreateBuffer(
|
||||
* VkDevice device,
|
||||
* const VkBufferCreateInfo* pCreateInfo,
|
||||
* const VkAllocationCallbacks* pAllocator,
|
||||
* VkBuffer* pBuffer)
|
||||
*
|
||||
* typedef struct {
|
||||
* VkDeviceSize size;
|
||||
* VkDeviceSize alignment;
|
||||
* uint32_t memoryTypeBits;
|
||||
* } VkMemoryRequirements
|
||||
*
|
||||
* void vkGetBufferMemoryRequirements(
|
||||
* VkDevice device,
|
||||
* VkBuffer buffer,
|
||||
* VkMemoryRequirements* pMemoryRequirements)
|
||||
*
|
||||
* typedef integer VkImageCreateFlags
|
||||
* typedef integer VkImageType
|
||||
*
|
||||
* const VkImageType VK_IMAGE_TYPE_2D
|
||||
*
|
||||
* typedef integer VkFormat
|
||||
*
|
||||
* typedef struct {
|
||||
* uint32_t width;
|
||||
* uint32_t height;
|
||||
* uint32_t depth;
|
||||
* } VkExtent3D
|
||||
*
|
||||
* typedef integer VkSampleCountFlagBits
|
||||
*
|
||||
* const VkSampleCountFlagBits VK_SAMPLE_COUNT_1_BIT
|
||||
*
|
||||
* typedef integer VkImageTiling
|
||||
*
|
||||
* const VkImageTiling VK_IMAGE_TILING_LINEAR
|
||||
*
|
||||
* const VkImageTiling VK_IMAGE_TILING_OPTIMAL
|
||||
*
|
||||
* typedef integer VkImageUsageFlags
|
||||
* typedef integer VkImageLayout
|
||||
*
|
||||
* const VkImageLayout VK_IMAGE_LAYOUT_UNDEFINED
|
||||
*
|
||||
* typedef struct {
|
||||
* VkStructureType sType;
|
||||
* const void* pNext;
|
||||
* VkImageCreateFlags flags;
|
||||
* VkImageType imageType;
|
||||
* VkFormat format;
|
||||
* VkExtent3D extent;
|
||||
* uint32_t mipLevels;
|
||||
* uint32_t arrayLayers;
|
||||
* VkSampleCountFlagBits samples;
|
||||
* VkImageTiling tiling;
|
||||
* VkImageUsageFlags usage;
|
||||
* VkSharingMode sharingMode;
|
||||
* uint32_t queueFamilyIndexCount;
|
||||
* const uint32_t* pQueueFamilyIndices;
|
||||
* VkImageLayout initialLayout;
|
||||
* } VkImageCreateInfo
|
||||
*
|
||||
* VkResult vkCreateImage(
|
||||
* VkDevice device,
|
||||
* const VkImageCreateInfo* pCreateInfo,
|
||||
* const VkAllocationCallbacks* pAllocator,
|
||||
* VkImage* pImage)
|
||||
*
|
||||
* void vkGetImageMemoryRequirements(
|
||||
* VkDevice device,
|
||||
* VkImage image,
|
||||
* VkMemoryRequirements* pMemoryRequirements)
|
||||
*
|
||||
* typedef struct {
|
||||
* VkStructureType sType;
|
||||
* const void* pNext;
|
||||
* VkDeviceSize allocationSize;
|
||||
* uint32_t memoryTypeIndex;
|
||||
* } VkMemoryAllocateInfo
|
||||
*
|
||||
* VkResult vkAllocateMemory(
|
||||
* VkDevice device,
|
||||
* const VkMemoryAllocateInfo* pAllocateInfo,
|
||||
* const VkAllocationCallbacks* pAllocator,
|
||||
* VkDeviceMemory* pMemory)
|
||||
*
|
||||
* VkResult vkBindBufferMemory(
|
||||
* VkDevice device,
|
||||
* VkBuffer buffer,
|
||||
* VkDeviceMemory memory,
|
||||
* VkDeviceSize memoryOffset)
|
||||
*
|
||||
* VkResult vkBindImageMemory(
|
||||
* VkDevice device,
|
||||
* VkImage image,
|
||||
* VkDeviceMemory memory,
|
||||
* VkDeviceSize memoryOffset)
|
||||
*
|
||||
* void vkDestroyBuffer(
|
||||
* VkDevice device,
|
||||
* VkBuffer buffer,
|
||||
* const VkAllocationCallbacks* pAllocator)
|
||||
*
|
||||
* void vkDestroyImage(
|
||||
* VkDevice device,
|
||||
* VkImage image,
|
||||
* const VkAllocationCallbacks* pAllocator)
|
||||
*/
|
||||
|
||||
#include "../../l1/core/util.h"
|
||||
#include "../../l1_5/core/buff_rb_tree_node.h"
|
||||
#include "../../../gen/l1_5/BufRBTree_MapU64ToU64.h"
|
||||
|
||||
typedef struct{
|
||||
U64 block;
|
||||
U64 start;
|
||||
U64 len;
|
||||
} MargaretIAFreeSegment;
|
||||
|
||||
#include "../../l1/core/uint_segments.h"
|
||||
|
||||
U64 margaret_get_length_resp_alignment(U64 start, U64 full_len, U8 alignment_exp) {
|
||||
if (start & ((1ull << alignment_exp) - 1)) {
|
||||
U64 pad_left = (1ull << alignment_exp) - (start & ((1ull << alignment_exp) - 1));
|
||||
return full_len >= pad_left ? full_len - pad_left : 0;
|
||||
}
|
||||
return full_len;
|
||||
}
|
||||
|
||||
bool MargaretIAFreeSegment_less_resp_align(const MargaretIAFreeSegment* A, const MargaretIAFreeSegment* B, U8 alignment_exp){
|
||||
U64 A_len = margaret_get_length_resp_alignment(A->start, A->len, alignment_exp);
|
||||
U64 B_len = margaret_get_length_resp_alignment(B->start, B->len, alignment_exp);
|
||||
if (A_len == B_len) {
|
||||
if (A->block == B->block) {
|
||||
return A->start < B->start;
|
||||
}
|
||||
return A->block < B->block;
|
||||
}
|
||||
return A_len < B_len;
|
||||
}
|
||||
|
||||
|
||||
/* Does not include all parameters needed for relocation. Because relocation is needed only
|
||||
* during controlled defragmentation */
|
||||
typedef struct {
|
||||
U64 block;
|
||||
VkImage image;
|
||||
U64 start;
|
||||
} MargaretImgAllocation;
|
||||
|
||||
/* Not primitive */
|
||||
typedef struct {
|
||||
BufRBTree_MapU64ToU64 images;
|
||||
U64 capacity;
|
||||
U64 occupation_counter;
|
||||
VkDeviceMemory mem_hand;
|
||||
void* mapped_memory;
|
||||
} MargaretImgAllocatorOneBlock;
|
||||
|
||||
void MargaretImgAllocatorOneBlock_drop(MargaretImgAllocatorOneBlock self){
|
||||
BufRBTree_MapU64ToU64_drop(self.images);
|
||||
}
|
||||
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretImgAllocatorOneBlock.h"
|
||||
|
||||
#include "../../../gen/l1/VecAndSpan_U8.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretIAFreeSegment.h"
|
||||
#include "../../../gen/l1/eve/margaret/OptionMargaretIAFreeSegment.h"
|
||||
#include "../../../gen/l1_5/eve/margaret/BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment.h"
|
||||
#include "../../../gen/l1/eve/margaret/OptionBufRBTreeByLenRespAlign_SetMargaretIAFreeSegment.h"
|
||||
|
||||
#define MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP 28
|
||||
|
||||
/* Superstructure for managing free segments of memory of some type in ALL BLOCKS */
|
||||
typedef struct {
|
||||
OptionBufRBTreeByLenRespAlign_SetMargaretIAFreeSegment free_space_in_memory[MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP];
|
||||
VecU8 set_present;
|
||||
} MargaretMemFreeSpaceManager;
|
||||
|
||||
MargaretMemFreeSpaceManager MargaretMemFreeSpaceManager_new(){
|
||||
MargaretMemFreeSpaceManager res = {.set_present = VecU8_new_zeroinit(1)};
|
||||
res.set_present.buf[0] = 3;
|
||||
for (U8 algn = 0; algn < MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP; algn++)
|
||||
res.free_space_in_memory[algn] = None_BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment();
|
||||
res.free_space_in_memory[3] = Some_BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment(
|
||||
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_new_reserved(3, 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
void MargaretMemFreeSpaceManager_drop(MargaretMemFreeSpaceManager self){
|
||||
for (U8 alignment_exp = 0; alignment_exp < MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP; alignment_exp++)
|
||||
OptionBufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_drop(self.free_space_in_memory[alignment_exp]);
|
||||
VecU8_drop(self.set_present);
|
||||
}
|
||||
|
||||
void MargaretMemFreeSpaceManager_erase(MargaretMemFreeSpaceManager* man, U64 block, U64 start, U64 len){
|
||||
if (len == 0)
|
||||
return;
|
||||
assert(man->set_present.len > 0);
|
||||
for (size_t aj = 0; aj < man->set_present.len; aj++) {
|
||||
U8 alignment = man->set_present.buf[aj];
|
||||
assert(alignment < MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP);
|
||||
assert(man->free_space_in_memory[alignment].variant == Option_Some);
|
||||
bool eret = BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_erase(&
|
||||
man->free_space_in_memory[alignment].some,
|
||||
&(MargaretIAFreeSegment){.block = block, .start = start, .len = len});
|
||||
assert(eret);
|
||||
}
|
||||
}
|
||||
|
||||
void MargaretMemFreeSpaceManager_insert(MargaretMemFreeSpaceManager* man, U64 block, U64 start, U64 len){
|
||||
if (len == 0)
|
||||
return;
|
||||
assert(man->set_present.len > 0); /* MargaretMemFreeSpaceManager will do that for us with 2^3 */
|
||||
for (size_t aj = 0; aj < man->set_present.len; aj++) {
|
||||
U8 alignment = man->set_present.buf[aj];
|
||||
assert(alignment < MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP);
|
||||
assert(man->free_space_in_memory[alignment].variant == Option_Some);
|
||||
bool iret = BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_insert(&
|
||||
man->free_space_in_memory[alignment].some, (MargaretIAFreeSegment){.block = block, .start = start, .len = len});
|
||||
assert(iret);
|
||||
}
|
||||
}
|
||||
|
||||
OptionMargaretIAFreeSegment MargaretMemFreeSpaceManager_search(
|
||||
MargaretMemFreeSpaceManager* man, U8 alignment_exp, U64 req_size) {
|
||||
check(alignment_exp < MARGARET_ALLOC_LIMIT_ALIGNMENT_EXP);
|
||||
if (man->free_space_in_memory[alignment_exp].variant == Option_None) {
|
||||
assert(man->set_present.len > 0);
|
||||
assert(man->free_space_in_memory[man->set_present.buf[0]].variant == Option_Some);
|
||||
assert(man->free_space_in_memory[alignment_exp].variant == Option_None);
|
||||
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment* have = &man->free_space_in_memory[man->set_present.buf[0]].some;
|
||||
man->free_space_in_memory[alignment_exp] = Some_BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment(
|
||||
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_new_reserved(alignment_exp, have->el.len));
|
||||
for (size_t i = 0; i < have->el.len; i++) {
|
||||
BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_insert(
|
||||
&man->free_space_in_memory[alignment_exp].some, *VecMargaretIAFreeSegment_at(&have->el, i));
|
||||
}
|
||||
VecU8_append(&man->set_present, alignment_exp);
|
||||
}
|
||||
assert(man->free_space_in_memory[alignment_exp].variant == Option_Some);
|
||||
U64 sit = BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_find_min_grtr_or_eq(
|
||||
&man->free_space_in_memory[alignment_exp].some, &(MargaretIAFreeSegment){.len = req_size,});
|
||||
if (sit == 0)
|
||||
return None_MargaretIAFreeSegment();
|
||||
return Some_MargaretIAFreeSegment(*BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment_at_iter(
|
||||
&man->free_space_in_memory[alignment_exp].some, sit));
|
||||
}
|
||||
|
||||
/* VkDevice and VkPhysicalDevice stay remembered here. Don't forget that, please */
|
||||
typedef struct {
|
||||
VecMargaretImgAllocatorOneBlock blocks;
|
||||
MargaretMemFreeSpaceManager mem_free_space;
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physical_device;
|
||||
U8 memory_type_id;
|
||||
} MargaretImgAllocator;
|
||||
|
||||
void MargaretImgAllocator__erase_gap(MargaretImgAllocator* self, U64 block_id, U64 start, U64 len){
|
||||
MargaretMemFreeSpaceManager_erase(&self->mem_free_space, block_id, start, len);
|
||||
MargaretImgAllocatorOneBlock* BLOCK = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, block_id);
|
||||
BLOCK->occupation_counter += len;
|
||||
assert(BLOCK->occupation_counter <= BLOCK->capacity);
|
||||
}
|
||||
|
||||
void MargaretImgAllocator__insert_gap(MargaretImgAllocator* self, U64 block_id, U64 start, U64 len){
|
||||
MargaretMemFreeSpaceManager_insert(&self->mem_free_space, block_id, start, len);
|
||||
MargaretImgAllocatorOneBlock* BLOCK = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, block_id);
|
||||
assert(len <= BLOCK->occupation_counter);
|
||||
BLOCK->occupation_counter -= len;
|
||||
}
|
||||
|
||||
void MargaretImgAllocator__add_block(MargaretImgAllocator* self, U64 capacity){
|
||||
VkDeviceMemory memory;
|
||||
printf("DEBUG MargaretImgAllocator: allocating block of size %lu\n", capacity);
|
||||
check(vkAllocateMemory(self->device, &(VkMemoryAllocateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = capacity, .memoryTypeIndex = self->memory_type_id
|
||||
}, NULL, &memory) == VK_SUCCESS);
|
||||
VecMargaretImgAllocatorOneBlock_append(&self->blocks, (MargaretImgAllocatorOneBlock){
|
||||
.images = BufRBTree_MapU64ToU64_new_reserved(1),
|
||||
.capacity = capacity,
|
||||
.occupation_counter = capacity, // sounds sus
|
||||
.mem_hand = memory,
|
||||
.mapped_memory = NULL /* not supported */});
|
||||
}
|
||||
|
||||
/* Idk where to put it */
|
||||
void MargaretImgAllocator__debug(const MargaretImgAllocator* self){
|
||||
printf("=============================== MargaretImgAllocator ============\n"
|
||||
"All blocks: { ");
|
||||
for (size_t i = 0; i < self->blocks.len; i++) {
|
||||
printf(" %lu/%lu ", self->blocks.buf[i].occupation_counter, self->blocks.buf[i].capacity);
|
||||
}
|
||||
printf("}\n");
|
||||
for (size_t ai = 0; ai < self->mem_free_space.set_present.len; ai++) {
|
||||
U8 alignment_exp = self->mem_free_space.set_present.buf[ai];
|
||||
printf("Free spaces at alignment_exp = %d:\n", (int)alignment_exp);
|
||||
assert(self->mem_free_space.free_space_in_memory[alignment_exp].variant == Option_Some);
|
||||
const BufRBTreeByLenRespAlign_SetMargaretIAFreeSegment* set =
|
||||
&self->mem_free_space.free_space_in_memory[alignment_exp].some;
|
||||
assert(set->guest == alignment_exp);
|
||||
for (size_t i = 0; i < set->el.len; i++) {
|
||||
const MargaretIAFreeSegment *free_seg = &set->el.buf[i];
|
||||
printf(" Block %lu, start %lu, len %lu\n", free_seg->block, free_seg->start, free_seg->len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MargaretImgAllocator MargaretImgAllocator_new(
|
||||
VkDevice device, VkPhysicalDevice physical_device, U8 memory_type_id, U64 initial_block_size
|
||||
){
|
||||
MargaretImgAllocator self = {
|
||||
.blocks = VecMargaretImgAllocatorOneBlock_new(),
|
||||
.mem_free_space = MargaretMemFreeSpaceManager_new(),
|
||||
.device = device,
|
||||
.physical_device = physical_device,
|
||||
.memory_type_id = memory_type_id,
|
||||
};
|
||||
MargaretImgAllocator__add_block(&self, initial_block_size);
|
||||
MargaretImgAllocator__insert_gap(&self, 0, 0, initial_block_size);
|
||||
// MargaretImgAllocator__debug(&self);
|
||||
return self;
|
||||
}
|
||||
|
||||
U64 margaret_get_alignment_left_padding(U64 unaligned_start, U8 alignment_exp){
|
||||
U64 hit = unaligned_start & (1ull << alignment_exp) - 1;
|
||||
return (hit ? (1ull << alignment_exp) - hit : 0);
|
||||
}
|
||||
|
||||
U64 MargaretImgAllocator__add_img_given_gap(
|
||||
MargaretImgAllocator* self, MargaretIAFreeSegment segment, U64 required_size, U8 alignment_exp
|
||||
){
|
||||
U64 gap_start = segment.start;
|
||||
U64 gap_len = segment.len;
|
||||
|
||||
U64 af = margaret_get_alignment_left_padding(gap_start, alignment_exp);
|
||||
U64 aligned_start = gap_start + af;
|
||||
assert(aligned_start + required_size <= gap_start + gap_len);
|
||||
MargaretImgAllocator__erase_gap(self, segment.block, gap_start, gap_len);
|
||||
MargaretImgAllocator__insert_gap(self, segment.block, gap_start, af);
|
||||
MargaretImgAllocator__insert_gap(self, segment.block, aligned_start + required_size,
|
||||
gap_start + gap_len - (aligned_start + required_size));
|
||||
|
||||
BufRBTree_MapU64ToU64* images = &VecMargaretImgAllocatorOneBlock_mat(&self->blocks, segment.block)->images;
|
||||
bool iret = BufRBTree_MapU64ToU64_insert(images, aligned_start, required_size);
|
||||
assert(iret);
|
||||
return aligned_start;
|
||||
}
|
||||
|
||||
U64Segment MargaretImgAllocator__get_left_free_space(
|
||||
const MargaretImgAllocator* self, MargaretImgAllocation allocation){
|
||||
const MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_at(&self->blocks, allocation.block);
|
||||
U64 occ_start = allocation.start;
|
||||
|
||||
U64 prev_occ_it = BufRBTree_MapU64ToU64_find_max_less(&block->images, allocation.start);
|
||||
if (prev_occ_it != 0) {
|
||||
U64 prev_occ_start;
|
||||
U64 prev_occ_taken_size;
|
||||
BufRBTree_MapU64ToU64_at_iter(&block->images, prev_occ_it, &prev_occ_start, &prev_occ_taken_size);
|
||||
|
||||
assert(prev_occ_start + prev_occ_taken_size <= occ_start);
|
||||
return (U64Segment){
|
||||
.start = prev_occ_start + prev_occ_taken_size,
|
||||
.len = occ_start - (prev_occ_start + prev_occ_taken_size)};
|
||||
}
|
||||
return (U64Segment){.start = 0, .len = occ_start};
|
||||
}
|
||||
|
||||
U64Segment MargaretImgAllocator__get_right_free_space(
|
||||
const MargaretImgAllocator* self, MargaretImgAllocation allocation){
|
||||
const MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_at(&self->blocks, allocation.block);
|
||||
U64 occ_start = allocation.start;
|
||||
VkMemoryRequirements occ_memory_requirements;
|
||||
vkGetImageMemoryRequirements(self->device, allocation.image, &occ_memory_requirements);
|
||||
U64 occ_taken_size = occ_memory_requirements.size;
|
||||
|
||||
U64 next_occ_it = BufRBTree_MapU64ToU64_find_min_grtr(&block->images, allocation.start);
|
||||
if (next_occ_it != 0) {
|
||||
U64 next_occ_start;
|
||||
U64 next_occ_taken_size;
|
||||
BufRBTree_MapU64ToU64_at_iter(&block->images, next_occ_it, &next_occ_start, &next_occ_taken_size);
|
||||
assert(occ_start + occ_taken_size <= next_occ_start);
|
||||
return (U64Segment){.start = occ_start + occ_taken_size, .len = next_occ_start - (occ_start + occ_taken_size)};
|
||||
}
|
||||
return (U64Segment){.start = occ_start + occ_taken_size, .len = block->capacity - (occ_start + occ_taken_size)};
|
||||
}
|
||||
|
||||
void MargaretImgAllocator_drop(MargaretImgAllocator self){
|
||||
for (size_t bi = 0; bi < self.blocks.len; bi++) {
|
||||
vkFreeMemory(self.device, self.blocks.buf[bi].mem_hand, NULL);
|
||||
}
|
||||
VecMargaretImgAllocatorOneBlock_drop(self.blocks);
|
||||
MargaretMemFreeSpaceManager_drop(self.mem_free_space);
|
||||
}
|
||||
|
||||
void MargaretImgAllocator_free(MargaretImgAllocator* self, MargaretImgAllocation allocation){
|
||||
U64Segment left_free_space = MargaretImgAllocator__get_left_free_space(self, allocation);
|
||||
U64Segment right_free_space = MargaretImgAllocator__get_right_free_space(self, allocation);
|
||||
|
||||
vkDestroyImage(self->device, allocation.image, NULL);
|
||||
|
||||
MargaretImgAllocator__erase_gap(self, allocation.block, left_free_space.start, left_free_space.len);
|
||||
MargaretImgAllocator__erase_gap(self, allocation.block, right_free_space.start, right_free_space.len);
|
||||
MargaretImgAllocator__insert_gap(self, allocation.block,
|
||||
left_free_space.start,
|
||||
right_free_space.start + right_free_space.len - left_free_space.start);
|
||||
|
||||
MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, allocation.block);
|
||||
bool eret = BufRBTree_MapU64ToU64_erase(&block->images, allocation.start);
|
||||
assert(eret);
|
||||
}
|
||||
|
||||
NODISCARD MargaretImgAllocation MargaretImgAllocator__alloc(
|
||||
MargaretImgAllocator* self, U64 width, U64 height, VkFormat format,
|
||||
VkImageUsageFlags usage_flags
|
||||
){
|
||||
VkPhysicalDeviceMaintenance3Properties maintenance3_properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,
|
||||
};
|
||||
VkPhysicalDeviceProperties2 properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &maintenance3_properties,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(self->physical_device, &properties);
|
||||
|
||||
|
||||
VkImage fresh_img;
|
||||
check(vkCreateImage(self->device, &(VkImageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = format,
|
||||
.extent = (VkExtent3D){.width = width, .height = height,.depth = 1,},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = usage_flags,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
}, NULL, &fresh_img) == VK_SUCCESS);
|
||||
VkMemoryRequirements mem_requirements;
|
||||
vkGetImageMemoryRequirements(self->device, fresh_img, &mem_requirements);
|
||||
|
||||
check(U64_is_2pow(mem_requirements.alignment));
|
||||
U8 alignment_exp = U64_2pow_log(mem_requirements.alignment);
|
||||
check(mem_requirements.size <= maintenance3_properties.maxMemoryAllocationSize);
|
||||
OptionMargaretIAFreeSegment free_gap =
|
||||
MargaretMemFreeSpaceManager_search(&self->mem_free_space, alignment_exp, mem_requirements.size);
|
||||
|
||||
if (free_gap.variant == Option_None) {
|
||||
assert(self->blocks.len > 0);
|
||||
U64 pitch = self->blocks.buf[self->blocks.len - 1].capacity;
|
||||
// Old blocks remain intact
|
||||
U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(2 * pitch, maintenance3_properties.maxMemoryAllocationSize));
|
||||
// U64 new_capacity = MAX_U64(mem_requirements.size, MIN_U64(pitch, maintenance3_properties.maxMemoryAllocationSize));
|
||||
MargaretImgAllocator__add_block(self, new_capacity);
|
||||
U64 bid = self->blocks.len - 1;
|
||||
MargaretImgAllocator__insert_gap(self, bid, mem_requirements.size, new_capacity - mem_requirements.size);
|
||||
MargaretImgAllocatorOneBlock* block = VecMargaretImgAllocatorOneBlock_mat(&self->blocks, bid);
|
||||
block->occupation_counter = mem_requirements.size;
|
||||
bool iret = BufRBTree_MapU64ToU64_insert(&block->images, 0, mem_requirements.size);
|
||||
assert(iret);
|
||||
check(vkBindImageMemory(self->device, fresh_img, block->mem_hand, 0) == VK_SUCCESS);
|
||||
// MargaretImgAllocator__debug(self);
|
||||
return (MargaretImgAllocation){.block = bid, fresh_img, 0};
|
||||
}
|
||||
U64 aligned_pos = MargaretImgAllocator__add_img_given_gap(self, free_gap.some, mem_requirements.size, alignment_exp);
|
||||
VkDeviceMemory memory = VecMargaretImgAllocatorOneBlock_at(&self->blocks, free_gap.some.block)->mem_hand;
|
||||
check(vkBindImageMemory(self->device, fresh_img, memory, aligned_pos) == VK_SUCCESS);
|
||||
// MargaretImgAllocator__debug(self);
|
||||
return (MargaretImgAllocation){.block = free_gap.some.block, .image = fresh_img, .start = aligned_pos};
|
||||
}
|
||||
|
||||
typedef struct{
|
||||
MargaretImgAllocation a;
|
||||
U64 width;
|
||||
U64 height;
|
||||
VkFormat format;
|
||||
VkImageUsageFlags usage_flags;
|
||||
VkImageLayout current_layout;
|
||||
} MargaretImg;
|
||||
|
||||
NODISCARD MargaretImg MargaretImgAllocator_alloc(
|
||||
MargaretImgAllocator* self, U64 width, U64 height, VkFormat format,
|
||||
VkImageUsageFlags usage_flags
|
||||
){
|
||||
return (MargaretImg){.a = MargaretImgAllocator__alloc(self, width, height, format, usage_flags),
|
||||
.width = width, .height = height, .format = format, .usage_flags = usage_flags,
|
||||
.current_layout = VK_IMAGE_LAYOUT_UNDEFINED};
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
#ifndef prototype1_src_l2_margaret_vulkan_memory_h
|
||||
#define prototype1_src_l2_margaret_vulkan_memory_h
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "vulkan_images_claire.h"
|
||||
#include "vulkan_buffer_claire.h"
|
||||
|
||||
#endif
|
||||
@ -1,8 +1,8 @@
|
||||
#ifndef PROTOTYPE1_SRC_L2_MARGARET_MARGARET_H
|
||||
#define PROTOTYPE1_SRC_L2_MARGARET_MARGARET_H
|
||||
|
||||
#include "../../../gen/l1/OptionU32.h"
|
||||
#include "../../../gen/l1/VecAndSpan_VecU8.h"
|
||||
#include "../../../gen/l1/Option_int_primitives.h"
|
||||
#include "../../../gen/l1/VecAndSpan_Vec_int_primitives.h"
|
||||
#include "../../l1_5/core/stringop.h"
|
||||
#include "../../l1/system/fileio.h"
|
||||
#include "time_utils.h"
|
||||
@ -18,6 +18,7 @@
|
||||
#include "../../../gen/l1/vulkan/VecVkPhysicalDevice.h"
|
||||
#include "../../../gen/l1/vulkan/SpanVkFormat.h"
|
||||
#include "../../../gen/l1/vulkan/OptionVkFormat.h"
|
||||
#include "../../../gen/l1/vulkan/VecVkDescriptorPoolSize.h"
|
||||
#include "../../../gen/l1/vulkan/VecVkQueueFamilyProperties.h"
|
||||
#include "../../../gen/l1/vulkan/OptionVkCompositeAlphaFlagBitsKHR.h"
|
||||
#include "../../../gen/l1/vulkan/VecVkPresentModeKHR.h"
|
||||
@ -27,7 +28,10 @@
|
||||
#include "../../../gen/l1/vulkan/VecVkSurfaceFormatKHR.h"
|
||||
#include "../../../gen/l1/vulkan/OptionVkSurfaceFormatKHR.h"
|
||||
#include <vulkan/vulkan_wayland.h>
|
||||
#include "../../../gen/l1/vulkan/VecVkImageMemoryBarrier.h"
|
||||
// #include <vulkan/vulkan.h>
|
||||
|
||||
|
||||
|
||||
|
||||
void margaret_create_debug_utils_messenger_EXT(
|
||||
VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
@ -269,12 +273,12 @@ NODISCARD VecU8 margaret_stringify_device_memory_properties(VkPhysicalDevice phy
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
|
||||
VecU8 result = VecU8_new();
|
||||
for (size_t h = 0; h < properties.memoryHeapCount; h++) {
|
||||
VecU8_append_vec(&result, VecU8_fmt("-+ Heap %u of %u bytes [ ", (U64)h, (U64)properties.memoryHeaps[h].size));
|
||||
VecU8_append_vec(&result, VecU8_format("-+ Heap %ld of %lu bytes [ ", h, properties.memoryHeaps[h].size));
|
||||
VecU8_append_vec(&result, margaret_stringify_memory_heap_flags(properties.memoryHeaps[h].flags));
|
||||
VecU8_append_span(&result, cstr(" ], mem types below\n"));
|
||||
for (size_t t = 0; t < properties.memoryTypeCount; t++) {
|
||||
if (properties.memoryTypes->heapIndex == h) {
|
||||
VecU8_append_vec(&result, VecU8_fmt("----> Mem type %u [ ", (U64)t));
|
||||
VecU8_append_vec(&result, VecU8_format("----> Mem type %lu [ ", t));
|
||||
VecU8_append_vec(&result, margaret_stringify_memory_property_flags(properties.memoryTypes[t].propertyFlags));
|
||||
VecU8_append_span(&result, cstr(" ]\n"));
|
||||
}
|
||||
@ -283,77 +287,40 @@ NODISCARD VecU8 margaret_stringify_device_memory_properties(VkPhysicalDevice phy
|
||||
return result;
|
||||
}
|
||||
|
||||
NODISCARD VecU8 margaret_stringify_device_memory_properties_2(VkPhysicalDevice physical_device){
|
||||
VkPhysicalDeviceMaintenance3Properties maintenance3_properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES,
|
||||
};
|
||||
VkPhysicalDeviceMaintenance4Properties maintenance4_properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES,
|
||||
.pNext = &maintenance3_properties,
|
||||
};
|
||||
VkPhysicalDeviceProperties2 properties = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
|
||||
.pNext = &maintenance4_properties,
|
||||
};
|
||||
vkGetPhysicalDeviceProperties2(physical_device, &properties);
|
||||
U64 maxBufferSize = maintenance4_properties.maxBufferSize;
|
||||
U64 maxMemoryAllocationCount = properties.properties.limits.maxMemoryAllocationCount;
|
||||
U64 maxMemoryAllocationSize = maintenance3_properties.maxMemoryAllocationSize;
|
||||
return VecU8_fmt(
|
||||
"maxMemoryAllocationsCount: %u\n"
|
||||
"maxMemoryAllocationSize: %u\n"
|
||||
"maxBufferSize: %u\n",
|
||||
maxMemoryAllocationCount, maxMemoryAllocationSize, maxBufferSize);
|
||||
}
|
||||
|
||||
VkDevice margaret_create_logical_device(VkPhysicalDevice physical_device, MargaretChosenQueueFamilies queue_fam) {
|
||||
VkPhysicalDeviceFeatures physical_features;
|
||||
vkGetPhysicalDeviceFeatures(physical_device, &physical_features);
|
||||
float qfam_queue_priorities[1] = {1.f};
|
||||
VkDeviceQueueCreateInfo queue_crinfo[2] = { 0 };
|
||||
int queue_c = 0;
|
||||
if (queue_fam.for_graphics == queue_fam.for_presentation) {
|
||||
queue_c = 1;
|
||||
queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
|
||||
} else {
|
||||
queue_c = 2;
|
||||
queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
|
||||
queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation;
|
||||
}
|
||||
for (int i = 0; i < queue_c; i++) {
|
||||
queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_crinfo[i].queueCount = 1;
|
||||
queue_crinfo[i].pQueuePriorities = qfam_queue_priorities;
|
||||
// todo: handle case of `two in one`
|
||||
float qfam_instance_priorities[1] = {1.f};
|
||||
VkDeviceQueueCreateInfo logical_device_queue_crinfo[2] = { 0 };
|
||||
for (int i = 0; i < 2; i++) {
|
||||
logical_device_queue_crinfo[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
logical_device_queue_crinfo[i].queueCount = 1;
|
||||
logical_device_queue_crinfo[i].pQueuePriorities = qfam_instance_priorities;
|
||||
}
|
||||
logical_device_queue_crinfo[0].queueFamilyIndex = queue_fam.for_graphics;
|
||||
logical_device_queue_crinfo[1].queueFamilyIndex = queue_fam.for_presentation;
|
||||
|
||||
VkPhysicalDeviceVulkan12Features used_vk12_features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
|
||||
.runtimeDescriptorArray = true,
|
||||
.descriptorBindingPartiallyBound = true,
|
||||
.shaderSampledImageArrayNonUniformIndexing = true,
|
||||
};
|
||||
// We DEMAND synchronization2
|
||||
VkPhysicalDeviceSynchronization2Features used_synchronization2_features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
|
||||
.pNext = &used_vk12_features,
|
||||
.synchronization2 = VK_TRUE,
|
||||
};
|
||||
VkPhysicalDeviceFeatures2 used_features2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &used_synchronization2_features,
|
||||
.pNext = (void*)&used_synchronization2_features,
|
||||
.features = (VkPhysicalDeviceFeatures) {
|
||||
.geometryShader = true,
|
||||
.samplerAnisotropy = physical_features.samplerAnisotropy,
|
||||
},
|
||||
};
|
||||
|
||||
const char* needed_extensions[] = {"VK_KHR_swapchain", "VK_KHR_synchronization2", "VK_KHR_maintenance4"};
|
||||
const char* needed_extensions[2] = {"VK_KHR_swapchain", "VK_KHR_synchronization2"};
|
||||
|
||||
VkDeviceCreateInfo device_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = (const void*)&used_features2,
|
||||
.queueCreateInfoCount = queue_c,
|
||||
.pQueueCreateInfos = queue_crinfo,
|
||||
.queueCreateInfoCount = ARRAY_SIZE(logical_device_queue_crinfo),
|
||||
.pQueueCreateInfos = logical_device_queue_crinfo,
|
||||
.enabledExtensionCount = ARRAY_SIZE(needed_extensions),
|
||||
.ppEnabledExtensionNames = needed_extensions,
|
||||
// We leave that filed because we have specified features2 in `.pNext`
|
||||
@ -413,8 +380,8 @@ OptionVkExtent2D margaret_choose_image_extent(const VkSurfaceCapabilitiesKHR* ca
|
||||
if (capabilities->minImageExtent.width > sane_limits.width ||
|
||||
capabilities->minImageExtent.height > sane_limits.height)
|
||||
return None_VkExtent2D();
|
||||
return Some_VkExtent2D((VkExtent2D) { MIN_U32(sane_limits.width, capabilities->maxImageExtent.width),
|
||||
MIN_U32(sane_limits.height, capabilities->maxImageExtent.height) });
|
||||
return Some_VkExtent2D((VkExtent2D) { MIN_U32(sane_limits.width, sane_limits.width),
|
||||
MIN_U32(sane_limits.height, sane_limits.height) });
|
||||
}
|
||||
/* May be bigger, than a sane limit */
|
||||
return Some_VkExtent2D(capabilities->currentExtent);
|
||||
@ -560,16 +527,12 @@ MargaretScoredPhysicalDevice margaret_score_physical_device(
|
||||
SpanU8_print(VecU8_to_span(&txt));
|
||||
VecU8_drop(txt);
|
||||
}
|
||||
VkPhysicalDeviceVulkan12Features vk12_features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES
|
||||
};
|
||||
VkPhysicalDeviceSynchronization2Features synchronization2_features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
|
||||
.pNext = &vk12_features
|
||||
};
|
||||
VkPhysicalDeviceFeatures2 features2 = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
|
||||
.pNext = &synchronization2_features,
|
||||
.pNext = (void*)&synchronization2_features,
|
||||
};
|
||||
vkGetPhysicalDeviceFeatures2(dev, &features2);
|
||||
// printf("Device %s\nmaxBoundDescriptorSets: %" PRIu32 " \nmaxPerStageDescriptorUniformBuffers: %" PRIu32 "\n"
|
||||
@ -583,23 +546,17 @@ MargaretScoredPhysicalDevice margaret_score_physical_device(
|
||||
else if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
|
||||
score += 100;
|
||||
if (!features2.features.geometryShader)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No geometry shaders")};
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No geometry shader")};
|
||||
if (!synchronization2_features.synchronization2)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No synchronization2")};
|
||||
if (!vk12_features.shaderSampledImageArrayNonUniformIndexing)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No shaderSampledImageArrayNonUniformIndexing")};
|
||||
if (!vk12_features.runtimeDescriptorArray)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No runtimeDescriptorArray")};
|
||||
if (!vk12_features.descriptorBindingPartiallyBound)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("No descriptorBindingPartiallyBound")};
|
||||
if (features2.features.samplerAnisotropy)
|
||||
score += 2;
|
||||
ResultMargaretChosenQueueFamiliesOrSpanU8 queue_families = margaret_choose_good_queue_families(dev, surface);
|
||||
if (queue_families.variant == Result_Err)
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, queue_families.err};
|
||||
// Checking device specific extensions (VK_KHR_swapchain required to check swap_chain support details
|
||||
VecVecU8 dev_extensions = margaret_get_extensions_of_physical_device(dev);
|
||||
SpanU8 required_dev_extensions[] = {
|
||||
cstr("VK_KHR_swapchain"), cstr("VK_KHR_synchronization2"),
|
||||
cstr("VK_KHR_maintenance4")};
|
||||
SpanU8 required_dev_extensions[] = {cstr("VK_KHR_swapchain"), cstr("VK_KHR_synchronization2")};
|
||||
for (size_t ei = 0; ei < ARRAY_SIZE(required_dev_extensions); ei++) {
|
||||
if (!is_string_in_string_vec(required_dev_extensions[ei], &dev_extensions))
|
||||
return (MargaretScoredPhysicalDevice){dev, -1, cstr("Missing some device extensions")};
|
||||
@ -623,7 +580,7 @@ MargaretScoredPhysicalDevice margaret_score_physical_device(
|
||||
|
||||
#define MargaretScoredPhysicalDevice_less_MargaretScoredPhysicalDevice(cap, cbp) ((cap)->score < (cbp)->score)
|
||||
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretScoredPhysicalDevice.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecAndSpan_MargaretScoredPhysicalDevice.h"
|
||||
|
||||
VecMargaretScoredPhysicalDevice margaret_get_physical_devices_scored(
|
||||
VkInstance instance, VkSurfaceKHR surface,
|
||||
@ -642,7 +599,7 @@ VecMargaretScoredPhysicalDevice margaret_get_physical_devices_scored(
|
||||
favourite_word, forbidden_word, sane_image_extent_limit
|
||||
);
|
||||
}
|
||||
VecMargaretScoredPhysicalDevice_sort(&scored_devices);
|
||||
MutSpanMargaretScoredPhysicalDevice_sort(VecMargaretScoredPhysicalDevice_to_mspan(&scored_devices));
|
||||
VecVkPhysicalDevice_drop(physical_devices);
|
||||
return scored_devices;
|
||||
}
|
||||
@ -757,7 +714,6 @@ VecVkFramebuffer margaret_create_swapchain_framebuffers(
|
||||
VecVkFramebuffer swapchain_framebuffers = VecVkFramebuffer_new_zeroinit(swapchain_image_views->len);
|
||||
for (uint32_t i = 0; i < swapchain_image_views->len; i++) {
|
||||
VkImageView attachments[1] = {*VecVkImageView_at(swapchain_image_views, i)};
|
||||
printf("CREATING FRAMEBUFFER: %u %u\n", image_extent.width, image_extent.height);
|
||||
VkFramebufferCreateInfo framebuffer_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = render_pass,
|
||||
@ -843,19 +799,34 @@ void MargaretSwapchainBundle_drop_with_device(VkDevice device, MargaretSwapchain
|
||||
VkShaderModule margaret_VkShaderModule_new(VkDevice device, VecU8 code) {
|
||||
if (code.len < 4)
|
||||
abortf("Kill yourself, please\n");
|
||||
VkShaderModule shad_module;
|
||||
check(vkCreateShaderModule(device, &(VkShaderModuleCreateInfo){
|
||||
VkShaderModuleCreateInfo shad_mod_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = code.len,
|
||||
// Now this is funny, we can't put arbitrary byte-string here, it should be 4-byte aligned
|
||||
// Thanks goodness all the strings in VecU8 are allocated with calloc, which gives high alignment to
|
||||
// virtually everything
|
||||
.pCode = (const uint32_t*)code.buf
|
||||
}, NULL, &shad_module) == VK_SUCCESS);
|
||||
VecU8_drop(code);
|
||||
};
|
||||
VkShaderModule shad_module;
|
||||
if (vkCreateShaderModule(device, &shad_mod_crinfo, NULL, &shad_module) != VK_SUCCESS)
|
||||
abortf("vkCreateShaderModule\n");
|
||||
return shad_module;
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo margaret_shader_stage_vertex_crinfo(VkShaderModule module) {
|
||||
return (VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .module = module,
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT, .pName = "main",
|
||||
};
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo margaret_shader_stage_fragment_crinfo(VkShaderModule module) {
|
||||
return (VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .module = module,
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT, .pName = "main",
|
||||
};
|
||||
}
|
||||
|
||||
VkCommandPool margaret_create_resettable_command_pool(VkDevice device, uint32_t wanted_queue_family) {
|
||||
VkCommandPoolCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
@ -917,21 +888,333 @@ VkDeviceSize margaret_align_start_of_buffer(VkDeviceSize was, VkDeviceSize align
|
||||
return was % alignment ? (was + alignment - was % alignment) : was;
|
||||
}
|
||||
|
||||
// We first specify the necessary fields `sz`, `usage` and then Snow White creation function fills `
|
||||
// Used in autogenerated code
|
||||
typedef struct {
|
||||
// necessary
|
||||
VkDeviceSize sz;
|
||||
VkBufferUsageFlags usage;
|
||||
// filled
|
||||
VkDeviceSize offset;
|
||||
VkBuffer buffer;
|
||||
} MargaretBufferInMemoryInfo;
|
||||
|
||||
typedef MargaretBufferInMemoryInfo* PtrMargaretBufferInMemoryInfo;
|
||||
|
||||
// Used in autogenerated code
|
||||
typedef struct {
|
||||
// necessary
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
VkFormat format;
|
||||
VkImageUsageFlags usage;
|
||||
// filled
|
||||
VkDeviceSize offset;
|
||||
VkImage image;
|
||||
} MargaretImageInMemoryInfo;
|
||||
|
||||
typedef MargaretImageInMemoryInfo* PtrMargaretImageInMemoryInfo;
|
||||
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretBufferInMemoryInfo.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecAndSpan_PtrMargaretBufferInMemoryInfo.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecMargaretImageInMemoryInfo.h"
|
||||
#include "../../../gen/l1/eve/margaret/VecAndSpan_PtrMargaretImageInMemoryInfo.h"
|
||||
|
||||
// A handy function to initialize buffers and images (attaching them to allocated memory)
|
||||
VkDeviceMemory margaret_initialize_buffers_and_images(
|
||||
VkPhysicalDevice physical_device, VkDevice device,
|
||||
MutSpanPtrMargaretBufferInMemoryInfo buffer_hands, MutSpanPtrMargaretImageInMemoryInfo image_hands,
|
||||
VkMemoryPropertyFlags properties
|
||||
) {
|
||||
uint32_t memory_types_allowed = -1;
|
||||
VkDeviceSize offset = 0;
|
||||
for (size_t i = 0; i < buffer_hands.len; i++) {
|
||||
MargaretBufferInMemoryInfo* buf_hand = *MutSpanPtrMargaretBufferInMemoryInfo_at(buffer_hands, i);
|
||||
VkBufferCreateInfo create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
.size = buf_hand->sz,
|
||||
.usage = buf_hand->usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
};
|
||||
if (vkCreateBuffer(device, &create_info, NULL, &buf_hand->buffer) != VK_SUCCESS) {
|
||||
abortf("vkCreateBuffer");
|
||||
}
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetBufferMemoryRequirements(device, buf_hand->buffer, &memory_requirements);
|
||||
|
||||
memory_types_allowed &= memory_requirements.memoryTypeBits;
|
||||
offset = margaret_align_start_of_buffer(offset, memory_requirements.alignment);
|
||||
buf_hand->offset = offset;
|
||||
offset = offset + memory_requirements.size;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < image_hands.len; i++) {
|
||||
MargaretImageInMemoryInfo* img_hand = *MutSpanPtrMargaretImageInMemoryInfo_at(image_hands, i);
|
||||
VkImageCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = img_hand->format,
|
||||
.extent = (VkExtent3D){
|
||||
.width = img_hand->width,
|
||||
.height = img_hand->height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = img_hand->usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
};
|
||||
if (vkCreateImage(device, &crinfo, NULL, &img_hand->image) != VK_SUCCESS)
|
||||
abortf("vkCreateImage");
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetImageMemoryRequirements(device, img_hand->image, &memory_requirements);
|
||||
|
||||
memory_types_allowed &= memory_requirements.memoryTypeBits;
|
||||
offset = margaret_align_start_of_buffer(offset, memory_requirements.alignment);
|
||||
img_hand->offset = offset;
|
||||
offset = offset + memory_requirements.size;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = offset,
|
||||
.memoryTypeIndex = margaret_find_memory_type (physical_device, memory_types_allowed, properties),
|
||||
};
|
||||
|
||||
VkDeviceMemory memory;
|
||||
if (vkAllocateMemory(device, &alloc_info, NULL, &memory) != VK_SUCCESS) {
|
||||
abortf("Having trouble allocating %lu bytes with memory type %u\n", alloc_info.allocationSize, alloc_info.memoryTypeIndex);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < buffer_hands.len; i++) {
|
||||
MargaretBufferInMemoryInfo* buf_hand = *MutSpanPtrMargaretBufferInMemoryInfo_at(buffer_hands, i);
|
||||
if (vkBindBufferMemory(device, buf_hand->buffer, memory, buf_hand->offset) != VK_SUCCESS)
|
||||
abortf("vkBindBufferMemory");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < image_hands.len; i++) {
|
||||
MargaretImageInMemoryInfo* img_hand = *MutSpanPtrMargaretImageInMemoryInfo_at(image_hands, i);
|
||||
if (vkBindImageMemory(device, img_hand->image, memory, img_hand->offset) != VK_SUCCESS)
|
||||
abortf("vkBindImageMemory");
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
#define margaret_prep_buffer_mem_info_of_gpu_vbo_Definition(TV) \
|
||||
MargaretBufferInMemoryInfo TV##_buffer_crinfo_of_gpu_vbo(size_t n) { \
|
||||
return (MargaretBufferInMemoryInfo){ \
|
||||
.sz = safe_mul_U64(sizeof(TV), n), \
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT \
|
||||
}; \
|
||||
}
|
||||
|
||||
MargaretBufferInMemoryInfo margaret_prep_buffer_mem_info_of_gpu_ebo(size_t n) {
|
||||
return (MargaretBufferInMemoryInfo){ .sz = sizeof(uint32_t) * n,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT };
|
||||
}
|
||||
|
||||
// Not very useful (but I used it anyway)
|
||||
MargaretBufferInMemoryInfo margaret_prep_buffer_mem_info_of_small_local_ubo(size_t struct_sz) {
|
||||
return (MargaretBufferInMemoryInfo){ .sz = struct_sz, .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_srgba(uint32_t w, uint32_t h) {
|
||||
return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8G8B8A8_SRGB,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_unorm_32(uint32_t w, uint32_t h) {
|
||||
return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8G8B8A8_UNORM,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT };
|
||||
}
|
||||
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_zbuffer(uint32_t max_width, uint32_t max_height, VkFormat zbuf_format) {
|
||||
return (MargaretImageInMemoryInfo){ .width = max_width, .height = max_height, .format = zbuf_format,
|
||||
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT };
|
||||
}
|
||||
|
||||
/* Used both for sampling and as a color attachment */
|
||||
MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_colorbuffer(U32 width, U32 height, VkFormat format) {
|
||||
return (MargaretImageInMemoryInfo){.width = width, .height = height, .format = format,
|
||||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT};
|
||||
}
|
||||
|
||||
MargaretBufferInMemoryInfo margaret_prep_buffer_mem_info_of_gpu_ubo(size_t struct_sz) {
|
||||
return (MargaretBufferInMemoryInfo){ .sz = struct_sz,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT };
|
||||
}
|
||||
|
||||
// Crutch for vulkan
|
||||
VkCommandBuffer margaret_alloc_and_begin_single_use_command_buffer(VkDevice device, VkCommandPool command_pool) {
|
||||
VkCommandBuffer command_buffers[1];
|
||||
VkCommandBufferAllocateInfo alloc_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandPool = command_pool,
|
||||
.commandBufferCount = ARRAY_SIZE(command_buffers),
|
||||
};
|
||||
|
||||
if (vkAllocateCommandBuffers(device, &alloc_info, command_buffers) != VK_SUCCESS)
|
||||
abortf("vkAllocateCommandBuffers");
|
||||
VkCommandBuffer copying_command_buffer = command_buffers[0];
|
||||
VkCommandBufferBeginInfo beginfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
|
||||
if (vkBeginCommandBuffer(copying_command_buffer, &beginfo) != VK_SUCCESS)
|
||||
abortf("vkBeginCommandBuffer");
|
||||
return command_buffers[0];
|
||||
}
|
||||
|
||||
void margaret_end_and_submit_and_free_command_buffer(
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
VkCommandBuffer cmd_buffer
|
||||
) {
|
||||
if (vkEndCommandBuffer(cmd_buffer) != VK_SUCCESS)
|
||||
abortf("vkEndCommandBuffer");
|
||||
|
||||
VkSubmitInfo submits_info[1] = {(VkSubmitInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmd_buffer,
|
||||
}};
|
||||
if (vkQueueSubmit(graphics_queue, ARRAY_SIZE(submits_info), submits_info, VK_NULL_HANDLE) != VK_SUCCESS)
|
||||
abortf("vkQueueSubmit");
|
||||
if (vkQueueWaitIdle(graphics_queue) != VK_SUCCESS)
|
||||
abortf("vkQueueWaitIdle");
|
||||
vkFreeCommandBuffers(device, command_pool, 1, &cmd_buffer);
|
||||
}
|
||||
|
||||
// For application initialization purposes only
|
||||
void margaret_copy_buffer_imm (
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
VkBuffer dest_buffer, VkBuffer src_buffer, VkDeviceSize buffer_size
|
||||
) {
|
||||
VkCommandBuffer cmd_buffer = margaret_alloc_and_begin_single_use_command_buffer(device, command_pool);
|
||||
|
||||
VkBufferCopy regions_to_copy[1] = {(VkBufferCopy){.srcOffset = 0, .dstOffset = 0, .size = buffer_size}};
|
||||
vkCmdCopyBuffer(cmd_buffer, src_buffer, dest_buffer, ARRAY_SIZE(regions_to_copy), regions_to_copy);
|
||||
|
||||
margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer);
|
||||
}
|
||||
|
||||
// todo: get rid of this crap. I can do better
|
||||
// For application initialization purposes only
|
||||
void transition_image_layout (
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
VkImage image, VkImageLayout old_layout, VkImageLayout new_layout,
|
||||
VkPipelineStageFlags src_stage_mask, VkAccessFlags src_access_mask,
|
||||
VkPipelineStageFlags dst_stage_mask, VkAccessFlags dst_access_mask
|
||||
) {
|
||||
VkCommandBuffer cmd_buffer = margaret_alloc_and_begin_single_use_command_buffer(device, command_pool);
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = src_access_mask,
|
||||
.dstAccessMask = dst_access_mask,
|
||||
.oldLayout = old_layout,
|
||||
.newLayout = new_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = image,
|
||||
.subresourceRange = (VkImageSubresourceRange){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vkCmdPipelineBarrier(cmd_buffer, src_stage_mask, dst_stage_mask,
|
||||
// Flags
|
||||
0,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
1, &barrier
|
||||
);
|
||||
margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer);
|
||||
}
|
||||
|
||||
// For application initialization purposes only
|
||||
void margaret_copy_buffer_to_trans_dst_optimal_image (
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
const MargaretImageInMemoryInfo* dst_image, VkBuffer src_buffer
|
||||
) {
|
||||
VkCommandBuffer cmd_buffer = margaret_alloc_and_begin_single_use_command_buffer(device, command_pool);
|
||||
VkBufferImageCopy region = {
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource = (VkImageSubresourceLayers){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = {
|
||||
.width = dst_image->width,
|
||||
.height = dst_image->height,
|
||||
.depth = 1
|
||||
},
|
||||
};
|
||||
vkCmdCopyBufferToImage(cmd_buffer, src_buffer, dst_image->image,
|
||||
// We assume that image was already transitioned to optimal layout transition_image_layout
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer);
|
||||
}
|
||||
|
||||
// todo: AHFHDF EW WHAT IS THAT???
|
||||
// For application initialization purposes only
|
||||
void margaret_copy_buffer_to_texture_for_frag_shader_imm(
|
||||
VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue,
|
||||
const MargaretImageInMemoryInfo* dst_image, VkBuffer src_buffer
|
||||
) {
|
||||
transition_image_layout(device, command_pool, graphics_queue, dst_image->image,
|
||||
// previous and new layouts
|
||||
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
// src stage and access
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0,
|
||||
// destination stage and access
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
);
|
||||
margaret_copy_buffer_to_trans_dst_optimal_image(device, command_pool, graphics_queue, dst_image, src_buffer);
|
||||
transition_image_layout(device, command_pool, graphics_queue, dst_image->image,
|
||||
// previous and new layouts
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
|
||||
// src stage and access
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
// destination stage and access
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT
|
||||
);
|
||||
}
|
||||
|
||||
// todo: cjafhs WHAT IS THIS?? I need to remove this. I can do better than this
|
||||
// For texture
|
||||
VkImageView margaret_create_view_for_image (
|
||||
VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect_flags
|
||||
){
|
||||
VkImageView view;
|
||||
check(vkCreateImageView(device, &(VkImageViewCreateInfo){
|
||||
VkDevice device, const MargaretImageInMemoryInfo* image, VkImageAspectFlags aspect_flags
|
||||
) {
|
||||
VkImageViewCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = image,
|
||||
.image = image->image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = format,
|
||||
.format = image->format,
|
||||
.subresourceRange = (VkImageSubresourceRange){
|
||||
.aspectMask = aspect_flags, .baseMipLevel = 0, .levelCount = 1,
|
||||
.baseArrayLayer = 0, .layerCount = 1,
|
||||
.aspectMask = aspect_flags,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
}, NULL, &view) == VK_SUCCESS)
|
||||
};
|
||||
VkImageView view;
|
||||
if (vkCreateImageView(device, &crinfo, NULL, &view) != VK_SUCCESS)
|
||||
abortf("vkCreateImageView");
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -941,12 +1224,11 @@ VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice dev
|
||||
vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
|
||||
VkPhysicalDeviceFeatures physical_device_features;
|
||||
vkGetPhysicalDeviceFeatures(physical_device, &physical_device_features);
|
||||
VkSampler sampler;
|
||||
check(vkCreateSampler(device, &(VkSamplerCreateInfo){
|
||||
VkSamplerCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.magFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
||||
.minFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST,
|
||||
.mipmapMode = make_linear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
||||
.mipmapMode = make_linear? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT,
|
||||
@ -960,37 +1242,37 @@ VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice dev
|
||||
.maxLod = 0.f,
|
||||
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
||||
.unnormalizedCoordinates = VK_FALSE,
|
||||
}, NULL, &sampler) == VK_SUCCESS);
|
||||
|
||||
};
|
||||
VkSampler sampler;
|
||||
if (vkCreateSampler(device, &crinfo, NULL, &sampler) != VK_SUCCESS)
|
||||
abortf("vkCreateSampler");
|
||||
return sampler;
|
||||
}
|
||||
|
||||
VkDescriptorPool margaret_create_descriptor_set_pool(
|
||||
VkDevice device, uint32_t ubo_descriptor_count, uint32_t image_sampler_descriptor_count, uint32_t max_sets
|
||||
VkDescriptorPool margaret_create_descriptor_set_pool(VkDevice device,
|
||||
uint32_t ubo_descriptor_count, uint32_t image_sampler_descriptor_count, uint32_t max_sets
|
||||
) {
|
||||
VkDescriptorPoolSize sizes[2];
|
||||
int sizes_c = 0;
|
||||
if (ubo_descriptor_count > 0) {
|
||||
sizes[sizes_c] = (VkDescriptorPoolSize){
|
||||
VecVkDescriptorPoolSize sizes = VecVkDescriptorPoolSize_new();
|
||||
if (ubo_descriptor_count > 0)
|
||||
VecVkDescriptorPoolSize_append(&sizes, (VkDescriptorPoolSize){
|
||||
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||
.descriptorCount = ubo_descriptor_count
|
||||
};
|
||||
sizes_c++;
|
||||
}
|
||||
if (image_sampler_descriptor_count > 0) {
|
||||
sizes[sizes_c] = (VkDescriptorPoolSize){
|
||||
});
|
||||
if (image_sampler_descriptor_count > 0)
|
||||
VecVkDescriptorPoolSize_append(&sizes, (VkDescriptorPoolSize){
|
||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.descriptorCount = image_sampler_descriptor_count
|
||||
};
|
||||
sizes_c++;
|
||||
}
|
||||
VkDescriptorPool descriptor_pool;
|
||||
check(vkCreateDescriptorPool(device, &(VkDescriptorPoolCreateInfo){
|
||||
});
|
||||
VkDescriptorPoolCreateInfo crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||
.maxSets = max_sets,
|
||||
.poolSizeCount = sizes_c,
|
||||
.pPoolSizes = sizes,
|
||||
}, NULL, &descriptor_pool) == VK_SUCCESS)
|
||||
.poolSizeCount = sizes.len,
|
||||
.pPoolSizes = sizes.buf,
|
||||
};
|
||||
VkDescriptorPool descriptor_pool;
|
||||
if (vkCreateDescriptorPool(device, &crinfo, NULL, &descriptor_pool) != VK_SUCCESS)
|
||||
abortf("vkCreateDescriptorPool");
|
||||
VecVkDescriptorPoolSize_drop(sizes);
|
||||
return descriptor_pool;
|
||||
}
|
||||
|
||||
@ -1007,245 +1289,4 @@ VkDescriptorSet margaret_allocate_descriptor_set(VkDevice device, VkDescriptorPo
|
||||
return descriptor_set;
|
||||
}
|
||||
|
||||
/* Aborts on error */
|
||||
void margaret_reset_and_begin_command_buffer(VkCommandBuffer command_buffer){
|
||||
check(vkResetCommandBuffer(command_buffer, 0) == VK_SUCCESS);
|
||||
check(vkBeginCommandBuffer(command_buffer,
|
||||
&(VkCommandBufferBeginInfo){ .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }) == VK_SUCCESS);
|
||||
}
|
||||
|
||||
/* Aborts on error */
|
||||
void margaret_end_command_buffer(VkCommandBuffer command_buffer){
|
||||
check(vkEndCommandBuffer(command_buffer) == VK_SUCCESS);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
VkPipelineLayout pipeline_layout;
|
||||
VecU8 vertex_shader_code;
|
||||
VecU8 geometry_shader_code;
|
||||
VecU8 fragment_shader_code;
|
||||
U32 vertexBindingDescriptionCount;
|
||||
VkVertexInputBindingDescription* pVertexBindingDescriptions;
|
||||
U32 vertexAttributeDescriptionCount;
|
||||
VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
|
||||
bool depthTestEnable;
|
||||
bool depthWriteEnable;
|
||||
bool blendEnable;
|
||||
} MargaretMostImportantPipelineOptions;
|
||||
|
||||
VkPipeline margaret_create_triangle_pipeline_one_attachment(
|
||||
VkDevice device, VkRenderPass render_pass, U32 renderpass_subpass,
|
||||
MargaretMostImportantPipelineOptions op
|
||||
){
|
||||
VkPipelineShaderStageCreateInfo shader_modules[3] = {
|
||||
(VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.module = margaret_VkShaderModule_new(device, op.vertex_shader_code),
|
||||
.stage = VK_SHADER_STAGE_VERTEX_BIT, .pName = "main",
|
||||
},
|
||||
(VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.module = margaret_VkShaderModule_new(device, op.fragment_shader_code),
|
||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT, .pName = "main",
|
||||
},
|
||||
};
|
||||
U32 shader_modules_c = 2;
|
||||
if (op.geometry_shader_code.len > 0) {
|
||||
shader_modules[shader_modules_c] = (VkPipelineShaderStageCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.module = margaret_VkShaderModule_new(device, op.geometry_shader_code),
|
||||
.stage = VK_SHADER_STAGE_GEOMETRY_BIT, .pName = "main",
|
||||
};
|
||||
shader_modules_c++;
|
||||
}
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_crinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.stageCount = shader_modules_c,
|
||||
.pStages = shader_modules,
|
||||
.pVertexInputState = &(VkPipelineVertexInputStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = op.vertexBindingDescriptionCount,
|
||||
.pVertexBindingDescriptions = op.pVertexBindingDescriptions,
|
||||
.vertexAttributeDescriptionCount = op.vertexAttributeDescriptionCount,
|
||||
.pVertexAttributeDescriptions = op.pVertexAttributeDescriptions,
|
||||
},
|
||||
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = VK_FALSE,
|
||||
},
|
||||
.pViewportState = &(VkPipelineViewportStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
// We are using dynamic viewport and scissors, that is why we do not attach viewport/scissor values
|
||||
// when creating a rendering pipeline. We will do that later
|
||||
.viewportCount = 1,
|
||||
.scissorCount = 1,
|
||||
},
|
||||
.pRasterizationState = &(VkPipelineRasterizationStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
// .cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
.cullMode = VK_CULL_MODE_NONE,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
|
||||
.depthBiasEnable = VK_FALSE,
|
||||
.depthBiasConstantFactor = 0.0f,
|
||||
.depthBiasClamp = 0.0f,
|
||||
.depthBiasSlopeFactor = 0.0f,
|
||||
.lineWidth = 1.0f,
|
||||
},
|
||||
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.sampleShadingEnable = VK_FALSE,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.minSampleShading = 1.0f,
|
||||
.pSampleMask = NULL,
|
||||
.alphaToCoverageEnable = VK_FALSE,
|
||||
.alphaToOneEnable = VK_FALSE,
|
||||
},
|
||||
.pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.depthTestEnable = op.depthTestEnable,
|
||||
.depthWriteEnable = op.depthWriteEnable,
|
||||
.depthCompareOp = VK_COMPARE_OP_LESS
|
||||
},
|
||||
.pColorBlendState = &(VkPipelineColorBlendStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &(VkPipelineColorBlendAttachmentState){
|
||||
.blendEnable = op.blendEnable,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
|
||||
},
|
||||
},
|
||||
.pDynamicState = &(VkPipelineDynamicStateCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = 2,
|
||||
.pDynamicStates = (VkDynamicState[]){VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR},
|
||||
},
|
||||
.layout = op.pipeline_layout,
|
||||
.renderPass = render_pass,
|
||||
.subpass = renderpass_subpass,
|
||||
.basePipelineHandle = VK_NULL_HANDLE,
|
||||
};
|
||||
|
||||
VkPipeline pipeline;
|
||||
check(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_crinfo, NULL, &pipeline) == VK_SUCCESS);
|
||||
|
||||
for (U32 i = 0; i < shader_modules_c; i++) {
|
||||
vkDestroyShaderModule(device, shader_modules[i].module, NULL);
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
#include "vulkan_memory.h"
|
||||
|
||||
// todo: move image copying function here
|
||||
|
||||
typedef struct {
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physical_device;
|
||||
VkCommandBuffer transfer_cmd_buffer;
|
||||
MargaretImgAllocator* dev_local_images;
|
||||
MargaretBufAllocator* dev_local_buffers;
|
||||
MargaretBufAllocator* staging_buffers;
|
||||
VkDescriptorPool descriptor_pool;
|
||||
VkSampler linear_sampler;
|
||||
VkSampler nearest_sampler;
|
||||
} MargaretEngineReference;
|
||||
|
||||
void margaret_rec_cmd_copy_buffer(
|
||||
VkCommandBuffer cmd_buf,
|
||||
const MargaretSubbuf* src_allocation, U64 src_offset,
|
||||
const MargaretSubbuf* dst_allocation, U64 dst_offset, U64 length){
|
||||
vkCmdCopyBuffer(cmd_buf,
|
||||
MargaretSubbuf_get_buffer(src_allocation), MargaretSubbuf_get_buffer(dst_allocation),
|
||||
1, &(VkBufferCopy){
|
||||
.srcOffset = src_allocation->start + src_offset, .dstOffset = dst_allocation->start + dst_offset,
|
||||
.size = length});
|
||||
}
|
||||
|
||||
void margaret_rec_cmd_copy_buffer_one_to_one_part(
|
||||
VkCommandBuffer cmd_buf,
|
||||
const MargaretSubbuf* src_allocation,
|
||||
const MargaretSubbuf* dst_allocation, U64 offset, U64 length){
|
||||
assert(offset + length <= src_allocation->len);
|
||||
assert(offset + length <= dst_allocation->len);
|
||||
vkCmdCopyBuffer(cmd_buf,
|
||||
MargaretSubbuf_get_buffer(src_allocation), MargaretSubbuf_get_buffer(dst_allocation),
|
||||
1, &(VkBufferCopy){
|
||||
.srcOffset = src_allocation->start + offset, .dstOffset = dst_allocation->start + offset, .size = length});
|
||||
}
|
||||
|
||||
void margaret_rec_cmd_copy_buffer_one_to_one(
|
||||
VkCommandBuffer cmd_buf, const MargaretSubbuf* src_allocation, const MargaretSubbuf* dst_allocation){
|
||||
U64 copying_len = MIN_U64(src_allocation->len, dst_allocation->len);
|
||||
vkCmdCopyBuffer(cmd_buf,
|
||||
MargaretSubbuf_get_buffer(src_allocation), MargaretSubbuf_get_buffer(dst_allocation),
|
||||
1, &(VkBufferCopy){
|
||||
.srcOffset = src_allocation->start, .dstOffset = dst_allocation->start, .size = copying_len});
|
||||
}
|
||||
|
||||
/* (destination_stage_mask, destination_access_mask) are probably
|
||||
* (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT) */
|
||||
void margaret_rec_cmd_copy_buffer_to_image_one_to_one_color_aspect(
|
||||
VkCommandBuffer cmd_buf, const MargaretSubbuf* src, MargaretImg* dst,
|
||||
VkImageLayout dst_new_layout,
|
||||
VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask){
|
||||
|
||||
vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0 /* Flags */, 0, NULL, 0, NULL, 1, &(VkImageMemoryBarrier){
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst->a.image,
|
||||
.subresourceRange = (VkImageSubresourceRange){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0,
|
||||
.levelCount = 1, .baseArrayLayer = 0, .layerCount = 1,
|
||||
},
|
||||
});
|
||||
|
||||
vkCmdCopyBufferToImage(cmd_buf, MargaretSubbuf_get_buffer(src), dst->a.image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &(VkBufferImageCopy){
|
||||
.bufferOffset = src->start,
|
||||
.bufferRowLength = 0,
|
||||
.bufferImageHeight = 0,
|
||||
.imageSubresource = (VkImageSubresourceLayers){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = 0, .baseArrayLayer = 0, .layerCount = 1,
|
||||
},
|
||||
.imageOffset = {0, 0, 0},
|
||||
.imageExtent = { .width = dst->width, .height = dst->height, .depth = 1 },
|
||||
});
|
||||
|
||||
vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_TRANSFER_BIT, destination_stage_mask,
|
||||
0 /* Flags */, 0, NULL, 0, NULL, 1, &(VkImageMemoryBarrier){
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = destination_access_mask,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = dst_new_layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst->a.image,
|
||||
.subresourceRange = (VkImageSubresourceRange){
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0,
|
||||
.levelCount = 1, .baseArrayLayer = 0, .layerCount = 1,
|
||||
},
|
||||
});
|
||||
dst->current_layout = dst_new_layout;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#define PROTOTYPE1_SRC_L2_MARIE_GRAPHICS_GEOM_H
|
||||
|
||||
#include "../../../gen/l1/geom.h"
|
||||
#include <math.h>
|
||||
#include "math.h"
|
||||
|
||||
mat4 marie_translation_mat4(vec3 vec) {
|
||||
return mat4_new(
|
||||
@ -91,15 +91,5 @@ vec3 marie_normal_from_tang_space_gradient(float delt_x, float delta_z) {
|
||||
return (vec3){-delt_x * N, N, -delta_z * N};
|
||||
}
|
||||
|
||||
mat4 marie_3d_scal_mat4(float scale){
|
||||
return mat4_new(scale, 0, 0, 0,
|
||||
0, scale, 0, 0,
|
||||
0, 0, scale, 0,
|
||||
0, 0, 0, 1);
|
||||
}
|
||||
|
||||
vec2 ivec2_to_vec2(ivec2 v){
|
||||
return (vec2){(float)v.x, (float)v.y};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -24,7 +24,7 @@ MarieLinearFun marie_gen_scanline_borderline(vec2 a, vec2 b) {
|
||||
|
||||
/* Utility function, that is used by rasterization function.
|
||||
* Don't use in your code*/
|
||||
void marie_h_rasterize_only_one_line_of_triangle(
|
||||
void marie_rasterize_line_in_triangle_with_attr_sorted(
|
||||
vec2 v0pos, vec2 v1pos, vec2 v2pos, S32 L, S32 R, MarieVertAttr P0, MarieVertAttr P1, MarieVertAttr P2,
|
||||
float S, S32 my, FnMarieRasterizerCallback cb
|
||||
) {
|
||||
@ -44,7 +44,7 @@ void marie_h_rasterize_only_one_line_of_triangle(
|
||||
|
||||
/* Utility function, that is used by rasterization function.
|
||||
* Don't use in your code*/
|
||||
void marie_h_rasterize_half_of_triangle(
|
||||
void marie_scan_rast_line_in_triangle_with_attr_sorted(
|
||||
vec2 v0pos, vec2 v1pos, vec2 v2pos, S32 below, S32 above, MarieVertAttr P0, MarieVertAttr P1, MarieVertAttr P2,
|
||||
MarieLinearFun left_border, MarieLinearFun right_border, FnMarieRasterizerCallback cb
|
||||
) {
|
||||
@ -66,9 +66,7 @@ void marie_h_rasterize_half_of_triangle(
|
||||
}
|
||||
}
|
||||
|
||||
/* Utility function, that is used by rasterization function.
|
||||
* Don't use in your code*/
|
||||
void marie_h_rasterize_triangle_with_attr_sorted(
|
||||
void marie_rasterize_triangle_with_attr_sorted(
|
||||
MariePlaneVertAttr v0, MariePlaneVertAttr v1, MariePlaneVertAttr v2, FnMarieRasterizerCallback cb
|
||||
) {
|
||||
float S = marie_surface(v0.pos, v1.pos, v2.pos);
|
||||
@ -91,22 +89,22 @@ void marie_h_rasterize_triangle_with_attr_sorted(
|
||||
MarieLinearFun line_12 = marie_gen_scanline_borderline(v1.pos, v2.pos);
|
||||
MarieLinearFun line_20 = marie_gen_scanline_borderline(v2.pos, v0.pos);
|
||||
|
||||
marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy0, cb);
|
||||
marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy0, cb);
|
||||
if (sy0 + 1 < sy1) {
|
||||
MarieLinearFun left_border = S > 0 ? line_20 : line_01;
|
||||
MarieLinearFun right_border = S > 0 ? line_01 : line_20;
|
||||
marie_h_rasterize_half_of_triangle(v0.pos, v1.pos, v2.pos, sy0, sy1, P0, P1, P2, left_border, right_border, cb);
|
||||
marie_scan_rast_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, sy0, sy1, P0, P1, P2, left_border, right_border, cb);
|
||||
}
|
||||
if (sy1 > sy0) {
|
||||
marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy1, cb);
|
||||
marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy1, cb);
|
||||
}
|
||||
if (sy1 + 1 < sy2) {
|
||||
MarieLinearFun left_border = S > 0 ? line_20 : line_12;
|
||||
MarieLinearFun right_border = S > 0 ? line_12 : line_20;
|
||||
marie_h_rasterize_half_of_triangle(v0.pos, v1.pos, v2.pos, sy1, sy2, P0, P1, P2, left_border, right_border, cb);
|
||||
marie_scan_rast_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, sy1, sy2, P0, P1, P2, left_border, right_border, cb);
|
||||
}
|
||||
if (sy2 > sy1) {
|
||||
marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy2, cb);
|
||||
marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy2, cb);
|
||||
}
|
||||
}
|
||||
void marie_rasterize_triangle_with_attr(
|
||||
@ -114,22 +112,22 @@ void marie_rasterize_triangle_with_attr(
|
||||
) {
|
||||
if (a.pos.y < b.pos.y) {
|
||||
if (b.pos.y < c.pos.y) {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(a, b, c, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(a, b, c, cb);
|
||||
} else {
|
||||
if (a.pos.y < c.pos.y) {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(a, c, b, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(a, c, b, cb);
|
||||
} else {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(c, a, b, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(c, a, b, cb);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a.pos.y < c.pos.y) {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(b, a, c, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(b, a, c, cb);
|
||||
} else {
|
||||
if (b.pos.y < c.pos.y) {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(b, c, a, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(b, c, a, cb);
|
||||
} else {
|
||||
marie_h_rasterize_triangle_with_attr_sorted(c, b, a, cb);
|
||||
marie_rasterize_triangle_with_attr_sorted(c, b, a, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,38 @@
|
||||
#define PROTOTYPE1_SRC_L2_MARIE_TEXTURE_PROCESSING_H
|
||||
|
||||
#include "../../../gen/l1/pixel_masses.h"
|
||||
#include "rasterization.h"
|
||||
|
||||
void TextureDataR8G8B8A8_print(const TextureDataR8G8B8A8* self) {
|
||||
U64 width = self->width;
|
||||
U64 height = TextureDataR8G8B8A8_get_height(self);
|
||||
U64 cell_width = MAX_U64(1, width / 350);
|
||||
U64 cell_height = MAX_U64(1, cell_width * 14 / 8);
|
||||
for (U64 CY = 0; CY < height; CY += cell_height) {
|
||||
for (U64 CX = 0; CX < width; CX += cell_width) {
|
||||
float lum = 0;
|
||||
for (U64 j = 0; j < cell_height; j++) {
|
||||
U64 y = cell_height * CY + j;
|
||||
if (y >= height)
|
||||
continue;
|
||||
for (U64 i = 0; i < cell_width; i++) {
|
||||
U64 x = cell_width * CX + i;
|
||||
if (x >= width)
|
||||
continue;
|
||||
cvec4 pix = *TextureDataR8G8B8A8_at(self, x, y);
|
||||
lum += (float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f;
|
||||
}
|
||||
}
|
||||
lum /= (float)cell_width * (float)cell_height;
|
||||
printf("%s", lum > 0.95 ? "@" : (lum > 0.8 ? "#" : (lum > 0.65 ? "*" : (lum > 0.4 ? "_" : (lum > 0.2 ? "." : " ")))));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Fixes several of my generated textures */
|
||||
NODISCARD TextureDataR8G8B8A8 TextureDataR8G8B8A8_expand_nontransparent_1px(const TextureDataR8G8B8A8* self) {
|
||||
S32 width = (S32)self->width;
|
||||
S32 height = (S32)self->height;
|
||||
S32 height = (S32)TextureDataR8G8B8A8_get_height(self);
|
||||
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height);
|
||||
// S32 chain[9][2] = {{0, 0}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}};
|
||||
for (S32 y = 0; y < height; y++) {
|
||||
@ -36,53 +62,4 @@ NODISCARD TextureDataR8G8B8A8 TextureDataR8G8B8A8_expand_nontransparent_1px(cons
|
||||
return res;
|
||||
}
|
||||
|
||||
vec4 marie_color_cvec4_to_vec4(cvec4 clr) {
|
||||
return (vec4){(float)clr.x / 255, (float)clr.y / 255, (float)clr.z / 255, (float)clr.w / 255};
|
||||
}
|
||||
|
||||
cvec4 marie_color_vec4_to_cvec4(vec4 clr) {
|
||||
return (cvec4){(U8)roundf(clr.x * 255), (U8)roundf(clr.y * 255), (U8)roundf(clr.z * 255), (U8)roundf(clr.w * 255)};
|
||||
}
|
||||
|
||||
vec3 marie_color_cvec3_to_vec3(cvec3 clr) {
|
||||
return (vec3){(float)clr.x / 255, (float)clr.y / 255, (float)clr.z / 255};
|
||||
}
|
||||
|
||||
cvec3 marie_color_vec3_to_cvec3(vec3 clr) {
|
||||
return (cvec3){(U8)roundf(clr.x * 255), (U8)roundf(clr.y * 255), (U8)roundf(clr.z * 255)};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* self;
|
||||
cvec4 pixel;
|
||||
} TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest;
|
||||
|
||||
void TextureDataR8G8B8A8_draw_triangle_of_one_color_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest *g = ug;
|
||||
if (TextureDataR8G8B8A8_is_inside(g->self, x, y))
|
||||
*TextureDataR8G8B8A8_mat(g->self, x, y) = g->pixel;
|
||||
}
|
||||
|
||||
/* Given triangle is not natural : it is from parameter space */
|
||||
void TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(
|
||||
TextureDataR8G8B8A8* self, vec3 color, MarieTriangle param_triang, mat3x2 trop
|
||||
) {
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest aboba =
|
||||
{ self, marie_color_vec4_to_cvec4(vec3_and_one(color)) };
|
||||
MarieTriangle natural = MarieTriangle_mat3x2_mul_pos(param_triang, trop);
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){natural.v0, {}}, (MariePlaneVertAttr){natural.v1, {}}, (MariePlaneVertAttr){natural.v2, {}},
|
||||
(FnMarieRasterizerCallback){.fn = TextureDataR8G8B8A8_draw_triangle_of_one_color_h_draw_guest,
|
||||
.guest = &aboba});
|
||||
}
|
||||
|
||||
void TextureDataR8G8B8A8_draw_triangle_of_one_color(TextureDataR8G8B8A8* self, vec3 color, MarieTriangle trig){
|
||||
TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest aboba =
|
||||
{ self, marie_color_vec4_to_cvec4(vec3_and_one(color)) };
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){trig.v0, {}}, (MariePlaneVertAttr){trig.v1, {}}, (MariePlaneVertAttr){trig.v2, {}},
|
||||
(FnMarieRasterizerCallback){.fn = TextureDataR8G8B8A8_draw_triangle_of_one_color_h_draw_guest,
|
||||
.guest = &aboba});
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,22 +1,21 @@
|
||||
#include "../../../../gen/l1_5/BufRBTree_SetS64.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_S64.h"
|
||||
#include "../../../../gen/l1_5/BuffRBTree_SetS64.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
#include "../../../l1/core/VecU8_as_str.h"
|
||||
#include "../../../../gen/l1/OptionS64.h"
|
||||
#include "../../../l1/system/fileio.h"
|
||||
#include "../../../l1/system/fsmanip.h"
|
||||
#include "../../../l1/system/creating_child_proc.h"
|
||||
|
||||
void check_structure_h_dfs(const VecBufRBTreeNode* tree, U64 x, VecU8* f){
|
||||
void check_structure_h_dfs(const VecRBTreeNode* tree, U64 x, VecU8* f){
|
||||
if (x == 0)
|
||||
return;
|
||||
if (*VecU8_at(f, x - 1) != 0)
|
||||
check(false);
|
||||
*VecU8_mat(f, x - 1) = 1;
|
||||
check_structure_h_dfs(tree, VecBufRBTreeNode_at(tree, x)->left, f);
|
||||
check_structure_h_dfs(tree, VecBufRBTreeNode_at(tree, x)->right, f);
|
||||
check_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->left, f);
|
||||
check_structure_h_dfs(tree, VecRBTreeNode_at(tree, x)->right, f);
|
||||
}
|
||||
|
||||
U32 check_structure_h_dfs_2(BufRBTreeNode* tree, U64 x){
|
||||
U32 check_structure_h_dfs_2(RBTreeNode* tree, U64 x){
|
||||
if (x == 0) {
|
||||
return 0;
|
||||
}
|
||||
@ -26,7 +25,7 @@ U32 check_structure_h_dfs_2(BufRBTreeNode* tree, U64 x){
|
||||
return a + (tree[x].color == RBTree_black ? 1 : 0);
|
||||
}
|
||||
|
||||
S64 min_key_in_subtree(const BufRBTree_SetS64* self, U64 x){
|
||||
S64 min_key_in_subtree(const BuffRBTree_SetS64* self, U64 x){
|
||||
assert(x != 0 && x < self->tree.len);
|
||||
S64 ans = self->el.buf[x - 1];
|
||||
if (self->tree.buf[x].left != 0) {
|
||||
@ -38,7 +37,7 @@ S64 min_key_in_subtree(const BufRBTree_SetS64* self, U64 x){
|
||||
return ans;
|
||||
}
|
||||
|
||||
S64 max_key_in_subtree(const BufRBTree_SetS64* self, U64 x){
|
||||
S64 max_key_in_subtree(const BuffRBTree_SetS64* self, U64 x){
|
||||
assert(x != 0 && x < self->tree.len);
|
||||
S64 ans = self->el.buf[x - 1];
|
||||
if (self->tree.buf[x].left != 0) {
|
||||
@ -50,7 +49,7 @@ S64 max_key_in_subtree(const BufRBTree_SetS64* self, U64 x){
|
||||
return ans;
|
||||
}
|
||||
|
||||
void check_only_structure(const BufRBTree_SetS64* self){
|
||||
void check_only_structure(const BuffRBTree_SetS64* self){
|
||||
check(self->tree.len == self->el.len + 1);
|
||||
check(self->root < self->tree.len);
|
||||
if (self->tree.len > 1) {
|
||||
@ -80,7 +79,7 @@ void check_only_structure(const BufRBTree_SetS64* self){
|
||||
}
|
||||
}
|
||||
|
||||
void check_correctness(const BufRBTree_SetS64* self){
|
||||
void check_correctness(const BuffRBTree_SetS64* self){
|
||||
check_only_structure(self);
|
||||
|
||||
/* Checking coloring */
|
||||
@ -114,7 +113,7 @@ void check_correctness(const BufRBTree_SetS64* self){
|
||||
}
|
||||
}
|
||||
|
||||
void save_tree_to_file(const BufRBTree_SetS64* set, SpanU8 name){
|
||||
void save_tree_to_file(const BuffRBTree_SetS64* set, SpanU8 name){
|
||||
check_only_structure(set);
|
||||
|
||||
VecS64 ranked_node_to_rb_node = VecS64_new_reserved(set->el.len);
|
||||
@ -186,236 +185,190 @@ void save_tree_to_file(const BufRBTree_SetS64* set, SpanU8 name){
|
||||
}
|
||||
VecU8_append_span(&graph, cstr("}\n"));
|
||||
mkdir_nofail("GRAPHS");
|
||||
write_file_by_path(VecU8_fmt("GRAPHS/GRAPH_%s.gv", name), VecU8_to_span(&graph));
|
||||
VecU8 dot_filename_nt = VecU8_fmt("GRAPHS/GRAPH_%s.gv%c", name, 0);
|
||||
write_whole_file_or_abort((CSTR)dot_filename_nt.buf, VecU8_to_span(&graph));
|
||||
VecU8_drop(graph);
|
||||
VecU8_drop(dot_filename_nt);
|
||||
VecU8 command_nt = VecU8_fmt("dot -Tpng GRAPHS/GRAPH_%s.gv -o GRAPHS/GRAPH_%s.png%c", name, name, 0);
|
||||
calling_system_func_nofail((CSTR)command_nt.buf);
|
||||
VecU8_drop(command_nt);
|
||||
}
|
||||
|
||||
OptionS64 VecS64_find_max_less(const VecS64* set, S64 key){
|
||||
OptionS64 max_less = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] < key)
|
||||
if (max_less.variant == Option_None || max_less.some < set->buf[i])
|
||||
max_less = Some_S64(set->buf[i]);
|
||||
return max_less;
|
||||
}
|
||||
|
||||
OptionS64 VecS64_find_max_less_or_eq(const VecS64* set, S64 key){
|
||||
OptionS64 max_less = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] <= key)
|
||||
if (max_less.variant == Option_None || max_less.some < set->buf[i])
|
||||
max_less = Some_S64(set->buf[i]);
|
||||
return max_less;
|
||||
}
|
||||
|
||||
|
||||
OptionS64 VecS64_find_min_grtr(const VecS64* set, S64 key){
|
||||
OptionS64 min_grtr = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] > key)
|
||||
if (min_grtr.variant == Option_None || min_grtr.some > set->buf[i])
|
||||
min_grtr = Some_S64(set->buf[i]);
|
||||
return min_grtr;
|
||||
}
|
||||
|
||||
|
||||
OptionS64 VecS64_find_min_grtr_or_eq(const VecS64* set, S64 key){
|
||||
OptionS64 min_grtr = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] >= key)
|
||||
if (min_grtr.variant == Option_None || min_grtr.some > set->buf[i])
|
||||
min_grtr = Some_S64(set->buf[i]);
|
||||
return min_grtr;
|
||||
}
|
||||
|
||||
void check_option_int_equiv_node(OptionS64 true_ans, BufRBTree_SetS64* set, U64 my_ans){
|
||||
if (true_ans.variant == Option_None) {
|
||||
check(my_ans == 0);
|
||||
} else {
|
||||
check(my_ans != 0 && my_ans < set->tree.len);
|
||||
check(set->el.buf[my_ans - 1] == true_ans.some);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void insert_only(){
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
check_correctness(&set);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
bool ret = BufRBTree_SetS64_insert(&set, 42);
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
bool ret = BuffRBTree_SetS64_insert(&set, 42);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
check(set.el.len == 1);
|
||||
check(set.root == 1);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
bool ret;
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
ret = BufRBTree_SetS64_insert(&set, 42);
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
ret = BuffRBTree_SetS64_insert(&set, 42);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
ret = BufRBTree_SetS64_insert(&set, 69);
|
||||
ret = BuffRBTree_SetS64_insert(&set, 69);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
check(set.el.len == 2);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
bool ret;
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
ret = BufRBTree_SetS64_insert(&set, 70);
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
ret = BuffRBTree_SetS64_insert(&set, 70);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
ret = BufRBTree_SetS64_insert(&set, 50);
|
||||
ret = BuffRBTree_SetS64_insert(&set, 50);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
check(set.el.len == 2);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
bool ret;
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
ret = BufRBTree_SetS64_insert(&set, 1);
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
ret = BuffRBTree_SetS64_insert(&set, 1);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
ret = BufRBTree_SetS64_insert(&set, 2);
|
||||
ret = BuffRBTree_SetS64_insert(&set, 2);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
ret = BufRBTree_SetS64_insert(&set, 3);
|
||||
ret = BuffRBTree_SetS64_insert(&set, 3);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
for (S64 i = 10; i < 100; i++) {
|
||||
bool ret = BufRBTree_SetS64_insert(&set, i);
|
||||
bool ret = BuffRBTree_SetS64_insert(&set, i);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
}
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
for (S64 i = 99; i >= 10; i--) {
|
||||
bool ret = BufRBTree_SetS64_insert(&set, i);
|
||||
bool ret = BuffRBTree_SetS64_insert(&set, i);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
}
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
for (S64 i = 10; i < 100; i++) {
|
||||
bool ret = BufRBTree_SetS64_insert(&set, i);
|
||||
bool ret = BuffRBTree_SetS64_insert(&set, i);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
bool ret2 = BufRBTree_SetS64_insert(&set, 1000 - i);
|
||||
bool ret2 = BuffRBTree_SetS64_insert(&set, 1000 - i);
|
||||
check(ret2);
|
||||
check_correctness(&set);
|
||||
}
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
// BufRBTree_SetS64_erase_substitute()
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
// BuffRBTree_SetS64_erase_substitute()
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
}
|
||||
|
||||
void insert_and_then_find(){
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
for (S64 p = 0; p < 100; p++) {
|
||||
bool ret = BufRBTree_SetS64_insert(&set, 2 * p);
|
||||
bool ret = BuffRBTree_SetS64_insert(&set, 2 * p);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
for (S64 i = 0; i <= p; i++) {
|
||||
U64 ret1 = BufRBTree_SetS64_find(&set, 2 * i);
|
||||
U64 ret1 = BuffRBTree_SetS64_find(&set, 2 * i);
|
||||
check(ret1);
|
||||
U64 ret2 = BufRBTree_SetS64_find(&set, 2 * i + 1);
|
||||
U64 ret2 = BuffRBTree_SetS64_find(&set, 2 * i + 1);
|
||||
check(ret2 == 0);
|
||||
}
|
||||
}
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
|
||||
void insert_and_delete(){
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
check(BufRBTree_SetS64_insert(&set, 1))
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
check(BuffRBTree_SetS64_insert(&set, 1))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_find(&set, 1));
|
||||
check(BufRBTree_SetS64_erase(&set, 1));
|
||||
check(BuffRBTree_SetS64_find(&set, 1));
|
||||
check(BuffRBTree_SetS64_erase(&set, 1));
|
||||
check_correctness(&set);
|
||||
check(!BufRBTree_SetS64_find(&set, 1));
|
||||
BufRBTree_SetS64_drop(set);
|
||||
check(!BuffRBTree_SetS64_find(&set, 1));
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
check(BufRBTree_SetS64_insert(&set, 1))
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
check(BuffRBTree_SetS64_insert(&set, 1))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_insert(&set, 2))
|
||||
check(BuffRBTree_SetS64_insert(&set, 2))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_erase(&set, 2));
|
||||
check(BuffRBTree_SetS64_erase(&set, 2));
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_find(&set, 1));
|
||||
check(!BufRBTree_SetS64_find(&set, 2));
|
||||
check(BufRBTree_SetS64_erase(&set, 1));
|
||||
check(BuffRBTree_SetS64_find(&set, 1));
|
||||
check(!BuffRBTree_SetS64_find(&set, 2));
|
||||
check(BuffRBTree_SetS64_erase(&set, 1));
|
||||
check_correctness(&set);
|
||||
check(!BufRBTree_SetS64_find(&set, 1));
|
||||
check(!BufRBTree_SetS64_find(&set, 2));
|
||||
BufRBTree_SetS64_drop(set);
|
||||
check(!BuffRBTree_SetS64_find(&set, 1));
|
||||
check(!BuffRBTree_SetS64_find(&set, 2));
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
check(BufRBTree_SetS64_insert(&set, 1))
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
check(BuffRBTree_SetS64_insert(&set, 1))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_insert(&set, 2))
|
||||
check(BuffRBTree_SetS64_insert(&set, 2))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_erase(&set, 1));
|
||||
check(BuffRBTree_SetS64_erase(&set, 1));
|
||||
check_correctness(&set);
|
||||
check(!BufRBTree_SetS64_find(&set, 1));
|
||||
check(BufRBTree_SetS64_find(&set, 2));
|
||||
check(!BuffRBTree_SetS64_find(&set, 1));
|
||||
check(BuffRBTree_SetS64_find(&set, 2));
|
||||
|
||||
check(!BufRBTree_SetS64_erase(&set, 1));
|
||||
check(!BufRBTree_SetS64_find(&set, 1));
|
||||
check(BufRBTree_SetS64_find(&set, 2));
|
||||
check(BufRBTree_SetS64_erase(&set, 2));
|
||||
check(!BuffRBTree_SetS64_erase(&set, 1));
|
||||
check(!BuffRBTree_SetS64_find(&set, 1));
|
||||
check(BuffRBTree_SetS64_find(&set, 2));
|
||||
check(BuffRBTree_SetS64_erase(&set, 2));
|
||||
check_correctness(&set);
|
||||
check(!BufRBTree_SetS64_find(&set, 1));
|
||||
check(!BufRBTree_SetS64_find(&set, 2));
|
||||
BufRBTree_SetS64_drop(set);
|
||||
check(!BuffRBTree_SetS64_find(&set, 1));
|
||||
check(!BuffRBTree_SetS64_find(&set, 2));
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
for (S64 i = -120; i < 1000; i += 10) {
|
||||
check(BufRBTree_SetS64_insert(&set, i))
|
||||
check(BuffRBTree_SetS64_insert(&set, i))
|
||||
check_correctness(&set);
|
||||
}
|
||||
// save_tree_to_file(&set, cstr("tree"));
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
check(BufRBTree_SetS64_insert(&set, 1))
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
check(BuffRBTree_SetS64_insert(&set, 1))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_insert(&set, 2))
|
||||
check(BuffRBTree_SetS64_insert(&set, 2))
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_insert(&set, 3))
|
||||
check(BuffRBTree_SetS64_insert(&set, 3))
|
||||
check_correctness(&set);
|
||||
// save_tree_to_file(&set, cstr("trio"));
|
||||
check(BufRBTree_SetS64_erase(&set, 2));
|
||||
check(BuffRBTree_SetS64_erase(&set, 2));
|
||||
check_correctness(&set);
|
||||
// save_tree_to_file(&set, cstr("duo"));
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,54 +396,54 @@ VecS64 gen_cool_sequence(S64 i){
|
||||
void chaos(){
|
||||
for (int i = 1; i < 100; i++) {
|
||||
srand(i);
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
VecS64 seq_to_insert = gen_cool_sequence(i);
|
||||
for (int j = 0; j < i; j++) {
|
||||
S64 to_insert = seq_to_insert.buf[j];
|
||||
BufRBTree_SetS64_insert(&set, to_insert);
|
||||
BuffRBTree_SetS64_insert(&set, to_insert);
|
||||
check_correctness(&set);
|
||||
}
|
||||
assert(set.el.len == (size_t)i);
|
||||
// save_tree_to_file(&set, cstr("last_good"));
|
||||
S64 to_delete = (rand() % i + 1) * 10;
|
||||
printf("Started deleting from i=%d\n", i);
|
||||
check(BufRBTree_SetS64_erase(&set, to_delete));
|
||||
check(BuffRBTree_SetS64_erase(&set, to_delete));
|
||||
printf("Deleted from i=%d\n", i);
|
||||
check_only_structure(&set);
|
||||
// save_tree_to_file(&set, cstr("chucked_tree"));
|
||||
// save_tree_to_file(&set, cstr("fucked_tree"));
|
||||
check_correctness(&set);
|
||||
VecS64_drop(seq_to_insert);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
}
|
||||
|
||||
void triple_black(){
|
||||
BufRBTree_SetS64 set;
|
||||
BuffRBTree_SetS64 set;
|
||||
{
|
||||
VecBufRBTreeNode tree = VecBufRBTreeNode_new_zeroinit(4);
|
||||
tree.buf[1] = (BufRBTreeNode){.parent = 3};
|
||||
tree.buf[2] = (BufRBTreeNode){.parent = 3};
|
||||
tree.buf[3] = (BufRBTreeNode){.left = 2, .right = 1};
|
||||
VecRBTreeNode tree = VecRBTreeNode_new_zeroinit(4);
|
||||
tree.buf[1] = (RBTreeNode){.parent = 3};
|
||||
tree.buf[2] = (RBTreeNode){.parent = 3};
|
||||
tree.buf[3] = (RBTreeNode){.left = 2, .right = 1};
|
||||
VecS64 el = VecS64_new_reserved(3);
|
||||
VecS64_append(&el, 300);
|
||||
VecS64_append(&el, 100);
|
||||
VecS64_append(&el, 200);
|
||||
set = (BufRBTree_SetS64){.tree = tree, .root = 3, .el = el};
|
||||
set = (BuffRBTree_SetS64){.tree = tree, .root = 3, .el = el};
|
||||
}
|
||||
check_correctness(&set);
|
||||
check(BufRBTree_SetS64_erase(&set, 300));
|
||||
check(BuffRBTree_SetS64_erase(&set, 300));
|
||||
check_correctness(&set);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
|
||||
void absolute_chaos(){
|
||||
for (int i = 1; i < 100; i++) {
|
||||
srand(i);
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
VecS64 seq_to_insert = gen_cool_sequence(i);
|
||||
for (int j = 0; j < i; j++) {
|
||||
S64 to_insert = seq_to_insert.buf[j];
|
||||
check(BufRBTree_SetS64_insert(&set, to_insert));
|
||||
check(BuffRBTree_SetS64_insert(&set, to_insert));
|
||||
check_correctness(&set);
|
||||
}
|
||||
printf("Filled chaos with i = %d\n", i);
|
||||
@ -499,14 +452,14 @@ void absolute_chaos(){
|
||||
VecS64 seq_to_erase = gen_cool_sequence(i);
|
||||
for (int j = 0; j < i; j++) {
|
||||
S64 to_erase = seq_to_erase.buf[j];
|
||||
check(BufRBTree_SetS64_erase(&set, to_erase));
|
||||
check(BuffRBTree_SetS64_erase(&set, to_erase));
|
||||
check_correctness(&set);
|
||||
}
|
||||
printf("Emptied chaos with i = %d\n", i);
|
||||
assert(set.el.len == 0);
|
||||
VecS64_drop(seq_to_insert);
|
||||
VecS64_drop(seq_to_erase);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,7 +467,7 @@ void stress(){
|
||||
printf("Prepare for some real stress\n");
|
||||
for (int s = 2; s < 1000; s++) {
|
||||
srand(s);
|
||||
BufRBTree_SetS64 set = BufRBTree_SetS64_new();
|
||||
BuffRBTree_SetS64 set = BuffRBTree_SetS64_new();
|
||||
VecS64 real_set = VecS64_new();
|
||||
U32 n = (U32)s;
|
||||
VecS64 complementary_set = VecS64_new_reserved(n);
|
||||
@ -523,7 +476,7 @@ void stress(){
|
||||
}
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
/* Do something */
|
||||
bool do_insertion = (rand() % 9) >= 4;
|
||||
int do_insertion = rand() % 2;
|
||||
if (real_set.len == 0)
|
||||
do_insertion = 1;
|
||||
if (complementary_set.len == 0)
|
||||
@ -533,52 +486,26 @@ void stress(){
|
||||
size_t j = rand() % complementary_set.len;
|
||||
S64 v = VecS64_unordered_pop(&complementary_set, j);
|
||||
VecS64_append(&real_set, v);
|
||||
check(BufRBTree_SetS64_insert(&set, v));
|
||||
check_correctness(&set);
|
||||
check(BuffRBTree_SetS64_insert(&set, v));
|
||||
} else {
|
||||
assert(real_set.len > 0);
|
||||
size_t j = rand() % real_set.len;
|
||||
S64 v = VecS64_unordered_pop(&real_set, j);
|
||||
VecS64_append(&complementary_set, v);
|
||||
check(BufRBTree_SetS64_erase(&set, v));
|
||||
check_correctness(&set);
|
||||
check(BuffRBTree_SetS64_erase(&set, v));
|
||||
}
|
||||
/* We did something */
|
||||
check(real_set.len == set.el.len);
|
||||
for (size_t j = 0; j < real_set.len; j++) {
|
||||
check(BufRBTree_SetS64_find(&set, real_set.buf[j]) != 0);
|
||||
check(BuffRBTree_SetS64_find(&set, real_set.buf[j]) != 0);
|
||||
}
|
||||
for (size_t j = 0; j < complementary_set.len; j++) {
|
||||
check(BufRBTree_SetS64_find(&set, complementary_set.buf[j]) == 0);
|
||||
}
|
||||
/* Checking weird methods that nobody needs */
|
||||
for (int tt = 0; tt < 15; tt++) {
|
||||
S64 key = (S64)(rand() % n) * 10;
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_max_less(&real_set, key);
|
||||
U64 my_ans = BufRBTree_SetS64_find_max_less(&set, key);
|
||||
check_option_int_equiv_node(true_ans, &set, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_max_less_or_eq(&real_set, key);
|
||||
U64 my_ans = BufRBTree_SetS64_find_max_less_or_eq(&set, key);
|
||||
check_option_int_equiv_node(true_ans, &set, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_min_grtr(&real_set, key);
|
||||
U64 my_ans = BufRBTree_SetS64_find_min_grtr(&set, key);
|
||||
check_option_int_equiv_node(true_ans, &set, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_min_grtr_or_eq(&real_set, key);
|
||||
U64 my_ans = BufRBTree_SetS64_find_min_grtr_or_eq(&set, key);
|
||||
check_option_int_equiv_node(true_ans, &set, my_ans);
|
||||
}
|
||||
check(BuffRBTree_SetS64_find(&set, complementary_set.buf[j]) == 0);
|
||||
}
|
||||
}
|
||||
VecS64_drop(real_set);
|
||||
VecS64_drop(complementary_set);
|
||||
BufRBTree_SetS64_drop(set);
|
||||
BuffRBTree_SetS64_drop(set);
|
||||
printf("Seed s=%d passed test\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,381 +0,0 @@
|
||||
// todo: rewrite this test with structures from l1_5/eve/margaret
|
||||
// todo: but before that: don't even bother running this test
|
||||
|
||||
// #include "../../../../gen/l1_5/BuffRBTreeByLen_SetU64Segment.h"
|
||||
// #include "../../../../gen/l1_5/BuffRBTreeByStart_SetU64Segment.h"
|
||||
// #include "../../../../gen/l1_5/BuffRBTreeByLenRespAlign_SetU64Segment.h"
|
||||
// #include "../../../l1/core/VecU8_as_str.h"
|
||||
//
|
||||
// U32 check_structure_h_dfs(const RBTreeNode* tree, U64 x, VecU8* f){
|
||||
// if (x == 0)
|
||||
// return 0;
|
||||
// if (*VecU8_at(f, x - 1) != 0)
|
||||
// check(false);
|
||||
// *VecU8_mat(f, x - 1) = 1;
|
||||
// U32 a = check_structure_h_dfs(tree, tree[x].left, f);
|
||||
// U32 b = check_structure_h_dfs(tree, tree[x].right, f);
|
||||
// check(a == b);
|
||||
// return a + (tree[x].color == RBTree_black ? 1 : 0);
|
||||
// }
|
||||
//
|
||||
// void check_correctness_ByStart(const BuffRBTreeByStart_SetU64Segment* self){
|
||||
// check(self->tree.len == self->el.len + 1);
|
||||
// check(self->root < self->tree.len);
|
||||
// if (self->tree.len > 1) {
|
||||
// check(self->root != 0);
|
||||
// }
|
||||
// VecU8 f = VecU8_new_zeroinit(self->tree.len - 1);
|
||||
// check_structure_h_dfs(self->tree.buf, self->root, &f);
|
||||
// for (size_t i = 0; i < self->tree.len - 1; i++) {
|
||||
// check(*VecU8_at(&f, i));
|
||||
// }
|
||||
// VecU8_drop(f); /* f invalidated */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (v == self->root) {
|
||||
// check(self->tree.buf[v].parent == 0);
|
||||
// } else {
|
||||
// check(self->tree.buf[v].parent != 0);
|
||||
// }
|
||||
// check(self->tree.buf[v].parent < self->tree.len);
|
||||
// check(self->tree.buf[v].left < self->tree.len);
|
||||
// check(self->tree.buf[v].right < self->tree.len);
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].parent == v);
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].right].parent == v);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* Checking coloring */
|
||||
// check(self->tree.buf[0].color == RBTree_black);
|
||||
// if (self->root != 0)
|
||||
// check(self->tree.buf[self->root].color == RBTree_black);
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].color == RBTree_red) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].color == RBTree_black);
|
||||
// check(self->tree.buf[self->tree.buf[v].right].color == RBTree_black);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* checking keys, but better */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(U64Segment_less_by_start(&self->el.buf[self->tree.buf[v].left - 1], &self->el.buf[v - 1]));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(U64Segment_less_by_start(&self->el.buf[v - 1], &self->el.buf[self->tree.buf[v].right - 1]));
|
||||
// }
|
||||
// }
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// size_t cur = self->tree.buf[v].left;
|
||||
// while (self->tree.buf[cur].right != 0)
|
||||
// cur = self->tree.buf[cur].right;
|
||||
// check(U64Segment_less_by_start(&self->el.buf[cur - 1], &self->el.buf[v - 1]));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// size_t cur = self->tree.buf[v].right;
|
||||
// while (self->tree.buf[cur].left != 0)
|
||||
// cur = self->tree.buf[cur].left;
|
||||
// check(U64Segment_less_by_start(&self->el.buf[v - 1], &self->el.buf[cur - 1]));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void stress_ByStart(){
|
||||
// printf("Prepare for some real stress\n");
|
||||
// for (int s = 2; s < 800; s++) {
|
||||
// srand(s);
|
||||
// BuffRBTreeByStart_SetU64Segment set = BuffRBTreeByStart_SetU64Segment_new();
|
||||
// VecU64Segment real_set = VecU64Segment_new();
|
||||
// U32 n = (U32)s;
|
||||
// VecU64Segment complementary_set = VecU64Segment_new_reserved(n);
|
||||
// for (size_t i = 0; i < n; i++) {
|
||||
// U64Segment value = {i, (U64)rand()};
|
||||
// VecU64Segment_append(&complementary_set, value);
|
||||
// }
|
||||
// for (int t = 0; t < 1000; t++) {
|
||||
// /* Do something */
|
||||
// int do_insertion = rand() % 2;
|
||||
// if (real_set.len == 0)
|
||||
// do_insertion = 1;
|
||||
// if (complementary_set.len == 0)
|
||||
// do_insertion = 0;
|
||||
// if (do_insertion) {
|
||||
// assert(complementary_set.len > 0);
|
||||
// size_t j = rand() % complementary_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&complementary_set, j);
|
||||
// VecU64Segment_append(&real_set, v);
|
||||
// check(BuffRBTreeByStart_SetU64Segment_insert(&set, v));
|
||||
// check_correctness_ByStart(&set);
|
||||
// } else {
|
||||
// assert(real_set.len > 0);
|
||||
// size_t j = rand() % real_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&real_set, j);
|
||||
// VecU64Segment_append(&complementary_set, v);
|
||||
// check(BuffRBTreeByStart_SetU64Segment_erase(&set, &v));
|
||||
// check_correctness_ByStart(&set);
|
||||
// }
|
||||
// /* We did something */
|
||||
// check(real_set.len == set.el.len);
|
||||
// for (size_t j = 0; j < real_set.len; j++) {
|
||||
// check(BuffRBTreeByStart_SetU64Segment_find(&set, &real_set.buf[j]) != 0);
|
||||
// check(BuffRBTreeByStart_SetU64Segment_at(&set, &real_set.buf[j]).variant == Option_Some);
|
||||
// }
|
||||
// for (size_t j = 0; j < complementary_set.len; j++) {
|
||||
// check(BuffRBTreeByStart_SetU64Segment_find(&set, &complementary_set.buf[j]) == 0);
|
||||
// check(BuffRBTreeByStart_SetU64Segment_at(&set, &complementary_set.buf[j]).variant == Option_None);
|
||||
// }
|
||||
// }
|
||||
// VecU64Segment_drop(real_set);
|
||||
// VecU64Segment_drop(complementary_set);
|
||||
// BuffRBTreeByStart_SetU64Segment_drop(set);
|
||||
// printf("Seed s=%d passed test\n", s);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void check_correctness_ByLen(const BuffRBTreeByLen_SetU64Segment* self){
|
||||
// check(self->tree.len == self->el.len + 1);
|
||||
// check(self->root < self->tree.len);
|
||||
// if (self->tree.len > 1) {
|
||||
// check(self->root != 0);
|
||||
// }
|
||||
// VecU8 f = VecU8_new_zeroinit(self->tree.len - 1);
|
||||
// check_structure_h_dfs(self->tree.buf, self->root, &f);
|
||||
// for (size_t i = 0; i < self->tree.len - 1; i++) {
|
||||
// check(*VecU8_at(&f, i));
|
||||
// }
|
||||
// VecU8_drop(f); /* f invalidated */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (v == self->root) {
|
||||
// check(self->tree.buf[v].parent == 0);
|
||||
// } else {
|
||||
// check(self->tree.buf[v].parent != 0);
|
||||
// }
|
||||
// check(self->tree.buf[v].parent < self->tree.len);
|
||||
// check(self->tree.buf[v].left < self->tree.len);
|
||||
// check(self->tree.buf[v].right < self->tree.len);
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].parent == v);
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].right].parent == v);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* Checking coloring */
|
||||
// check(self->tree.buf[0].color == RBTree_black);
|
||||
// if (self->root != 0)
|
||||
// check(self->tree.buf[self->root].color == RBTree_black);
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].color == RBTree_red) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].color == RBTree_black);
|
||||
// check(self->tree.buf[self->tree.buf[v].right].color == RBTree_black);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* checking keys, but better */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(U64Segment_less_by_len_and_start(&self->el.buf[self->tree.buf[v].left - 1], &self->el.buf[v - 1]));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(U64Segment_less_by_len_and_start(&self->el.buf[v - 1], &self->el.buf[self->tree.buf[v].right - 1]));
|
||||
// }
|
||||
// }
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// size_t cur = self->tree.buf[v].left;
|
||||
// while (self->tree.buf[cur].right != 0)
|
||||
// cur = self->tree.buf[cur].right;
|
||||
// check(U64Segment_less_by_len_and_start(&self->el.buf[cur - 1], &self->el.buf[v - 1]));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// size_t cur = self->tree.buf[v].right;
|
||||
// while (self->tree.buf[cur].left != 0)
|
||||
// cur = self->tree.buf[cur].left;
|
||||
// check(U64Segment_less_by_len_and_start(&self->el.buf[v - 1], &self->el.buf[cur - 1]));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void stress_ByLen(){
|
||||
// printf("Prepare for some real stress\n");
|
||||
// for (int s = 2; s < 400; s++) {
|
||||
// srand(s);
|
||||
// BuffRBTreeByLen_SetU64Segment set = BuffRBTreeByLen_SetU64Segment_new();
|
||||
// VecU64Segment real_set = VecU64Segment_new();
|
||||
// U32 n = (U32)s;
|
||||
// VecU64Segment complementary_set = VecU64Segment_new_reserved(n);
|
||||
// for (size_t i = 0; i < n; i++) {
|
||||
// U64Segment value = {i, (U64)rand()};
|
||||
// VecU64Segment_append(&complementary_set, value);
|
||||
// }
|
||||
// for (int t = 0; t < 1000; t++) {
|
||||
// /* Do something */
|
||||
// int do_insertion = rand() % 2;
|
||||
// if (real_set.len == 0)
|
||||
// do_insertion = 1;
|
||||
// if (complementary_set.len == 0)
|
||||
// do_insertion = 0;
|
||||
// if (do_insertion) {
|
||||
// assert(complementary_set.len > 0);
|
||||
// size_t j = rand() % complementary_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&complementary_set, j);
|
||||
// VecU64Segment_append(&real_set, v);
|
||||
// check(BuffRBTreeByLen_SetU64Segment_insert(&set, v));
|
||||
// check_correctness_ByLen(&set);
|
||||
// } else {
|
||||
// assert(real_set.len > 0);
|
||||
// size_t j = rand() % real_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&real_set, j);
|
||||
// VecU64Segment_append(&complementary_set, v);
|
||||
// check(BuffRBTreeByLen_SetU64Segment_erase(&set, &v));
|
||||
// check_correctness_ByLen(&set);
|
||||
// }
|
||||
// /* We did something */
|
||||
// check(real_set.len == set.el.len);
|
||||
// for (size_t j = 0; j < real_set.len; j++) {
|
||||
// check(BuffRBTreeByLen_SetU64Segment_find(&set, &real_set.buf[j]) != 0);
|
||||
// check(BuffRBTreeByLen_SetU64Segment_at(&set, &real_set.buf[j]).variant == Option_Some);
|
||||
// }
|
||||
// for (size_t j = 0; j < complementary_set.len; j++) {
|
||||
// check(BuffRBTreeByLen_SetU64Segment_find(&set, &complementary_set.buf[j]) == 0);
|
||||
// check(BuffRBTreeByLen_SetU64Segment_at(&set, &complementary_set.buf[j]).variant == Option_None);
|
||||
// }
|
||||
// }
|
||||
// VecU64Segment_drop(real_set);
|
||||
// VecU64Segment_drop(complementary_set);
|
||||
// BuffRBTreeByLen_SetU64Segment_drop(set);
|
||||
// printf("Seed s=%d passed test\n", s);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void check_correctness_ByLenRespAlign(const BuffRBTreeByLenRespAlign_SetU64Segment* self, U8 alignment_exp){
|
||||
// check(self->guest == alignment_exp)
|
||||
// check(self->tree.len == self->el.len + 1);
|
||||
// check(self->root < self->tree.len);
|
||||
// if (self->tree.len > 1) {
|
||||
// check(self->root != 0);
|
||||
// }
|
||||
// VecU8 f = VecU8_new_zeroinit(self->tree.len - 1);
|
||||
// check_structure_h_dfs(self->tree.buf, self->root, &f);
|
||||
// for (size_t i = 0; i < self->tree.len - 1; i++) {
|
||||
// check(*VecU8_at(&f, i));
|
||||
// }
|
||||
// VecU8_drop(f); /* f invalidated */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (v == self->root) {
|
||||
// check(self->tree.buf[v].parent == 0);
|
||||
// } else {
|
||||
// check(self->tree.buf[v].parent != 0);
|
||||
// }
|
||||
// check(self->tree.buf[v].parent < self->tree.len);
|
||||
// check(self->tree.buf[v].left < self->tree.len);
|
||||
// check(self->tree.buf[v].right < self->tree.len);
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].parent == v);
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(self->tree.buf[self->tree.buf[v].right].parent == v);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* Checking coloring */
|
||||
// check(self->tree.buf[0].color == RBTree_black);
|
||||
// if (self->root != 0)
|
||||
// check(self->tree.buf[self->root].color == RBTree_black);
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].color == RBTree_red) {
|
||||
// check(self->tree.buf[self->tree.buf[v].left].color == RBTree_black);
|
||||
// check(self->tree.buf[self->tree.buf[v].right].color == RBTree_black);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /* checking keys, but better */
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// check(U64Segment_less_by_len_and_start_resp_align(&self->el.buf[self->tree.buf[v].left - 1], &self->el.buf[v - 1], alignment_exp));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// check(U64Segment_less_by_len_and_start_resp_align(&self->el.buf[v - 1], &self->el.buf[self->tree.buf[v].right - 1], alignment_exp));
|
||||
// }
|
||||
// }
|
||||
// for (size_t v = 1; v < self->tree.len; v++) {
|
||||
// if (self->tree.buf[v].left != 0) {
|
||||
// size_t cur = self->tree.buf[v].left;
|
||||
// while (self->tree.buf[cur].right != 0)
|
||||
// cur = self->tree.buf[cur].right;
|
||||
// check(U64Segment_less_by_len_and_start_resp_align(&self->el.buf[cur - 1], &self->el.buf[v - 1], alignment_exp));
|
||||
// }
|
||||
// if (self->tree.buf[v].right != 0) {
|
||||
// size_t cur = self->tree.buf[v].right;
|
||||
// while (self->tree.buf[cur].left != 0)
|
||||
// cur = self->tree.buf[cur].left;
|
||||
// check(U64Segment_less_by_len_and_start_resp_align(&self->el.buf[v - 1], &self->el.buf[cur - 1], alignment_exp));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void stress_ByLenRespAlign(U8 alignment_exp){
|
||||
// printf("Prepare for some real stress\n");
|
||||
// for (int s = 2; s < 400; s++) {
|
||||
// srand(s + 232323);
|
||||
// BuffRBTreeByLenRespAlign_SetU64Segment set = BuffRBTreeByLenRespAlign_SetU64Segment_new(alignment_exp);
|
||||
// VecU64Segment real_set = VecU64Segment_new();
|
||||
// U32 n = (U32)s;
|
||||
// VecU64Segment complementary_set = VecU64Segment_new_reserved(n);
|
||||
// for (size_t i = 0; i < n; i++) {
|
||||
// U64Segment value = {i, (U64)rand()};
|
||||
// VecU64Segment_append(&complementary_set, value);
|
||||
// }
|
||||
// for (int t = 0; t < 1000; t++) {
|
||||
// /* Do something */
|
||||
// int do_insertion = rand() % 2;
|
||||
// if (real_set.len == 0)
|
||||
// do_insertion = 1;
|
||||
// if (complementary_set.len == 0)
|
||||
// do_insertion = 0;
|
||||
// if (do_insertion) {
|
||||
// assert(complementary_set.len > 0);
|
||||
// size_t j = rand() % complementary_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&complementary_set, j);
|
||||
// VecU64Segment_append(&real_set, v);
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_insert(&set, v));
|
||||
// check_correctness_ByLenRespAlign(&set, alignment_exp);
|
||||
// } else {
|
||||
// assert(real_set.len > 0);
|
||||
// size_t j = rand() % real_set.len;
|
||||
// U64Segment v = VecU64Segment_unordered_pop(&real_set, j);
|
||||
// VecU64Segment_append(&complementary_set, v);
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_erase(&set, &v));
|
||||
// check_correctness_ByLenRespAlign(&set, alignment_exp);
|
||||
// }
|
||||
// /* We did something */
|
||||
// check(real_set.len == set.el.len);
|
||||
// for (size_t j = 0; j < real_set.len; j++) {
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_find(&set, &real_set.buf[j]) != 0);
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_at(&set, &real_set.buf[j]).variant == Option_Some);
|
||||
// }
|
||||
// for (size_t j = 0; j < complementary_set.len; j++) {
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_find(&set, &complementary_set.buf[j]) == 0);
|
||||
// check(BuffRBTreeByLenRespAlign_SetU64Segment_at(&set, &complementary_set.buf[j]).variant == Option_None);
|
||||
// }
|
||||
// }
|
||||
// VecU64Segment_drop(real_set);
|
||||
// VecU64Segment_drop(complementary_set);
|
||||
// BuffRBTreeByLenRespAlign_SetU64Segment_drop(set);
|
||||
// printf("Seed s=%d passed test\n", s);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int main(){
|
||||
// stress_ByStart();
|
||||
// stress_ByLen();
|
||||
// stress_ByLenRespAlign(0); // 1
|
||||
// stress_ByLenRespAlign(3); // 8
|
||||
// stress_ByLenRespAlign(10); // 1024
|
||||
// stress_ByLenRespAlign(12); // 4096
|
||||
// return 0;
|
||||
// }
|
||||
@ -1,360 +0,0 @@
|
||||
#include "../../../../gen/l1_5/RBTree_SetS64.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_U8.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_S64.h"
|
||||
#include "../../../../gen/l1/OptionS64.h"
|
||||
|
||||
#include "../../../l1/core/VecU8_as_str.h"
|
||||
#include "../../../l1/system/fileio.h"
|
||||
#include "../../../l1/system/fsmanip.h"
|
||||
#include "../../../l1/system/creating_child_proc.h"
|
||||
|
||||
typedef RBTreeNode_S64* RefRBTreeNode_S64;
|
||||
|
||||
#include "../../../../gen/l1/eve/ds_test/VecRefRBTreeNode_S64.h"
|
||||
|
||||
S64 min_key_in_subtree(RBTreeNode_S64* x, RBTreeNode* NIL){
|
||||
check(x != NULL && &x->base != NIL);
|
||||
S64 ans = x->key;
|
||||
if (x->base.left != NIL)
|
||||
ans = MIN_S64(ans, min_key_in_subtree((RBTreeNode_S64*)x->base.left, NIL));
|
||||
if (x->base.right != NIL)
|
||||
ans = MIN_S64(ans, min_key_in_subtree((RBTreeNode_S64*)x->base.right, NIL));
|
||||
return ans;
|
||||
}
|
||||
|
||||
S64 max_key_in_subtree(RBTreeNode_S64* x, RBTreeNode* NIL){
|
||||
check(x != NULL && &x->base != NIL);
|
||||
S64 ans = x->key;
|
||||
if (x->base.left != NIL)
|
||||
ans = MAX_S64(ans, max_key_in_subtree((RBTreeNode_S64*)x->base.left, NIL));
|
||||
if (x->base.right != NIL)
|
||||
ans = MAX_S64(ans, max_key_in_subtree((RBTreeNode_S64*)x->base.right, NIL));
|
||||
return ans;
|
||||
}
|
||||
|
||||
int check_structure_h_dfs(RBTree_SetS64* set, RBTreeNode_S64* x){
|
||||
check(x != NULL);
|
||||
if (&x->base == set->NIL)
|
||||
return 0;
|
||||
int a = x->base.left == set->NIL ? 0 : check_structure_h_dfs(set, (RBTreeNode_S64*)x->base.left);
|
||||
int b = x->base.right == set->NIL ? 0 : check_structure_h_dfs(set, (RBTreeNode_S64*)x->base.right);
|
||||
check(a == b);
|
||||
if (&x->base == set->root) {
|
||||
check(x->base.parent == set->NIL);
|
||||
} else {
|
||||
check(x->base.parent != set->NIL);
|
||||
}
|
||||
if (x->base.left != set->NIL)
|
||||
check(x->base.left->parent == &x->base);
|
||||
if (x->base.right != set->NIL)
|
||||
check(x->base.right->parent == &x->base);
|
||||
|
||||
if (x->base.left != set->NIL)
|
||||
check(max_key_in_subtree((RBTreeNode_S64*)x->base.left, set->NIL) < x->key);
|
||||
if (x->base.right != set->NIL)
|
||||
check(x->key < min_key_in_subtree((RBTreeNode_S64*)x->base.right, set->NIL));
|
||||
|
||||
if (x->base.color == RBTREE_RED) {
|
||||
check(x->base.left->color == RBTREE_BLACK);
|
||||
check(x->base.right->color == RBTREE_BLACK);
|
||||
}
|
||||
|
||||
return a + (x->base.color == RBTREE_BLACK ? 1 : 0);
|
||||
}
|
||||
|
||||
void check_correctness(RBTree_SetS64* set){
|
||||
check(set->root->color == RBTREE_BLACK);
|
||||
check_structure_h_dfs(set, (RBTreeNode_S64*)set->root);
|
||||
}
|
||||
|
||||
|
||||
void save_tree_to_file(const RBTree_SetS64* set, SpanU8 name){
|
||||
// check_only_structure(set);
|
||||
|
||||
VecU8 graph = vcstr(
|
||||
"digraph rbtree {\n"
|
||||
" fontsize = 20\n"
|
||||
" rankdir = TB\n"
|
||||
" bgcolor = \"lightgray\"\n"
|
||||
" node [fontname = \"Arial\", style=\"rounded,filled\", shape=circle];\n\n");
|
||||
|
||||
VecRefRBTreeNode_S64 bfs_nxt = VecRefRBTreeNode_S64_new();
|
||||
VecRefRBTreeNode_S64 bfs = VecRefRBTreeNode_S64_new();
|
||||
if (set->root != set->NIL) {
|
||||
check(set->root->parent == set->NIL);
|
||||
VecRefRBTreeNode_S64_append(&bfs_nxt, (RBTreeNode_S64*)set->root);
|
||||
}
|
||||
while (bfs_nxt.len > 0) {
|
||||
VecRefRBTreeNode_S64 t = bfs_nxt;
|
||||
bfs_nxt = bfs;
|
||||
bfs = t;
|
||||
for (size_t j = 0; j < bfs.len; j++) {
|
||||
RBTreeNode_S64* cur = *VecRefRBTreeNode_S64_at(&bfs, j);
|
||||
assert(cur != NULL);
|
||||
if (cur->base.left != set->NIL) {
|
||||
check(cur->base.left->parent == &cur->base);
|
||||
VecRefRBTreeNode_S64_append(&bfs, (RBTreeNode_S64*)cur->base.left);
|
||||
}
|
||||
|
||||
if (cur->base.right != set->NIL) {
|
||||
check(cur->base.right->parent == &cur->base);
|
||||
VecRefRBTreeNode_S64_append(&bfs, (RBTreeNode_S64*)cur->base.right);
|
||||
}
|
||||
|
||||
VecU8_append_vec(&graph, VecU8_fmt(
|
||||
" v%i [label=%i, color=%s, fontcolor=%s]\n",
|
||||
cur->key, cur->key,
|
||||
cur->base.color == RBTREE_BLACK ? cstr("black") : cstr("red"),
|
||||
cur->base.color == RBTREE_BLACK ? cstr("white") : cstr("black")));
|
||||
|
||||
if (cur->base.left != set->NIL)
|
||||
VecU8_append_vec(&graph, VecU8_fmt(" v%i -> v%i [label=left]\n",
|
||||
cur->key, ((RBTreeNode_S64*)cur->base.left)->key));
|
||||
if (cur->base.right != set->NIL)
|
||||
VecU8_append_vec(&graph, VecU8_fmt(" v%i -> v%i [label=right]\n",
|
||||
cur->key, ((RBTreeNode_S64*)cur->base.right)->key));
|
||||
}
|
||||
bfs.len = 0;
|
||||
}
|
||||
VecU8_append_span(&graph, cstr("}\n"));
|
||||
mkdir_nofail("GRAPHS");
|
||||
write_file_by_path(VecU8_fmt("GRAPHS/GRAPH_%s.gv", name), VecU8_to_span(&graph));
|
||||
VecU8_drop(graph);
|
||||
VecU8 command_nt = VecU8_fmt("dot -Tpng GRAPHS/GRAPH_%s.gv -o GRAPHS/GRAPH_%s.png%c", name, name, 0);
|
||||
calling_system_func_nofail((CSTR)command_nt.buf);
|
||||
VecU8_drop(command_nt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void insert_only(){
|
||||
{
|
||||
RBTree_SetS64 set = RBTree_SetS64_new();
|
||||
check_correctness(&set);
|
||||
RBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
RBTree_SetS64 set = RBTree_SetS64_new();
|
||||
for (S64 p = 0; p < 100; p++) {
|
||||
bool ret = RBTree_SetS64_insert(&set, 2 * p);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
// save_tree_to_file(&set, cstr("last_correct"));
|
||||
for (S64 i = 0; i <= p; i++) {
|
||||
RBTreeNode_S64* ret1 = RBTree_SetS64_find(&set, 2 * i);
|
||||
check(ret1 != NULL);
|
||||
RBTreeNode_S64* ret2 = RBTree_SetS64_find(&set, 2 * i + 1);
|
||||
check(ret2 == NULL);
|
||||
}
|
||||
}
|
||||
RBTree_SetS64_drop(set);
|
||||
}
|
||||
{
|
||||
RBTree_SetS64 set = RBTree_SetS64_new();
|
||||
for (S64 p = -99; p <= 0; p++) {
|
||||
bool ret = RBTree_SetS64_insert(&set, 2 * p);
|
||||
check(ret);
|
||||
check_correctness(&set);
|
||||
// save_tree_to_file(&set, cstr("last_correct"));
|
||||
for (S64 i = -99; i <= p; i++) {
|
||||
RBTreeNode_S64* ret1 = RBTree_SetS64_find(&set, 2 * i);
|
||||
check(ret1 != NULL);
|
||||
RBTreeNode_S64* ret2 = RBTree_SetS64_find(&set, 2 * i + 1);
|
||||
check(ret2 == NULL);
|
||||
}
|
||||
}
|
||||
RBTree_SetS64_drop(set);
|
||||
}
|
||||
for (int s = 0; s < 1000; s++) {
|
||||
srand(s);
|
||||
VecS64 have = VecS64_new();
|
||||
RBTree_SetS64 set = RBTree_SetS64_new();
|
||||
for (int m = 0; m < 1000; m++) {
|
||||
S64 x = (S64)rand();
|
||||
bool in = false;
|
||||
for (size_t j = 0; j < have.len; j++) {
|
||||
if (have.buf[j] == x)
|
||||
in = true;
|
||||
}
|
||||
bool iret = RBTree_SetS64_insert(&set, x);
|
||||
if (in) {
|
||||
check(!iret);
|
||||
} else {
|
||||
check(iret);
|
||||
VecS64_append(&have, x);
|
||||
}
|
||||
}
|
||||
RBTree_SetS64_drop(set);
|
||||
VecS64_drop(have);
|
||||
}
|
||||
}
|
||||
|
||||
void s_4_t_42(){
|
||||
RBTreeNode_S64* v0 = safe_malloc(sizeof(RBTreeNode_S64));
|
||||
RBTreeNode_S64* v10 = safe_malloc(sizeof(RBTreeNode_S64));
|
||||
RBTreeNode_S64* v20 = safe_malloc(sizeof(RBTreeNode_S64));
|
||||
RBTreeNode_S64* v30 = safe_malloc(sizeof(RBTreeNode_S64));
|
||||
RBTreeNode* NIL = safe_calloc(1, sizeof(RBTreeNode));
|
||||
*v0 = (RBTreeNode_S64){ .base.parent = &v20->base, .base.left = NIL, .base.right = &v10->base,
|
||||
.base.color = RBTREE_BLACK, .key = 0};
|
||||
*v10 = (RBTreeNode_S64){ .base.parent = &v0->base, .base.left = NIL, .base.right = NIL,
|
||||
.base.color = RBTREE_RED, .key = 10};
|
||||
*v20 = (RBTreeNode_S64){ .base.parent = NIL, .base.left = &v0->base, .base.right = &v30->base,
|
||||
.base.color = RBTREE_BLACK, .key = 20};
|
||||
*v30 = (RBTreeNode_S64){ .base.parent = &v20->base, .base.left = NIL, .base.right = NIL,
|
||||
.base.color = RBTREE_BLACK, .key = 30};
|
||||
RBTree_SetS64 set = {.root = &v20->base, .NIL = NIL};
|
||||
check_correctness(&set);
|
||||
// save_tree_to_file(&set, cstr("SOROK_ONE"));
|
||||
check(RBTree_SetS64_erase(&set, 20));
|
||||
// save_tree_to_file(&set, cstr("I_AM_LOOSING_MY_MIND"));
|
||||
check_correctness(&set);
|
||||
RBTree_SetS64_drop(set);
|
||||
}
|
||||
|
||||
OptionS64 VecS64_find_max_less(const VecS64* set, S64 key){
|
||||
OptionS64 max_less = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] < key)
|
||||
if (max_less.variant == Option_None || max_less.some < set->buf[i])
|
||||
max_less = Some_S64(set->buf[i]);
|
||||
return max_less;
|
||||
}
|
||||
|
||||
OptionS64 VecS64_find_max_less_or_eq(const VecS64* set, S64 key){
|
||||
OptionS64 max_less = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] <= key)
|
||||
if (max_less.variant == Option_None || max_less.some < set->buf[i])
|
||||
max_less = Some_S64(set->buf[i]);
|
||||
return max_less;
|
||||
}
|
||||
|
||||
|
||||
OptionS64 VecS64_find_min_grtr(const VecS64* set, S64 key){
|
||||
OptionS64 min_grtr = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] > key)
|
||||
if (min_grtr.variant == Option_None || min_grtr.some > set->buf[i])
|
||||
min_grtr = Some_S64(set->buf[i]);
|
||||
return min_grtr;
|
||||
}
|
||||
|
||||
|
||||
OptionS64 VecS64_find_min_grtr_or_eq(const VecS64* set, S64 key){
|
||||
OptionS64 min_grtr = None_S64();
|
||||
for (size_t i = 0; i < set->len; i++)
|
||||
if (set->buf[i] >= key)
|
||||
if (min_grtr.variant == Option_None || min_grtr.some > set->buf[i])
|
||||
min_grtr = Some_S64(set->buf[i]);
|
||||
return min_grtr;
|
||||
}
|
||||
|
||||
void check_option_int_equiv_node(OptionS64 true_ans, RBTreeNode_S64* my_ans){
|
||||
if (true_ans.variant == Option_None) {
|
||||
check(my_ans == NULL);
|
||||
} else {
|
||||
check(my_ans != NULL && my_ans->key == true_ans.some);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stress(){
|
||||
printf("Are you ready for real stress?\n");
|
||||
for (int s = 2; s < 1000; s++) {
|
||||
srand(s);
|
||||
RBTree_SetS64 set = RBTree_SetS64_new();
|
||||
VecS64 real_set = VecS64_new();
|
||||
U32 n = (U32)s;
|
||||
VecS64 complementary_set = VecS64_new_reserved(n);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
VecS64_append(&complementary_set, (S64)i * 10);
|
||||
}
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
/* Do something */
|
||||
bool do_insertion = (rand() % 9) >= 4;
|
||||
if (real_set.len == 0)
|
||||
do_insertion = 1;
|
||||
if (complementary_set.len == 0)
|
||||
do_insertion = 0;
|
||||
if (do_insertion) {
|
||||
assert(complementary_set.len > 0);
|
||||
size_t j = rand() % complementary_set.len;
|
||||
S64 v = VecS64_unordered_pop(&complementary_set, j);
|
||||
VecS64_append(&real_set, v);
|
||||
check(RBTree_SetS64_insert(&set, v));
|
||||
check_correctness(&set);
|
||||
} else {
|
||||
assert(real_set.len > 0);
|
||||
size_t j = rand() % real_set.len;
|
||||
S64 v = VecS64_unordered_pop(&real_set, j);
|
||||
VecS64_append(&complementary_set, v);
|
||||
check(RBTree_SetS64_erase(&set, v));
|
||||
check_correctness(&set);
|
||||
}
|
||||
// VecU8 name = VecU8_fmt("t_%u", (U64)t);
|
||||
// save_tree_to_file(&set, VecU8_to_span(&name));
|
||||
/* We did something */
|
||||
for (size_t j = 0; j < real_set.len; j++) {
|
||||
check(RBTree_SetS64_find(&set, real_set.buf[j]) != NULL);
|
||||
}
|
||||
for (size_t j = 0; j < complementary_set.len; j++) {
|
||||
check(RBTree_SetS64_find(&set, complementary_set.buf[j]) == NULL);
|
||||
}
|
||||
|
||||
{ /* Tree detour forward */
|
||||
U64 count = 0;
|
||||
RBTreeNode_S64* cur = RBTree_SetS64_find_min(&set);
|
||||
while (cur) {
|
||||
count++;
|
||||
cur = RBTree_SetS64_find_next(&set, cur);
|
||||
}
|
||||
check(count == real_set.len);
|
||||
}
|
||||
{ /* Tree detour backward */
|
||||
U64 count = 0;
|
||||
RBTreeNode_S64* cur = RBTree_SetS64_find_max(&set);
|
||||
while (cur) {
|
||||
count++;
|
||||
cur = RBTree_SetS64_find_prev(&set, cur);
|
||||
}
|
||||
check(count == real_set.len);
|
||||
}
|
||||
/* Checking weird methods that nobody needs */
|
||||
for (int tt = 0; tt < 15; tt++) {
|
||||
S64 key = (S64)(rand() % n) * 10;
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_max_less(&real_set, key);
|
||||
RBTreeNode_S64* my_ans = RBTree_SetS64_find_max_less(&set, key);
|
||||
check_option_int_equiv_node(true_ans, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_max_less_or_eq(&real_set, key);
|
||||
RBTreeNode_S64* my_ans = RBTree_SetS64_find_max_less_or_eq(&set, key);
|
||||
check_option_int_equiv_node(true_ans, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_min_grtr(&real_set, key);
|
||||
RBTreeNode_S64* my_ans = RBTree_SetS64_find_min_grtr(&set, key);
|
||||
check_option_int_equiv_node(true_ans, my_ans);
|
||||
}
|
||||
{
|
||||
OptionS64 true_ans = VecS64_find_min_grtr_or_eq(&real_set, key);
|
||||
RBTreeNode_S64* my_ans = RBTree_SetS64_find_min_grtr_or_eq(&set, key);
|
||||
check_option_int_equiv_node(true_ans, my_ans);
|
||||
}
|
||||
}
|
||||
}
|
||||
VecS64_drop(real_set);
|
||||
VecS64_drop(complementary_set);
|
||||
RBTree_SetS64_drop(set);
|
||||
printf("Seed s=%d passed test\n", s);
|
||||
}
|
||||
}
|
||||
|
||||
int main(){
|
||||
insert_only();
|
||||
stress();
|
||||
s_4_t_42();
|
||||
return 0;
|
||||
}
|
||||
@ -1,93 +0,0 @@
|
||||
#include "../../../l1_5/core/stringsearch.h"
|
||||
|
||||
void VecU64_fprint_debug_vivod(FILE* file, const VecU64* vec){
|
||||
for (size_t i = 0; i < vec->len; i++) {
|
||||
fprintf(file, "%lu ", vec->buf[i]);
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
VecU64 trivial_prefix_function(SpanU8 s){
|
||||
VecU64 prefix = VecU64_new_zeroinit(s.len + 1);
|
||||
for (size_t i = 0; i <= s.len; i++) {
|
||||
for (size_t k = 0; k < i; k++) {
|
||||
for (size_t j = 0; j < k; j++) {
|
||||
if (s.data[j] != s.data[i - k + j])
|
||||
goto cnt;
|
||||
}
|
||||
prefix.buf[i] = k;
|
||||
cnt:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
VecU64 trivial_z_function(SpanU8 s){
|
||||
VecU64 z = VecU64_new_zeroinit(s.len + 1);
|
||||
for (size_t i = 0; i <= s.len; i++) {
|
||||
for (size_t j = 0; i + j < s.len; j++) {
|
||||
if (s.data[j] != s.data[i + j])
|
||||
break;
|
||||
z.buf[i]++;
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
void test_prefix_function(SpanU8 str){
|
||||
VecU64 correct = trivial_prefix_function(str);
|
||||
VecU64 my = prefix_function(str);
|
||||
if (!VecU64_equal_VecU64(&correct, &my)) {
|
||||
fprintf(stderr, "Test Pi ");
|
||||
SpanU8_fprint(str, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Correct: ");
|
||||
VecU64_fprint_debug_vivod(stderr, &correct);
|
||||
fprintf(stderr, "My: ");
|
||||
VecU64_fprint_debug_vivod(stderr, &my);
|
||||
abort();
|
||||
}
|
||||
VecU64_drop(correct);
|
||||
VecU64_drop(my);
|
||||
}
|
||||
|
||||
void test_z_function(SpanU8 str){
|
||||
VecU64 correct = trivial_z_function(str);
|
||||
VecU64 my = z_function(str);
|
||||
if (!VecU64_equal_VecU64(&correct, &my)) {
|
||||
fprintf(stderr, "Test Z ");
|
||||
SpanU8_fprint(str, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Correct: ");
|
||||
VecU64_fprint_debug_vivod(stderr, &correct);
|
||||
fprintf(stderr, "My: ");
|
||||
VecU64_fprint_debug_vivod(stderr, &my);
|
||||
abort();
|
||||
}
|
||||
VecU64_drop(correct);
|
||||
VecU64_drop(my);
|
||||
}
|
||||
|
||||
int main(){
|
||||
test_prefix_function(cstr(""));
|
||||
test_prefix_function(cstr("a"));
|
||||
test_prefix_function(cstr("ab"));
|
||||
test_prefix_function(cstr("aaaa"));
|
||||
test_prefix_function(cstr("aabbaabxxxaabbaab"));
|
||||
|
||||
test_z_function(cstr(""));
|
||||
test_z_function(cstr("a"));
|
||||
test_z_function(cstr("aa"));
|
||||
test_z_function(cstr("aaa"));
|
||||
test_z_function(cstr("aaaa"));
|
||||
test_z_function(cstr("ab"));
|
||||
test_z_function(cstr("aba"));
|
||||
test_z_function(cstr("bbaa"));
|
||||
test_z_function(cstr("abacad"));
|
||||
|
||||
test_prefix_function(cstr("hsooihoioifodoiwoihoiodisifoioihhhshshsshsoodfojoioow"));
|
||||
test_z_function(cstr("kdfkjpkjpksdpsdkpfpkspksfpksdpjpsdpdfjpospsdjpsdpfpspsf"));
|
||||
test_prefix_function(cstr("alkalaalkalakalkalakklakalalkalaakllaklakka"));
|
||||
test_z_function(cstr("alkalaalkalakalkalakklakalalkalaakllaklakka"));
|
||||
}
|
||||
@ -1,369 +0,0 @@
|
||||
#include "../../../l1/core/util.h"
|
||||
|
||||
typedef U64 VkDeviceSize;
|
||||
#define VK_NULL_HANDLE NULL
|
||||
typedef int VkResult;
|
||||
|
||||
const VkResult VK_SUCCESS = 120;
|
||||
const VkResult VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR = -2;
|
||||
|
||||
typedef int VkStructureType;
|
||||
|
||||
const VkStructureType VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 100;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 200;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 3000;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 645484;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES = 14542;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 145;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 5324;
|
||||
const VkStructureType VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 986;
|
||||
|
||||
|
||||
typedef int VkBufferCreateFlags;
|
||||
typedef int VkBufferUsageFlags;
|
||||
typedef int VkSharingMode;
|
||||
|
||||
const VkSharingMode VK_SHARING_MODE_EXCLUSIVE = 12;
|
||||
|
||||
|
||||
typedef void* VkPhysicalDevice;
|
||||
typedef void* VkDevice;
|
||||
typedef void* VkBuffer;
|
||||
typedef void* VkImage;
|
||||
typedef void* VkDeviceMemory;
|
||||
typedef void* VkCommandBuffer;
|
||||
|
||||
typedef struct {
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkBufferCreateFlags flags;
|
||||
VkDeviceSize size;
|
||||
VkBufferUsageFlags usage;
|
||||
VkSharingMode sharingMode;
|
||||
uint32_t queueFamilyIndexCount;
|
||||
const uint32_t* pQueueFamilyIndices;
|
||||
} VkBufferCreateInfo;
|
||||
|
||||
typedef int VkMemoryPropertyFlags;
|
||||
|
||||
const VkMemoryPropertyFlags VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x1000;
|
||||
|
||||
typedef struct {
|
||||
VkMemoryPropertyFlags propertyFlags;
|
||||
// ...
|
||||
} VkMemoryType;
|
||||
|
||||
#define VK_MAX_MEMORY_TYPES 32
|
||||
|
||||
typedef struct {
|
||||
uint32_t memoryTypeCount;
|
||||
VkMemoryType memoryTypes[VK_MAX_MEMORY_TYPES];
|
||||
// ...
|
||||
} VkPhysicalDeviceMemoryProperties;
|
||||
|
||||
void vkGetPhysicalDeviceMemoryProperties(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
VkPhysicalDeviceMemoryProperties* pMemoryProperties);
|
||||
|
||||
typedef void VkAllocationCallbacks;
|
||||
|
||||
VkResult vkCreateBuffer(
|
||||
VkDevice device,
|
||||
const VkBufferCreateInfo* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkBuffer* pBuffer);
|
||||
|
||||
typedef struct {
|
||||
VkDeviceSize size;
|
||||
VkDeviceSize alignment;
|
||||
uint32_t memoryTypeBits;
|
||||
} VkMemoryRequirements;
|
||||
|
||||
void vkGetBufferMemoryRequirements(
|
||||
VkDevice device,
|
||||
VkBuffer buffer,
|
||||
VkMemoryRequirements* pMemoryRequirements);
|
||||
|
||||
typedef int VkImageCreateFlags;
|
||||
typedef int VkImageType;
|
||||
|
||||
const VkImageType VK_IMAGE_TYPE_2D = 1232;
|
||||
|
||||
typedef int VkFormat;
|
||||
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t depth;
|
||||
} VkExtent3D;
|
||||
|
||||
typedef int VkSampleCountFlagBits;
|
||||
|
||||
const VkSampleCountFlagBits VK_SAMPLE_COUNT_1_BIT = 0x100;
|
||||
|
||||
typedef int VkImageTiling;
|
||||
|
||||
const VkImageTiling VK_IMAGE_TILING_OPTIMAL = 13115;
|
||||
const VkImageTiling VK_IMAGE_TILING_LINEAR = 9874;
|
||||
|
||||
typedef int VkImageUsageFlags;
|
||||
typedef int VkImageLayout;
|
||||
|
||||
const VkImageLayout VK_IMAGE_LAYOUT_UNDEFINED = 780;
|
||||
const VkImageLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 56637;
|
||||
const VkImageLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 56622;
|
||||
|
||||
typedef struct {
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkImageCreateFlags flags;
|
||||
VkImageType imageType;
|
||||
VkFormat format;
|
||||
VkExtent3D extent;
|
||||
uint32_t mipLevels;
|
||||
uint32_t arrayLayers;
|
||||
VkSampleCountFlagBits samples;
|
||||
VkImageTiling tiling;
|
||||
VkImageUsageFlags usage;
|
||||
VkSharingMode sharingMode;
|
||||
uint32_t queueFamilyIndexCount;
|
||||
const uint32_t* pQueueFamilyIndices;
|
||||
VkImageLayout initialLayout;
|
||||
} VkImageCreateInfo;
|
||||
|
||||
VkResult vkCreateImage(
|
||||
VkDevice device,
|
||||
const VkImageCreateInfo* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkImage* pImage);
|
||||
|
||||
void vkGetImageMemoryRequirements(
|
||||
VkDevice device,
|
||||
VkImage image,
|
||||
VkMemoryRequirements* pMemoryRequirements);
|
||||
|
||||
typedef struct {
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkDeviceSize allocationSize;
|
||||
uint32_t memoryTypeIndex;
|
||||
} VkMemoryAllocateInfo;
|
||||
|
||||
VkResult vkAllocateMemory(
|
||||
VkDevice device,
|
||||
const VkMemoryAllocateInfo* pAllocateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkDeviceMemory* pMemory);
|
||||
|
||||
VkResult vkBindBufferMemory(
|
||||
VkDevice device,
|
||||
VkBuffer buffer,
|
||||
VkDeviceMemory memory,
|
||||
VkDeviceSize memoryOffset);
|
||||
|
||||
VkResult vkBindImageMemory(
|
||||
VkDevice device,
|
||||
VkImage image,
|
||||
VkDeviceMemory memory,
|
||||
VkDeviceSize memoryOffset);
|
||||
|
||||
void vkDestroyBuffer(
|
||||
VkDevice device,
|
||||
VkBuffer buffer,
|
||||
const VkAllocationCallbacks* pAllocator);
|
||||
|
||||
void vkDestroyImage(
|
||||
VkDevice device,
|
||||
VkImage image,
|
||||
const VkAllocationCallbacks* pAllocator);
|
||||
|
||||
typedef int VkMemoryMapFlags;
|
||||
|
||||
#define VK_WHOLE_SIZE (~0ULL)
|
||||
|
||||
VkResult vkMapMemory(
|
||||
VkDevice device,
|
||||
VkDeviceMemory memory,
|
||||
VkDeviceSize offset,
|
||||
VkDeviceSize size,
|
||||
VkMemoryMapFlags flags,
|
||||
void** ppData);
|
||||
|
||||
void vkUnmapMemory(
|
||||
VkDevice device,
|
||||
VkDeviceMemory memory);
|
||||
|
||||
void vkFreeMemory(
|
||||
VkDevice device,
|
||||
VkDeviceMemory memory,
|
||||
const VkAllocationCallbacks* pAllocator);
|
||||
|
||||
typedef struct VkPhysicalDeviceLimits {
|
||||
/* ... */
|
||||
uint32_t maxMemoryAllocationCount;
|
||||
/* ... */
|
||||
} VkPhysicalDeviceLimits;
|
||||
|
||||
typedef struct VkPhysicalDeviceProperties {
|
||||
/* ... */
|
||||
VkPhysicalDeviceLimits limits;
|
||||
/* ... */
|
||||
} VkPhysicalDeviceProperties;
|
||||
|
||||
typedef struct VkPhysicalDeviceMaintenance4Properties {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
VkDeviceSize maxBufferSize;
|
||||
} VkPhysicalDeviceMaintenance4Properties;
|
||||
|
||||
typedef struct VkPhysicalDeviceMaintenance3Properties {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
/* ... */
|
||||
VkDeviceSize maxMemoryAllocationSize;
|
||||
} VkPhysicalDeviceMaintenance3Properties;
|
||||
|
||||
typedef struct VkPhysicalDeviceProperties2 {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
VkPhysicalDeviceProperties properties;
|
||||
} VkPhysicalDeviceProperties2;
|
||||
|
||||
void vkGetPhysicalDeviceProperties2(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
VkPhysicalDeviceProperties2* pProperties);
|
||||
|
||||
typedef int VkCommandBufferResetFlags;
|
||||
|
||||
VkResult vkResetCommandBuffer(
|
||||
VkCommandBuffer commandBuffer,
|
||||
VkCommandBufferResetFlags flags);
|
||||
|
||||
typedef int VkCommandBufferUsageFlags;
|
||||
|
||||
typedef struct VkCommandBufferBeginInfo {
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkCommandBufferUsageFlags flags;
|
||||
const void* pInheritanceInfo; /* will be NULL */
|
||||
} VkCommandBufferBeginInfo;
|
||||
|
||||
VkResult vkBeginCommandBuffer(
|
||||
VkCommandBuffer commandBuffer,
|
||||
const VkCommandBufferBeginInfo* pBeginInfo);
|
||||
|
||||
typedef int VkAccessFlags;
|
||||
const VkAccessFlags VK_ACCESS_TRANSFER_READ_BIT = 0x100;
|
||||
const VkAccessFlags VK_ACCESS_TRANSFER_WRITE_BIT = 0x100000;
|
||||
|
||||
typedef int VkImageAspectFlags;
|
||||
const VkImageAspectFlags VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001;
|
||||
|
||||
typedef struct VkImageSubresourceRange {
|
||||
VkImageAspectFlags aspectMask;
|
||||
uint32_t baseMipLevel;
|
||||
uint32_t levelCount;
|
||||
uint32_t baseArrayLayer;
|
||||
uint32_t layerCount;
|
||||
} VkImageSubresourceRange;
|
||||
|
||||
const uint32_t VK_QUEUE_FAMILY_IGNORED = (~0U);
|
||||
|
||||
typedef struct VkImageMemoryBarrier {
|
||||
VkStructureType sType;
|
||||
const void* pNext;
|
||||
VkAccessFlags srcAccessMask;
|
||||
VkAccessFlags dstAccessMask;
|
||||
VkImageLayout oldLayout;
|
||||
VkImageLayout newLayout;
|
||||
uint32_t srcQueueFamilyIndex;
|
||||
uint32_t dstQueueFamilyIndex;
|
||||
VkImage image;
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
} VkImageMemoryBarrier;
|
||||
|
||||
typedef int VkPipelineStageFlags;
|
||||
const VkPipelineStageFlags VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x1;
|
||||
const VkPipelineStageFlags VK_PIPELINE_STAGE_TRANSFER_BIT = 0x2;
|
||||
|
||||
typedef int VkDependencyFlags;
|
||||
|
||||
void vkCmdPipelineBarrier(
|
||||
VkCommandBuffer commandBuffer,
|
||||
VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask,
|
||||
VkDependencyFlags dependencyFlags,
|
||||
uint32_t memoryBarrierCount,
|
||||
const void* /* VkMemoryBarrier */ pMemoryBarriers,
|
||||
uint32_t bufferMemoryBarrierCount,
|
||||
const void* /* VkBufferMemoryBarrier */ pBufferMemoryBarriers,
|
||||
uint32_t imageMemoryBarrierCount,
|
||||
const VkImageMemoryBarrier* pImageMemoryBarriers);
|
||||
|
||||
typedef struct VkImageSubresourceLayers {
|
||||
VkImageAspectFlags aspectMask;
|
||||
uint32_t mipLevel;
|
||||
uint32_t baseArrayLayer;
|
||||
uint32_t layerCount;
|
||||
} VkImageSubresourceLayers;
|
||||
|
||||
typedef struct VkOffset3D {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t z;
|
||||
} VkOffset3D;
|
||||
|
||||
typedef struct VkBufferImageCopy {
|
||||
VkDeviceSize bufferOffset;
|
||||
uint32_t bufferRowLength;
|
||||
uint32_t bufferImageHeight;
|
||||
VkImageSubresourceLayers imageSubresource;
|
||||
VkOffset3D imageOffset;
|
||||
VkExtent3D imageExtent;
|
||||
} VkBufferImageCopy;
|
||||
|
||||
void vkCmdCopyBufferToImage(
|
||||
VkCommandBuffer commandBuffer,
|
||||
VkBuffer srcBuffer,
|
||||
VkImage dstImage,
|
||||
VkImageLayout dstImageLayout,
|
||||
uint32_t regionCount,
|
||||
const VkBufferImageCopy* pRegions);
|
||||
|
||||
typedef struct VkBufferCopy {
|
||||
VkDeviceSize srcOffset;
|
||||
VkDeviceSize dstOffset;
|
||||
VkDeviceSize size;
|
||||
} VkBufferCopy;
|
||||
|
||||
void vkCmdCopyBuffer(
|
||||
VkCommandBuffer commandBuffer,
|
||||
VkBuffer srcBuffer,
|
||||
VkBuffer dstBuffer,
|
||||
uint32_t regionCount,
|
||||
const VkBufferCopy* pRegions);
|
||||
|
||||
typedef struct VkImageCopy {
|
||||
VkImageSubresourceLayers srcSubresource;
|
||||
VkOffset3D srcOffset;
|
||||
VkImageSubresourceLayers dstSubresource;
|
||||
VkOffset3D dstOffset;
|
||||
VkExtent3D extent;
|
||||
} VkImageCopy;
|
||||
|
||||
void vkCmdCopyImage(
|
||||
VkCommandBuffer commandBuffer,
|
||||
VkImage srcImage,
|
||||
VkImageLayout srcImageLayout,
|
||||
VkImage dstImage,
|
||||
VkImageLayout dstImageLayout,
|
||||
uint32_t regionCount,
|
||||
const VkImageCopy* pRegions);
|
||||
|
||||
|
||||
// #include "../../margaret/vulkan_memory_claire.h"
|
||||
// #include "../../margaret/vulkan_me"
|
||||
|
||||
int main(){
|
||||
return 0;
|
||||
}
|
||||
1
src/l2/tests/hse/A/A.c
Normal file
1
src/l2/tests/hse/A/A.c
Normal file
@ -0,0 +1 @@
|
||||
#include "../../../../l1/core/util.h"
|
||||
2159
src/l2/tests/r0/r0.c
Normal file
2159
src/l2/tests/r0/r0.c
Normal file
File diff suppressed because it is too large
Load Diff
795
src/l2/tests/r0/r0_assets.h
Normal file
795
src/l2/tests/r0/r0_assets.h
Normal file
@ -0,0 +1,795 @@
|
||||
#ifndef SPLITTER_DRAFT_SRC_L2_TESTS_R0_ASSETS_H
|
||||
#define SPLITTER_DRAFT_SRC_L2_TESTS_R0_ASSETS_H
|
||||
|
||||
#include "../../marie/graphics_geom.h"
|
||||
#include "../../../../gen/l1/VecAndSpan_int_primitives.h"
|
||||
#include "../../../l1/system/fileio.h"
|
||||
#include <math.h>
|
||||
#include "../../../../gen/l1/VecAndSpan_vec.h"
|
||||
#include "../../../../gen/l1/pixel_masses.h"
|
||||
#include "../../marie/rasterization.h"
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
vec2 tex;
|
||||
} GenericMeshVertex;
|
||||
#include "../../../../gen/l1/eve/r0/VecAndSpan_GenericMeshVertex.h"
|
||||
|
||||
typedef struct {
|
||||
VecGenericMeshVertex vertices;
|
||||
VecU32 indexes;
|
||||
} GenericMeshTopology;
|
||||
|
||||
void GenericMeshTopology_drop(GenericMeshTopology self) {
|
||||
VecGenericMeshVertex_drop(self.vertices);
|
||||
VecU32_drop(self.indexes);
|
||||
}
|
||||
|
||||
GenericMeshTopology GenericMeshTopology_clone(const GenericMeshTopology* self) {
|
||||
return (GenericMeshTopology){.vertices = VecGenericMeshVertex_clone(&self->vertices), .indexes = VecU32_clone(&self->indexes)};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GenericMeshTopology topology;
|
||||
U32 max_instance_count;
|
||||
} GenericMeshInSceneTemplate;
|
||||
|
||||
void GenericMeshInSceneTemplate_drop(GenericMeshInSceneTemplate self) {
|
||||
GenericMeshTopology_drop(self.topology);
|
||||
}
|
||||
|
||||
GenericMeshInSceneTemplate GenericMeshInSceneTemplate_clone(const GenericMeshInSceneTemplate* self) {
|
||||
return (GenericMeshInSceneTemplate){.topology = GenericMeshTopology_clone(&self->topology), .max_instance_count = self->max_instance_count};
|
||||
}
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecGenericMeshInSceneTemplate.h"
|
||||
|
||||
typedef struct {
|
||||
mat4 model_t;
|
||||
} GenericMeshInstance;
|
||||
#include "../../../../gen/l1/eve/r0/VecGenericMeshInstance.h"
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
vec3 normal;
|
||||
} ShinyMeshVertex;
|
||||
#include "../../../../gen/l1/eve/r0/VecAndSpan_ShinyMeshVertex.h"
|
||||
|
||||
typedef struct {
|
||||
VecShinyMeshVertex vertices;
|
||||
VecU32 indexes;
|
||||
} ShinyMeshTopology;
|
||||
|
||||
void ShinyMeshTopology_drop(ShinyMeshTopology self) {
|
||||
VecShinyMeshVertex_drop(self.vertices);
|
||||
VecU32_drop(self.indexes);
|
||||
}
|
||||
|
||||
ShinyMeshTopology ShinyMeshTopology_clone(const ShinyMeshTopology* self) {
|
||||
return (ShinyMeshTopology){.vertices = VecShinyMeshVertex_clone(&self->vertices), VecU32_clone(&self->indexes)};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ShinyMeshTopology topology;
|
||||
U32 max_instance_count;
|
||||
} ShinyMeshInSceneTemplate;
|
||||
|
||||
void ShinyMeshInSceneTemplate_drop(ShinyMeshInSceneTemplate self) {
|
||||
ShinyMeshTopology_drop(self.topology);
|
||||
}
|
||||
|
||||
ShinyMeshInSceneTemplate ShinyMeshInSceneTemplate_clone(const ShinyMeshInSceneTemplate* self) {
|
||||
return (ShinyMeshInSceneTemplate){.topology = ShinyMeshTopology_clone(&self->topology),
|
||||
.max_instance_count = self->max_instance_count};
|
||||
}
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecShinyMeshInSceneTemplate.h"
|
||||
|
||||
typedef struct {
|
||||
mat4 model_t;
|
||||
vec3 color_off;
|
||||
vec3 color_on;
|
||||
} ShinyMeshInstance;
|
||||
#include "../../../../gen/l1/eve/r0/VecShinyMeshInstance.h"
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
vec2 win_scale;
|
||||
} Pipeline1PushRangeVertex;
|
||||
|
||||
typedef struct {
|
||||
float gamma_correction_factor;
|
||||
float hdr_factor;
|
||||
float lsd_factor;
|
||||
float anim_time;
|
||||
} Pipeline1PushRangeFragment;
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
char _padding_0[4];
|
||||
vec3 dir;
|
||||
char _padding_1[4];
|
||||
vec3 color;
|
||||
char _padding_2[4];
|
||||
float d;
|
||||
char _padding_3[12];
|
||||
} Pipeline0Spotlight;
|
||||
#include "../../../../gen/l1/eve/r0/VecPipeline0Spotlight.h"
|
||||
|
||||
typedef struct {
|
||||
vec3 pos;
|
||||
char _padding_0[4];
|
||||
vec3 color;
|
||||
char _padding_1[4];
|
||||
} Pipeline0PointLight;
|
||||
#include "../../../../gen/l1/eve/r0/VecPipeline0PointLight.h"
|
||||
|
||||
typedef struct {
|
||||
VecGenericMeshInSceneTemplate generic_models;
|
||||
VecShinyMeshInSceneTemplate shiny_models;
|
||||
size_t point_lights_max_count;
|
||||
size_t spotlights_max_count;
|
||||
} SceneTemplate;
|
||||
|
||||
void SceneTemplate_drop(SceneTemplate self) {
|
||||
VecGenericMeshInSceneTemplate_drop(self.generic_models);
|
||||
}
|
||||
|
||||
size_t SceneTemplate_get_space_needed_for_all_instance_attributes(const SceneTemplate* self) {
|
||||
size_t s = 0;
|
||||
for (size_t mi = 0; mi < self->generic_models.len; mi++) {
|
||||
const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&self->generic_models, mi);
|
||||
s += M->max_instance_count * sizeof(GenericMeshInstance);
|
||||
}
|
||||
for (size_t mi = 0; mi < self->shiny_models.len; mi++) {
|
||||
const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&self->shiny_models, mi);
|
||||
s += M->max_instance_count * sizeof(ShinyMeshInstance);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t SceneTemplate_get_space_needed_for_widest_state_transfer(const SceneTemplate* self) {
|
||||
return self->point_lights_max_count * sizeof(Pipeline0PointLight) +
|
||||
self->spotlights_max_count * sizeof(Pipeline0Spotlight) +
|
||||
SceneTemplate_get_space_needed_for_all_instance_attributes(self);
|
||||
|
||||
}
|
||||
|
||||
size_t SceneTemplate_get_space_for_initial_model_topology_transfer(const SceneTemplate* self) {
|
||||
size_t s = 0;
|
||||
for (size_t mi = 0; mi < self->generic_models.len; mi++) {
|
||||
const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&self->generic_models, mi);
|
||||
s += M->topology.vertices.len * sizeof(GenericMeshVertex) + M->topology.indexes.len * sizeof(U32);
|
||||
}
|
||||
for (size_t mi = 0; mi < self->shiny_models.len; mi++) {
|
||||
const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&self->shiny_models, mi);
|
||||
s += M->topology.vertices.len * sizeof(ShinyMeshVertex) + M->topology.indexes.len * sizeof(U32);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#define pipeline_0_ubo_point_light_max_count 20
|
||||
#define pipeline_0_ubo_spotlight_max_count 120
|
||||
|
||||
typedef struct {
|
||||
int point_light_count;
|
||||
int spotlight_count;
|
||||
char _padding_1[8];
|
||||
Pipeline0PointLight point_light_arr[pipeline_0_ubo_point_light_max_count];
|
||||
Pipeline0Spotlight spotlight_arr[pipeline_0_ubo_spotlight_max_count];
|
||||
} Pipeline0UBO;
|
||||
|
||||
size_t GenericMeshTopology_get_space_needed_for_staging_buffer(const GenericMeshTopology* self) {
|
||||
return MAX_U64(self->vertices.len * sizeof(GenericMeshVertex), self->indexes.len * sizeof(U32));
|
||||
}
|
||||
|
||||
void TextureDataR8_pixel_maxing(TextureDataR8* self, S32 x, S32 y, U8 val) {
|
||||
if (x < 0 || y < 0 || (size_t)x >= self->width)
|
||||
return;
|
||||
size_t p = (size_t)x + (size_t)y * self->width;
|
||||
if (p >= self->pixels.len)
|
||||
return;
|
||||
U8 b = *TextureDataR8_at(self, x, y);
|
||||
*TextureDataR8_mat(self, x, y) = MAX_U8(b, val);
|
||||
}
|
||||
|
||||
U8 a_small_cute_gradient(float r_cut, float r_decay, float dist) {
|
||||
return dist > r_cut ? 0 : (dist < r_decay) ? 255 : (U8)roundf( 255.f * (r_cut - dist) / (r_cut - r_decay) );
|
||||
}
|
||||
|
||||
void TextureDataR8_draw_spot_maxing(TextureDataR8* self, vec2 v, float r_cut, float r_decay) {
|
||||
S32 sx = (S32)roundf(v.x - .5f);
|
||||
S32 sy = (S32)roundf(v.y - .5f);
|
||||
S32 k = (S32)ceilf(r_cut);
|
||||
for (S32 i = sx-k; i <= sx+k; i++) {
|
||||
for (S32 j = sy-k; j <= sy+k; j++) {
|
||||
float dx = 0.5f + (float)i - v.x;
|
||||
float dy = 0.5f + (float)j - v.y;
|
||||
float dist = sqrtf(dx*dx + dy*dy);
|
||||
TextureDataR8_pixel_maxing(self, i, j, a_small_cute_gradient(r_cut, r_decay, dist));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenericMeshTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
const vec2 v0tex = {r / (2 * r + w), r / (2 * r + (float)k * l)};
|
||||
const vec2 v1tex = {(r + w) / (2 * r + w), r / (2 * r + (float)k * l)};
|
||||
const vec2 v2tex = {r / (2 * r + w), 2 * r / (2 * r + (float)k * l)};
|
||||
const vec2 v3tex = {(r + w) / (2 * r + w), 2 * r / (2 * r + (float)k * l)};
|
||||
VecGenericMeshVertex vertices = VecGenericMeshVertex_new_reserved(4 * k + 6);
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, 0, 0}, .tex = v0tex});
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, 0, 0}, .tex = v1tex});
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, r, 0}, .tex = v2tex});
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, r, 0}, .tex = v3tex});
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {0, 0, -r}, .tex = {r / (2 * r + w), 0}});
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){.pos = {w, 0, -r}, .tex = {(r + w) / (2 * r + w), 0}});
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){
|
||||
.pos = {0, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = vec2_add_vec2(v0tex, (vec2){r / (2 * r + w) * -sinf(a * (float)i), r / (2*r + (float)k * l) * cosf(a * (float)i)})
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){
|
||||
.pos = {w, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = vec2_add_vec2(v1tex, (vec2){r / (2 * r + w) * sinf(a * (float)i), r / (2*r + (float)k * l) * cosf(a * (float)i)})
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){
|
||||
.pos = {0, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = {v2tex.x, v2tex.y + (float)i * l / (2*r + (float)k * l)}
|
||||
});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
VecGenericMeshVertex_append(&vertices, (GenericMeshVertex){
|
||||
.pos = {w, cosf(a * (float)i) * r, -sinf(a * (float)i) * r},
|
||||
.tex = {v3tex.x, v3tex.y + (float)i * l / (2*r + (float)k * l)}
|
||||
});
|
||||
}
|
||||
VecU32 indexes = VecU32_new_reserved(3*(2+2+2*k+2*k));
|
||||
{
|
||||
U32 _span_0[] = {5, 1, 0, 5, 0, 4, 1, 3, 0, 3, 2, 0};
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)});
|
||||
}
|
||||
for (U32 i = 1; i <= k; i++) {
|
||||
U32 _span_1[] = {
|
||||
0, i > 1 ? 5 + i - 1 : 2, 5 + i,
|
||||
1, 5 + k + i, i > 1 ? 5 + k + i - 1 : 3,
|
||||
i > 1 ? 5 + 2 * k + i - 1 : 2, i > 1 ? 5 + 3 * k + i - 1 : 3, 5 + 2 * k + i,
|
||||
5 + 3 * k + i, 5 + 2 * k + i, i > 1 ? 5 + 3 * k + i - 1 : 3,
|
||||
};
|
||||
VecU32_append_span(&indexes, (SpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)});
|
||||
}
|
||||
return (GenericMeshTopology){.vertices = vertices, .indexes = indexes};
|
||||
}
|
||||
|
||||
vec2 perimeter_line_get_thorn_on_vertex(Spanvec2 P, size_t i, float thickness) {
|
||||
assert(P.len >= 3 && i < P.len);
|
||||
vec2 A = *Spanvec2_at(P, i ? i - 1 : P.len - 1);
|
||||
vec2 B = *Spanvec2_at(P, i);
|
||||
vec2 C = *Spanvec2_at(P, i == P.len - 1 ? 0 : i + 1);
|
||||
vec2 b = vec2_normalize(vec2_minus_vec2(A, B));
|
||||
vec2 f = vec2_minus_vec2(C, B);
|
||||
float cr = b.x * f.y - b.y * f.x;
|
||||
float dt = b.x * f.x + b.y * f.y;
|
||||
float a = M_PIf + atan2f(cr, dt);
|
||||
float t = M_PI_2f + a / 2;
|
||||
return vec2_mul_scal(mat2_mul_vec2(marie_2d_rot_mat2(t), b), thickness / sinf(t));
|
||||
}
|
||||
|
||||
/* It is assumed that A != B */
|
||||
float distance_to_segment(vec2 A, vec2 B, vec2 P) {
|
||||
vec2 seg = vec2_minus_vec2(B, A);
|
||||
vec2 tg = vec2_minus_vec2(P, A);
|
||||
float t = vec2_dot(seg, tg) / vec2_dot(seg, seg);
|
||||
float c = marie_clamp_float(t, 0, 1);
|
||||
vec2 closest = vec2_add_vec2(A, vec2_mul_scal(seg, c));
|
||||
float len = vec2_length(vec2_minus_vec2(P, closest));
|
||||
return len;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8* texture;
|
||||
vec2 A;
|
||||
vec2 B;
|
||||
float r_cut;
|
||||
float r_decay;
|
||||
} TextureDataR8_draw_perimeter_maxing_H_DrawGuest;
|
||||
|
||||
void TextureDataR8_draw_perimeter_maxing_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest* g = ug;
|
||||
if (TextureDataR8_is_inside(g->texture, x, y)) {
|
||||
vec2 P = {attr.x, attr.y};
|
||||
U8 clr = a_small_cute_gradient(g->r_cut, g->r_decay, distance_to_segment(g->A, g->B, P));
|
||||
TextureDataR8_pixel_maxing(g->texture, x, y, clr);
|
||||
}
|
||||
}
|
||||
|
||||
void TextureDataR8_draw_perimeter_maxing_h_draw_triangle(
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest* aboba, vec2 a, vec2 b, vec2 c
|
||||
) {
|
||||
marie_rasterize_triangle_with_attr((MariePlaneVertAttr){a, {a.x, a.y, 0, 0}},
|
||||
(MariePlaneVertAttr){b, {b.x, b.y, 0, 0}}, (MariePlaneVertAttr){c, {c.x, c.y, 0, 0}},
|
||||
(FnMarieRasterizerCallback){TextureDataR8_draw_perimeter_maxing_h_draw_guest, aboba});
|
||||
}
|
||||
|
||||
/* It is assumed that P[i] != P[i + 1] foreach i from 0 to P.len - 1 */
|
||||
void TextureDataR8_draw_perimeter_maxing(TextureDataR8* self, Spanvec2 P) {
|
||||
float r_cut = 5;
|
||||
float r_decay = 2;
|
||||
for (size_t i = 0; i < P.len; i++) {
|
||||
size_t ia = i == P.len - 1 ? 0 : i + 1;
|
||||
vec2 A = *Spanvec2_at(P, i);
|
||||
vec2 B = *Spanvec2_at(P, ia);
|
||||
vec2 hA = perimeter_line_get_thorn_on_vertex(P, i, r_cut);
|
||||
vec2 hB = perimeter_line_get_thorn_on_vertex(P, ia, r_cut);
|
||||
vec2 q0 = vec2_add_vec2(A, hA);
|
||||
vec2 q1 = vec2_add_vec2(B, hB);
|
||||
vec2 q2 = vec2_minus_vec2(B, hB);
|
||||
vec2 q3 = vec2_minus_vec2(A, hA);
|
||||
TextureDataR8_draw_perimeter_maxing_H_DrawGuest aboba = { self, A, B, r_cut, r_decay };
|
||||
TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q1, q2);
|
||||
TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q2, q3);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
vec2 bl;
|
||||
vec2 tr;
|
||||
float height;
|
||||
float brd;
|
||||
} Wimbzle;
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecWimbzle.h"
|
||||
|
||||
typedef struct {
|
||||
vec2 center;
|
||||
float rad;
|
||||
float hc;
|
||||
} Nibzle;
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecNibzle.h"
|
||||
|
||||
typedef struct {
|
||||
VecWimbzle wimbzles;
|
||||
VecNibzle nibzles;
|
||||
} Bublazhuzhka;
|
||||
|
||||
Bublazhuzhka Bublazhuzhka_new() {
|
||||
return (Bublazhuzhka){.wimbzles = VecWimbzle_new(), .nibzles = VecNibzle_new()};
|
||||
}
|
||||
|
||||
void Bublazhuzhka_drop(Bublazhuzhka self) {
|
||||
VecWimbzle_drop(self.wimbzles);
|
||||
VecNibzle_drop(self.nibzles);
|
||||
}
|
||||
|
||||
void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDataR8* canvas, mat3x2 trop) {
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
|
||||
vec2 p1[4] = {mat3x2_mul_vec3(trop, vec2_and_one(A)), mat3x2_mul_vec3(trop, vec2_and_one(B)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(D)), mat3x2_mul_vec3(trop, vec2_and_one(C))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p1, ARRAY_SIZE(p1)});
|
||||
vec2 p2[4] = {mat3x2_mul_vec3(trop, vec2_and_one(E)), mat3x2_mul_vec3(trop, vec2_and_one(F)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(H)), mat3x2_mul_vec3(trop, vec2_and_one(G))};
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p2, ARRAY_SIZE(p2)});
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_at(&self->nibzles, i);
|
||||
Vecvec2 p = Vecvec2_new_zeroinit(13);
|
||||
for (int j = 0; j < 13; j++) {
|
||||
float a = (float)j * 2 * M_PIf / 13;
|
||||
*Vecvec2_mat(&p, j) = mat3x2_mul_vec3(trop, vec2_and_one(vec2_add_vec2(sphere.center,
|
||||
vec2_mul_scal(marie_trigonom_circle(a), sphere.rad))));
|
||||
}
|
||||
TextureDataR8_draw_perimeter_maxing(canvas, Vecvec2_to_span(&p));
|
||||
Vecvec2_drop(p);
|
||||
TextureDataR8_draw_spot_maxing(canvas, mat3x2_mul_vec3(trop, vec2_and_one(sphere.center)), 3, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Bublazhuzhka fill_rectangle_with_crap(float w, float h) {
|
||||
S32 k = MAX_S32(0, (S32)floorf((w/h + 0.1f) / 0.7f));
|
||||
VecWimbzle wimbzles = VecWimbzle_new_zeroinit(k);
|
||||
VecNibzle nibzles = VecNibzle_new_zeroinit(2 * k);
|
||||
float start = k != 1 ? h * 0.2f : ((w - 0.2f * h) / 2);
|
||||
float d = k > 1 ? ((w - h * 0.4f - h * 0.2f * (float)k) / (float)(k - 1)) : 0;
|
||||
for (S32 i = 0; i < k; i++) {
|
||||
float x = start + (d + h * 0.2f) * (float)i;
|
||||
*VecWimbzle_mat(&wimbzles, i) = (Wimbzle){.bl = {x + 0.02f * h, 0.27f * h}, .tr = {x + 0.18f * h, h * 0.73f}, .height = h * 0.03f, .brd = h * 0.03f};
|
||||
/* hc is a height coefficient*/
|
||||
*VecNibzle_mat(&nibzles, 2 * i) = (Nibzle){.center = {x + 0.10f * h, 0.11f * h}, .rad = h * 0.05f, .hc = 0.75f};
|
||||
*VecNibzle_mat(&nibzles, 2 * i + 1) = (Nibzle){.center = {x + 0.10f * h, 0.89f * h}, .rad = h * 0.05f, .hc = 0.75f};
|
||||
}
|
||||
return (Bublazhuzhka){.wimbzles = wimbzles, .nibzles = nibzles};
|
||||
}
|
||||
|
||||
vec2 Bublazhuzhka_get_derivative(const Bublazhuzhka* self, vec2 v) {
|
||||
vec2 sum = { 0 };
|
||||
for (size_t i = 0; i < self->wimbzles.len; i++) {
|
||||
Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i);
|
||||
vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd};
|
||||
vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd};
|
||||
vec2 A = {C.x, B.y};
|
||||
vec2 D = {B.x, C.y};
|
||||
vec2 F = rect.tr;
|
||||
vec2 G = rect.bl;
|
||||
vec2 E = {G.x, F.y};
|
||||
vec2 H = {F.x, G.y};
|
||||
float slp = rect.height / rect.brd;
|
||||
if (A.x < v.x && v.x < E.x && marie_surface(E, A, v) > 0 && marie_surface(C, G, v) > 0) {
|
||||
sum.x += slp;
|
||||
} else if (F.x < v.x && v.x < B.x && marie_surface(B, F, v) > 0 && marie_surface(H, D, v) > 0) {
|
||||
sum.x -= slp;
|
||||
} else if (C.y < v.y && v.y < G.y && marie_surface(G, C, v) > 0 && marie_surface(D, H, v) > 0) {
|
||||
sum.y += slp;
|
||||
} else if (F.y < v.y && v.y < B.y && marie_surface(A, E, v) > 0 && marie_surface(F, B, v) > 0) {
|
||||
sum.y -= slp;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < self->nibzles.len; i++) {
|
||||
Nibzle sphere = *VecNibzle_at(&self->nibzles, i);
|
||||
float sq_h = pow2f(sphere.rad) - pow2f(v.x - sphere.center.x) - pow2f(v.y - sphere.center.y);
|
||||
if (sq_h <= 0)
|
||||
continue;
|
||||
float w = sphere.hc / sqrtf(sq_h);
|
||||
sum = vec2_add_vec2(sum, vec2_mul_scal(vec2_minus_vec2(sphere.center, v), w));
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
cvec3 compress_normal_vec_into_norm_texel(vec3 n) {
|
||||
return (cvec3){(U32)roundf(255 * (n.x + 1) / 2), (U32)roundf(255 * (n.y + 1) / 2), (U32)roundf(255 * (n.z + 1) / 2)};
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnNormalVectorGenCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* tex;
|
||||
FnNormalVectorGenCallback my_client;
|
||||
} draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec2){attr.x, attr.y});
|
||||
cvec3 ans = compress_normal_vec_into_norm_texel(normal);
|
||||
*TextureDataR8G8B8A8_mat(g->tex, x, y) = (cvec4){ans.x, ans.y, ans.z, 255};
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_smooth_param_surf(
|
||||
TextureDataR8G8B8A8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop, FnNormalVectorGenCallback cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb};
|
||||
// todo: generate rasterization function (with different precision + different attributes)
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pa)), .attr = {pa.x, pa.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pb)), .attr = {pb.x, pb.y, 0, 0} },
|
||||
(MariePlaneVertAttr){.pos = mat3x2_mul_vec3(trop, vec2_and_one(pc)), .attr = {pc.x, pc.y, 0, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb, (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> normal vector in model space */
|
||||
vec3 (*fn)(void*, vec3);
|
||||
void* guest;
|
||||
} FnNormalVectorGenExaggParamCallback;
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8* tex;
|
||||
FnNormalVectorGenExaggParamCallback my_client;
|
||||
} draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest* g = ug;
|
||||
vec3 normal = g->my_client.fn(g->my_client.guest, (vec3){attr.x, attr.y, attr.z});
|
||||
*TextureDataR8G8B8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal);
|
||||
}
|
||||
|
||||
/* We can't derive texture coordinates from parameter space coordinates, you have to do it yourself */
|
||||
void draw_polygon_on_normal_texture_nat_cords_exaggerated_param_surf(
|
||||
TextureDataR8G8B8* tex, vec2 ta, vec2 tb, vec2 tc, vec3 pa, vec3 pb, vec3 pc, FnNormalVectorGenExaggParamCallback cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest aboba = {.tex = tex, .my_client = cb};
|
||||
marie_rasterize_triangle_with_attr(
|
||||
(MariePlaneVertAttr){.pos = ta, .attr = {pa.x, pa.y, pa.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tb, .attr = {pb.x, pb.y, pb.z, 0} },
|
||||
(MariePlaneVertAttr){.pos = tc, .attr = {pc.x, pc.y, pc.z, 0} },
|
||||
(FnMarieRasterizerCallback){draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb, (void*)&aboba});
|
||||
}
|
||||
// todo: add a version for that function with non-native coordinate system (on vertex) (like I did with absolutely flat surface)
|
||||
|
||||
|
||||
typedef struct {
|
||||
TextureDataR8G8B8A8* tex;
|
||||
cvec3 normal_compr;
|
||||
} draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest;
|
||||
|
||||
void draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest* g = ug;
|
||||
*TextureDataR8G8B8A8_mat(g->tex, x, y) = (cvec4){g->normal_compr.x, g->normal_compr.y, g->normal_compr.z, 255};
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_nat_cords_absolutely_flat(TextureDataR8G8B8A8* tex,
|
||||
vec2 ta, vec2 tb, vec2 tc, vec3 c_normal
|
||||
) {
|
||||
draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest aboba = {tex, compress_normal_vec_into_norm_texel(c_normal)};
|
||||
marie_rasterize_triangle_with_attr((MariePlaneVertAttr){.pos = ta}, (MariePlaneVertAttr){.pos = tb},
|
||||
(MariePlaneVertAttr){.pos = tc}, (FnMarieRasterizerCallback){
|
||||
.fn = draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
void draw_polygon_on_normal_texture_absolutely_flat(TextureDataR8G8B8A8* tex,
|
||||
vec2 pa, vec2 pb, vec2 pc, mat3x2 trop, vec3 c_normal
|
||||
) {
|
||||
draw_polygon_on_normal_texture_nat_cords_absolutely_flat(tex, mat3x2_mul_vec3(trop, vec2_and_one(pa)),
|
||||
mat3x2_mul_vec3(trop, vec2_and_one(pb)), mat3x2_mul_vec3(trop, vec2_and_one(pc)), c_normal);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* (guest, param) -> height gradient */
|
||||
vec2 (*fn)(void*, vec2);
|
||||
void* guest;
|
||||
} FnHeightMapGradFlatSurfCallback;
|
||||
|
||||
typedef struct {
|
||||
mat3 surf_orient;
|
||||
FnHeightMapGradFlatSurfCallback my_client;
|
||||
} draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest;
|
||||
|
||||
vec3 draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb(void* ug, vec2 p) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest* g = ug;
|
||||
vec2 grad = g->my_client.fn(g->my_client.guest, p);
|
||||
return mat3_mul_vec3(g->surf_orient, marie_normal_from_tang_space_gradient(grad.x, grad.y));
|
||||
}
|
||||
|
||||
/* The simplest case of normal texture generation: for a smooth flat surface of a polygon */
|
||||
void draw_polygon_on_normal_texture_flat_param_surf(TextureDataR8G8B8A8* tex, vec2 pa, vec2 pb, vec2 pc, mat3x2 trop,
|
||||
mat3 surf_orient, FnHeightMapGradFlatSurfCallback height_map_cb
|
||||
) {
|
||||
draw_polygon_on_normal_texture_flat_param_surf_H_DrawGuest aboba = {surf_orient, height_map_cb};
|
||||
draw_polygon_on_normal_texture_smooth_param_surf(tex, pa, pb, pc, trop, (FnNormalVectorGenCallback){
|
||||
.fn = draw_polygon_on_normal_texture_flat_param_surf_h_draw_cb, .guest = (void*)&aboba});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w));
|
||||
size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l));
|
||||
vec2 cord_resol = {(float)width_pix / (2 * r + w), (float)height_pix / (2 * r + (float)k * l)};
|
||||
const vec2 v0tex = {r, r};
|
||||
const vec2 v1tex = {r + w, r};
|
||||
const vec2 v2tex = {r, 2 * r};
|
||||
const vec2 v3tex = {r + w, 2 * r};
|
||||
TextureDataR8 res = TextureDataR8_new(width_pix, height_pix);
|
||||
Vecvec2 P = Vecvec2_new_reserved(6 + k * 4);
|
||||
Vecvec2_append(&P, v0tex);
|
||||
Vecvec2_append(&P, (vec2){r, 0}); // 4
|
||||
Vecvec2_append(&P, (vec2){r + w, 0}); // 5
|
||||
Vecvec2_append(&P, v1tex);
|
||||
for (size_t i = k; i > 0; i--) {
|
||||
Vecvec2_append(&P, (vec2){r + w + r * sinf(a * (float)i), r + r * cosf(a * (float)i)});
|
||||
}
|
||||
Vecvec2_append(&P, v3tex);
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
Vecvec2_append(&P, (vec2){r + w, 2 * r + (float)i * l});
|
||||
}
|
||||
for (size_t i = k; i > 0; i--) {
|
||||
Vecvec2_append(&P, (vec2){r, 2 * r + (float)i * l});
|
||||
}
|
||||
Vecvec2_append(&P, v2tex);
|
||||
for (size_t i = 1; i <= k; i++) {
|
||||
Vecvec2_append(&P, (vec2){r - r * sinf(a * (float)i), r + r * cosf(a * (float)i)});
|
||||
}
|
||||
for (size_t i = 0; i < P.len; i++) {
|
||||
*Vecvec2_mat(&P, i) = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol);
|
||||
}
|
||||
TextureDataR8_draw_perimeter_maxing(&res, Vecvec2_to_span(&P));
|
||||
Vecvec2_drop(P);
|
||||
|
||||
Bublazhuzhka crap_on_back_side = fill_rectangle_with_crap(w, r);
|
||||
// todo: draw bublazhuzhka pixel-by-pixel myself
|
||||
Bublazhuzhka_TextureDataR8_draw_maxing(&crap_on_back_side, &res,
|
||||
(mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)});
|
||||
Bublazhuzhka_drop(crap_on_back_side);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Use it as a callback in normal map drawing functions that work with smooth (smooth / flat / cylindrical)
|
||||
* height maps. Guest pointer is of type Bublazhuzhka* */
|
||||
vec2 height_map_cb_that_uses_bublazhuzhka(void* ug, vec2 v) {
|
||||
Bublazhuzhka* bzh = ug;
|
||||
return Bublazhuzhka_get_derivative(bzh, v);
|
||||
}
|
||||
|
||||
TextureDataR8G8B8A8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) {
|
||||
assert(k >= 1);
|
||||
const float a = M_PI_2f / (float)k;
|
||||
const float l = 2 * r * sinf(M_PI_4f / (float)k);
|
||||
size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w));
|
||||
size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l));
|
||||
vec2 cord_resol = {(float)width_pix / (2 * r + w), (float)height_pix / (2 * r + (float)k * l)};
|
||||
const vec2 v0tex = {r, r};
|
||||
const vec2 v1tex = {r + w, r};
|
||||
// const vec2 v2tex = {r, 2 * r};
|
||||
// const vec2 v3tex = {r + w, 2 * r};
|
||||
const vec2 v4tex = {r, 0};
|
||||
const vec2 v5tex = {r + w, 0};
|
||||
TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width_pix, height_pix);
|
||||
|
||||
Bublazhuzhka crap_on_the_back_side = fill_rectangle_with_crap(w, r);
|
||||
mat3x2 trop_back_side = {.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)};
|
||||
mat3 orient_back_side = {.x = {1, 0, 0}, .y = {0, 0, 1}, .z = {0, 1, 0}};
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){w, 0}, (vec2){w, r}, trop_back_side, orient_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){0, r}, (vec2){w, r}, trop_back_side, orient_back_side,
|
||||
(FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side});
|
||||
Bublazhuzhka_drop(crap_on_the_back_side);
|
||||
|
||||
mat3x2 str = {.x.x = cord_resol.x, .y.y = cord_resol.y};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v0tex, v1tex, v4tex, str, (vec3){0, -1, 0});
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, v1tex, v4tex, v5tex, str, (vec3){0, -1, 0});
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r - sinf((float)i * a) * r, r + cosf((float)i * a) * r};
|
||||
vec2 B = {r - sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r, r}, str, (vec3){-1, 0, 0});
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r + w + sinf((float)i * a) * r, r + cosf((float)i * a) * r};
|
||||
vec2 B = {r + w + sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r + w, r}, str, (vec3){1, 0, 0});
|
||||
}
|
||||
for (size_t i = 0; i < k; i++) {
|
||||
vec2 A = {r, 2 * r + (float)i * l};
|
||||
vec2 B = {r + w, 2 * r + (float)i * l};
|
||||
vec2 C = {r, 2 * r + (float)i * l + l};
|
||||
vec2 D = {r + w, 2 * r + (float)i * l + l};
|
||||
vec3 n = {0, cosf(a / 2 + a * (float)i), -sinf(a / 2 + a * (float)i)};
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, C, str, n);
|
||||
draw_polygon_on_normal_texture_absolutely_flat(&res, D, B, C, str, n);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U32 quad_to_triangles_conv_arr[6] = {0, 1, 2, 0, 2, 3};
|
||||
|
||||
ShinyMeshTopology generate_shiny_cube(float r) {
|
||||
ShinyMeshVertex vert[24] = {
|
||||
{{+r, +r, +r}, {1, 0, 0}},
|
||||
{{+r, -r, +r}, {1, 0, 0}},
|
||||
{{+r, -r, -r}, {1, 0, 0}},
|
||||
{{+r, +r, -r}, {1, 0, 0}},
|
||||
|
||||
{{-r, -r, -r}, {-1, 0, 0}},
|
||||
{{-r, -r, +r}, {-1, 0, 0}},
|
||||
{{-r, +r, +r}, {-1, 0, 0}},
|
||||
{{-r, +r, -r}, {-1, 0, 0}},
|
||||
|
||||
{{+r, +r, +r}, {0, 1, 0}},
|
||||
{{+r, +r, -r}, {0, 1, 0}},
|
||||
{{-r, +r, -r}, {0, 1, 0}},
|
||||
{{-r, +r, +r}, {0, 1, 0}},
|
||||
|
||||
{{-r, -r, -r}, {0, -1, 0}},
|
||||
{{+r, -r, -r}, {0, -1, 0}},
|
||||
{{+r, -r, +r}, {0, -1, 0}},
|
||||
{{-r, -r, +r}, {0, -1, 0}},
|
||||
|
||||
{{+r, +r, +r}, {0, 0, 1}},
|
||||
{{-r, +r, +r}, {0, 0, 1}},
|
||||
{{-r, -r, +r}, {0, 0, 1}},
|
||||
{{+r, -r, +r}, {0, 0, 1}},
|
||||
|
||||
{{-r, -r, -r}, {0, 0, -1}},
|
||||
{{-r, +r, -r}, {0, 0, -1}},
|
||||
{{+r, +r, -r}, {0, 0, -1}},
|
||||
{{+r, -r, -r}, {0, 0, -1}},
|
||||
};
|
||||
VecShinyMeshVertex vertices_vec = VecShinyMeshVertex_new_zeroinit(24);
|
||||
memcpy(vertices_vec.buf, vert, sizeof(vert));
|
||||
VecU32 indexes_vec = VecU32_new_reserved(36);
|
||||
for (U32 f = 0; f < 6; f++) {
|
||||
for (U32 j = 0; j < 6; j++)
|
||||
VecU32_append(&indexes_vec, f * 4 + quad_to_triangles_conv_arr[j]);
|
||||
}
|
||||
return (ShinyMeshTopology){ .vertices = vertices_vec, .indexes = indexes_vec};
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int face;
|
||||
/* There is a counterclockwise one-to-one correspondence between vertexes of face and edges of face */
|
||||
int vert_on_it;
|
||||
} CubeVertOfFace;
|
||||
|
||||
CubeVertOfFace CubeVertOfFace_jump(CubeVertOfFace vert) {
|
||||
const CubeVertOfFace cube_detour_get_neighbour_face[6][4] = {
|
||||
{{4, 3}, {3, 1}, {5, 2}, {2, 0}},
|
||||
{{3, 3}, {4, 1}, {2, 2}, {5, 0}},
|
||||
{{0, 3}, {5, 1}, {1, 2}, {4, 0}},
|
||||
{{5, 3}, {0, 1}, {4, 2}, {1, 0}},
|
||||
{{2, 3}, {1, 1}, {3, 2}, {0, 0}},
|
||||
{{1, 3}, {2, 1}, {0, 2}, {3, 0}}
|
||||
};
|
||||
return cube_detour_get_neighbour_face[vert.face][vert.vert_on_it];
|
||||
}
|
||||
|
||||
U32 CubeVertOfFace_to_vid(CubeVertOfFace vert) {
|
||||
return 4 * vert.face + vert.vert_on_it;
|
||||
}
|
||||
|
||||
CubeVertOfFace CubeVertOfFace_next(CubeVertOfFace vert) {
|
||||
return (CubeVertOfFace){vert.face, (vert.vert_on_it + 1) % 4};
|
||||
}
|
||||
|
||||
ShinyMeshTopology generate_shiny_rhombicuboctahedron(float r) {
|
||||
ShinyMeshTopology res = generate_shiny_cube(r);
|
||||
for (int f = 0; f < 6; f++) {
|
||||
vec3 growth = vec3_mul_scal((*VecShinyMeshVertex_at(&res.vertices, f * 4)).normal, M_SQRT1_2);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec3* pos = &VecShinyMeshVertex_mat(&res.vertices, f * 4 + i)->pos;
|
||||
*pos = vec3_add_vec3(*pos, growth);
|
||||
}
|
||||
}
|
||||
for (int f = 0; f < 6; f++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
CubeVertOfFace vof = {f, 2*i+(f%2)};
|
||||
ShinyMeshVertex A = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(vof));
|
||||
ShinyMeshVertex B = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(CubeVertOfFace_next(CubeVertOfFace_jump(vof))));
|
||||
ShinyMeshVertex C = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(CubeVertOfFace_jump(vof)));
|
||||
ShinyMeshVertex D = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(CubeVertOfFace_next(vof)));
|
||||
vec3 norm = vec3_normalize(vec3_add_vec3(A.normal, B.normal));
|
||||
ShinyMeshVertex quad_v[4] = {{A.pos, norm}, {B.pos, norm}, {C.pos, norm}, {D.pos, norm}};
|
||||
size_t b = res.vertices.len;
|
||||
VecShinyMeshVertex_append_span(&res.vertices, (SpanShinyMeshVertex){quad_v, ARRAY_SIZE(quad_v)});
|
||||
for (U32 j = 0; j < 6; j++)
|
||||
VecU32_append(&res.indexes, b + quad_to_triangles_conv_arr[j]);
|
||||
}
|
||||
}
|
||||
for (int f = 0; f < 2; f++) {
|
||||
for (int e = 0; e < 4; e++) {
|
||||
CubeVertOfFace vof = {f, e};
|
||||
ShinyMeshVertex A = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(CubeVertOfFace_next(vof)));
|
||||
ShinyMeshVertex B = *VecShinyMeshVertex_at(&res.vertices, CubeVertOfFace_to_vid(CubeVertOfFace_jump(vof)));
|
||||
ShinyMeshVertex C = *VecShinyMeshVertex_at(&res.vertices,
|
||||
CubeVertOfFace_to_vid(CubeVertOfFace_next(CubeVertOfFace_jump(CubeVertOfFace_next(vof)))));
|
||||
vec3 norm = vec3_normalize(vec3_add_vec3(A.normal, vec3_add_vec3(B.normal, C.normal)));
|
||||
|
||||
ShinyMeshVertex ang_v[3] = {{A.pos, norm}, {B.pos, norm}, {C.pos, norm}};
|
||||
size_t b = res.vertices.len;
|
||||
VecShinyMeshVertex_append_span(&res.vertices, (SpanShinyMeshVertex){ang_v, ARRAY_SIZE(ang_v)});
|
||||
for (int i = 0; i < 3; i++)
|
||||
VecU32_append(&res.indexes, b + i);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif
|
||||
168
src/l2/tests/r0/r0_scene.h
Normal file
168
src/l2/tests/r0/r0_scene.h
Normal file
@ -0,0 +1,168 @@
|
||||
#ifndef PROTOTYPE1_SRC_L2_TESTS_R0_SCENE_H
|
||||
#define PROTOTYPE1_SRC_L2_TESTS_R0_SCENE_H
|
||||
|
||||
#include "r0_assets.h"
|
||||
|
||||
/* No offset yet.
|
||||
* Contains references to vulkan handlers for buffers */
|
||||
typedef struct {
|
||||
VkBuffer vbo;
|
||||
VkBuffer ebo;
|
||||
size_t indexes;
|
||||
VkBuffer instance_attr_buf;
|
||||
VkDeviceSize instance_attr_buf_offset;
|
||||
U32 limit_max_instance_count;
|
||||
} ModelOnSceneMem;
|
||||
|
||||
/* Contains both data for model instances attributes and buffer (+offset) where it is stored */
|
||||
/* Also, I made it non-clonable. Thus */
|
||||
typedef struct {
|
||||
ModelOnSceneMem model;
|
||||
VecGenericMeshInstance instances;
|
||||
} UsedGenericModelOnScene;
|
||||
|
||||
void UsedGenericModelOnScene_drop(UsedGenericModelOnScene self) {
|
||||
VecGenericMeshInstance_drop(self.instances);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecUsedGenericModelOnScene.h"
|
||||
|
||||
typedef struct {
|
||||
ModelOnSceneMem model;
|
||||
VecShinyMeshInstance instances;
|
||||
} UsedShinyModelOnScene;
|
||||
|
||||
void UsedShinyModelOnScene_drop(UsedShinyModelOnScene self) {
|
||||
VecShinyMeshInstance_drop(self.instances);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l1/eve/r0/VecUsedShinyModelOnScene.h"
|
||||
|
||||
typedef struct {
|
||||
float fov;
|
||||
mat3 cam_basis;
|
||||
vec3 pos;
|
||||
|
||||
float speed;
|
||||
float sensitivity;
|
||||
float pitch_cap;
|
||||
} CamControlInfo;
|
||||
|
||||
void CamControlInfo_forward(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, -self->speed * fl));
|
||||
}
|
||||
|
||||
void CamControlInfo_backward(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.z, self->speed * fl));
|
||||
}
|
||||
|
||||
void CamControlInfo_left(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, -self->speed * fl));
|
||||
}
|
||||
|
||||
void CamControlInfo_right(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal(self->cam_basis.x, self->speed * fl));
|
||||
}
|
||||
|
||||
void CamControlInfo_down(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, -1, 0}, self->speed * fl));
|
||||
}
|
||||
|
||||
void CamControlInfo_up(CamControlInfo* self, float fl) {
|
||||
self->pos = vec3_add_vec3(self->pos, vec3_mul_scal((vec3){0, 1, 0}, self->speed * fl));
|
||||
}
|
||||
|
||||
CamControlInfo CamControlInfo_new() {
|
||||
return (CamControlInfo){
|
||||
.fov = 1.5f, .cam_basis = marie_simple_camera_rot_m_basis_in_cols(0, 0, 0), .pos = {0, 0, 0},
|
||||
.speed = 2.7f, .sensitivity = 0.5f * M_PIf / 180, .pitch_cap = M_PIf * 0.49f
|
||||
};
|
||||
}
|
||||
|
||||
void CamControlInfo_update_direction(CamControlInfo* self, int win_width, int win_height, int pointer_x, int pointer_y) {
|
||||
float yaw = ((float)win_width / 2 - (float)pointer_x) * self->sensitivity;
|
||||
float pitch = marie_clamp_float(
|
||||
((float)win_height / 2 - (float)pointer_y) * self->sensitivity,
|
||||
-self->pitch_cap, self->pitch_cap
|
||||
);
|
||||
self->cam_basis = marie_simple_camera_rot_m_basis_in_cols(yaw, pitch, 0);
|
||||
}
|
||||
|
||||
/* Non copyable */
|
||||
typedef struct {
|
||||
VecUsedGenericModelOnScene generic_models;
|
||||
VecUsedShinyModelOnScene shiny_models;
|
||||
VkClearColorValue color;
|
||||
float gamma_correction_factor;
|
||||
float hdr_factor;
|
||||
float lsd_factor;
|
||||
float anim_time; // A timer, passed to functions that push push constants
|
||||
VecPipeline0Spotlight spotlights;
|
||||
VecPipeline0PointLight point_lights;
|
||||
} Scene;
|
||||
|
||||
Scene Scene_new() {
|
||||
return (Scene){.generic_models = VecUsedGenericModelOnScene_new(), .shiny_models = VecUsedShinyModelOnScene_new(),
|
||||
.color = {.float32 = {0, 0, 0, 1}},
|
||||
.gamma_correction_factor = 2.2f, .hdr_factor = 1, .lsd_factor = 0, .anim_time = 0,
|
||||
.spotlights = VecPipeline0Spotlight_new(), .point_lights = VecPipeline0PointLight_new()
|
||||
};
|
||||
}
|
||||
|
||||
void Scene_drop(Scene self) {
|
||||
VecUsedGenericModelOnScene_drop(self.generic_models);
|
||||
VecUsedShinyModelOnScene_drop(self.shiny_models);
|
||||
VecPipeline0Spotlight_drop(self.spotlights);
|
||||
VecPipeline0PointLight_drop(self.point_lights);
|
||||
}
|
||||
|
||||
void SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd(
|
||||
const SceneTemplate* scene_template, const Scene* scene, char* host_mem_buffer_mem,
|
||||
VkCommandBuffer command_buffer, VkBuffer host_memory_buffer
|
||||
) {
|
||||
assert(scene_template->generic_models.len == scene->generic_models.len);
|
||||
assert(scene_template->shiny_models.len == scene->shiny_models.len);
|
||||
|
||||
if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS)
|
||||
abortf("vkResetCommandBuffer");
|
||||
VkCommandBufferBeginInfo info_begin = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
if (vkBeginCommandBuffer(command_buffer, &info_begin) != VK_SUCCESS)
|
||||
abortf("vkBeginCommandBuffer");
|
||||
|
||||
size_t offset = 0;
|
||||
// todo: use BufferCopyCmd 2 (to perform all the copying in one command)
|
||||
// todo: ot use one buffer per all the data
|
||||
for (size_t mi = 0; mi < scene_template->generic_models.len; mi++) {
|
||||
const GenericMeshInSceneTemplate* mt = VecGenericMeshInSceneTemplate_at(&scene_template->generic_models, mi);
|
||||
const ModelOnSceneMem *m_buf = &VecUsedGenericModelOnScene_at(&scene->generic_models, mi)->model;
|
||||
size_t vbo_len = mt->topology.vertices.len * sizeof(GenericMeshVertex);
|
||||
memcpy(host_mem_buffer_mem + offset, mt->topology.vertices.buf, vbo_len);
|
||||
VkBufferCopy ra = {.srcOffset = offset, .dstOffset = 0, .size = vbo_len};
|
||||
vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->vbo, 1, &ra);
|
||||
offset += vbo_len;
|
||||
size_t ebo_len = mt->topology.indexes.len * sizeof(U32);
|
||||
memcpy(host_mem_buffer_mem + offset, mt->topology.indexes.buf, ebo_len);
|
||||
VkBufferCopy rb = {.srcOffset = offset, .dstOffset = 0, .size = ebo_len};
|
||||
vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->ebo, 1, &rb);
|
||||
offset += ebo_len;
|
||||
}
|
||||
for (size_t mi = 0; mi < scene_template->shiny_models.len; mi++) {
|
||||
const ShinyMeshInSceneTemplate* mt = VecShinyMeshInSceneTemplate_at(&scene_template->shiny_models, mi);
|
||||
const ModelOnSceneMem *m_buf = &VecUsedShinyModelOnScene_at(&scene->shiny_models, mi)->model;
|
||||
size_t vbo_len = mt->topology.vertices.len * sizeof(ShinyMeshVertex);
|
||||
memcpy(host_mem_buffer_mem + offset, mt->topology.vertices.buf, vbo_len);
|
||||
VkBufferCopy ra = {.srcOffset = offset, .dstOffset = 0, .size = vbo_len};
|
||||
vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->vbo, 1, &ra);
|
||||
offset += vbo_len;
|
||||
size_t ebo_len = mt->topology.indexes.len * sizeof(U32);
|
||||
memcpy(host_mem_buffer_mem + offset, mt->topology.indexes.buf, ebo_len);
|
||||
VkBufferCopy rb = {.srcOffset = offset, .dstOffset = 0, .size = ebo_len};
|
||||
vkCmdCopyBuffer(command_buffer, host_memory_buffer, m_buf->ebo, 1, &rb);
|
||||
offset += ebo_len;
|
||||
}
|
||||
|
||||
if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS)
|
||||
abortf("vkEndCommandBuffer");
|
||||
}
|
||||
|
||||
#endif
|
||||
30
src/l2/tests/r0/r0_tex_init_prep.c
Normal file
30
src/l2/tests/r0/r0_tex_init_prep.c
Normal file
@ -0,0 +1,30 @@
|
||||
#include "r0_assets.h"
|
||||
#include "../../marie/rasterization.h"
|
||||
#include "../../margaret/png_pixel_masses.h"
|
||||
#include "../../marie/texture_processing.h"
|
||||
|
||||
void model_1_template() {
|
||||
TextureDataR8 tex = generate_tex_template_for_one_fourth_of_a_cylinder(120, 10, 2, 6);
|
||||
TextureDataR8G8B8A8 tex_1_big = TextureDataR8G8B8A8_new(tex.width, TextureDataR8_get_height(&tex));
|
||||
for (size_t i = 0; i < tex.pixels.len; i++) {
|
||||
U8 g = *VecU8_at(&tex.pixels, i);
|
||||
*Veccvec4_mat(&tex_1_big.pixels, i) = (cvec4){g, g, g, 255};
|
||||
}
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&tex_1_big, cstr("textures/log_10_2_6_TEMPLATE.png"));
|
||||
TextureDataR8G8B8A8_drop(tex_1_big);
|
||||
TextureDataR8_drop(tex);
|
||||
}
|
||||
|
||||
void model_1_normal() {
|
||||
TextureDataR8G8B8A8 tex = generate_normal_tex_for_one_fourth_of_a_cylinder(120, 10, 2, 6);
|
||||
TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex);
|
||||
TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, cstr("textures/log_10_2_6_NORMAL.png"));
|
||||
TextureDataR8G8B8A8_drop(fixed_tex);
|
||||
TextureDataR8G8B8A8_drop(tex);
|
||||
}
|
||||
|
||||
int main() {
|
||||
model_1_template();
|
||||
model_1_normal();
|
||||
return 0;
|
||||
}
|
||||
@ -1,27 +1,18 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 tang_norm;
|
||||
layout(location = 1) in vec3 tang_U;
|
||||
layout(location = 2) in vec3 tang_V;
|
||||
layout(location = 3) in vec2 tex;
|
||||
layout(location = 4) in vec3 pos;
|
||||
layout(location = 0) in vec2 fsin_tex;
|
||||
layout(location = 1) in vec3 fsin_pos;
|
||||
|
||||
/* Right now all in set 0 */
|
||||
layout(location = 0) out vec4 fin_color;
|
||||
/* Yes, even these guys */
|
||||
|
||||
layout(binding = 1) uniform sampler2D color_tex;
|
||||
|
||||
layout(binding = 2) uniform sampler2D normal_map;
|
||||
layout(binding = 3) uniform sampler2D specular_map;
|
||||
|
||||
layout(push_constant, std430) uniform pc {
|
||||
layout(offset = 64) vec3 camera_pos;
|
||||
};
|
||||
|
||||
struct Pipeline0PointLight {
|
||||
vec3 pos;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
struct Pipeline0Spotlight {
|
||||
vec3 pos;
|
||||
vec3 dir;
|
||||
@ -29,11 +20,16 @@ struct Pipeline0Spotlight {
|
||||
float range;
|
||||
};
|
||||
|
||||
struct Pipeline0PointLight {
|
||||
vec3 pos;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
layout(std140, binding = 0) uniform Pipeline0UBO {
|
||||
int point_light_count;
|
||||
int spotlight_count;
|
||||
Pipeline0PointLight point_light_arr[120];
|
||||
Pipeline0Spotlight spotlight_arr [20];
|
||||
Pipeline0PointLight point_light_arr[20];
|
||||
Pipeline0Spotlight spotlight_arr [120];
|
||||
};
|
||||
|
||||
float get_intensity(float dist){
|
||||
@ -41,19 +37,18 @@ float get_intensity(float dist){
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec3 compressed_normal = texture(normal_map, tex).xyz;
|
||||
vec3 correct_norm_on_tang = compressed_normal * 2 - 1;
|
||||
vec3 norm = normalize(mat3(tang_U, tang_norm, tang_V) * correct_norm_on_tang);
|
||||
vec3 compressed_normal = texture(normal_map, fsin_tex).xyz;
|
||||
vec3 norm = compressed_normal * 2 - 1;
|
||||
vec3 diffuse_illumination = vec3(0);
|
||||
vec3 specular_illumination = vec3(0);
|
||||
for (int i = 0; i < point_light_count; i++) {
|
||||
Pipeline0PointLight lamp = point_light_arr[i];
|
||||
vec3 to_light = -pos + lamp.pos;
|
||||
vec3 to_light = -fsin_pos + lamp.pos;
|
||||
float dist = length(to_light);
|
||||
vec3 U = to_light / dist;
|
||||
diffuse_illumination += get_intensity(dist) * max(0, dot(U, norm)) * lamp.color;
|
||||
diffuse_illumination += get_intensity(dist) * max(0.02, dot(U, norm)) * lamp.color;
|
||||
vec3 A = reflect(-U, norm);
|
||||
vec3 to_cam = -pos+camera_pos;
|
||||
vec3 to_cam = -fsin_pos+camera_pos;
|
||||
float dist_to_cam = length(to_cam);
|
||||
vec3 B = to_cam / dist_to_cam;
|
||||
specular_illumination += get_intensity(dist) * pow(max(0, dot(A, B)), 32) * lamp.color;
|
||||
@ -61,8 +56,8 @@ void main(){
|
||||
for (int i = 0; i < spotlight_count; i++) {
|
||||
Pipeline0Spotlight lamp = spotlight_arr[i];
|
||||
}
|
||||
vec3 natural_color = texture(color_tex, tex).xyz;
|
||||
float specular_c = texture(specular_map, tex).x;
|
||||
vec3 color = natural_color * diffuse_illumination + specular_c * specular_illumination;
|
||||
vec3 natural_color = texture(color_tex, fsin_tex).xyz;
|
||||
// todo: add specular map texture
|
||||
vec3 color = natural_color * diffuse_illumination + 0.5 * specular_illumination;
|
||||
fin_color = vec4(color, 1);
|
||||
}
|
||||
20
src/l2/tests/r0/shaders/glsl/0/0.vert
Normal file
20
src/l2/tests/r0/shaders/glsl/0/0.vert
Normal file
@ -0,0 +1,20 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 pos;
|
||||
layout(location = 1) in vec2 tex;
|
||||
layout(location = 2) in mat4 model_t;
|
||||
/* 2 <- 3, 4, 5 */
|
||||
|
||||
layout(location = 0) out vec2 vsout_tex;
|
||||
layout(location = 1) out vec3 vsout_pos;
|
||||
|
||||
layout(push_constant, std430) uniform pc {
|
||||
mat4 proj_cam_t;
|
||||
};
|
||||
|
||||
void main(){
|
||||
vsout_tex = tex;
|
||||
vec4 real_pos = model_t * vec4(pos, 1);
|
||||
vsout_pos = real_pos.xyz;
|
||||
gl_Position = proj_cam_t * real_pos;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 norm;
|
||||
layout(location = 1) in vec3 color_off;
|
||||
layout(location = 1) in vec3 color_off;
|
||||
layout(location = 2) in vec3 color_on;
|
||||
layout(location = 3) in vec3 pos;
|
||||
|
||||
@ -11,11 +11,6 @@ layout(push_constant, std430) uniform pc {
|
||||
layout(offset = 64) vec3 camera_pos;
|
||||
};
|
||||
|
||||
struct Pipeline0PointLight {
|
||||
vec3 pos;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
struct Pipeline0Spotlight {
|
||||
vec3 pos;
|
||||
vec3 dir;
|
||||
@ -23,11 +18,16 @@ struct Pipeline0Spotlight {
|
||||
float range;
|
||||
};
|
||||
|
||||
struct Pipeline0PointLight {
|
||||
vec3 pos;
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
layout(std140, binding = 0) uniform Pipeline0UBO {
|
||||
int point_light_count;
|
||||
int spotlight_count;
|
||||
Pipeline0PointLight point_light_arr[120];
|
||||
Pipeline0Spotlight spotlight_arr [20];
|
||||
Pipeline0PointLight point_light_arr[20];
|
||||
Pipeline0Spotlight spotlight_arr [120];
|
||||
};
|
||||
|
||||
float get_intensity(float dist){
|
||||
@ -42,14 +42,15 @@ void main(){
|
||||
vec3 to_light = -pos + lamp.pos;
|
||||
float dist = length(to_light);
|
||||
vec3 U = to_light / dist;
|
||||
diffuse_illumination += get_intensity(dist) * max(0, dot(U, norm)) * lamp.color;
|
||||
diffuse_illumination += get_intensity(dist) * max(0.02, dot(U, norm)) * lamp.color;
|
||||
vec3 A = reflect(-U, norm);
|
||||
vec3 B = normalize(-pos+camera_pos);
|
||||
// specular_illumination += get_intensity(dist) * pow(max(0, dot(A, B)), 256) * lamp.color;
|
||||
specular_illumination += get_intensity(dist) * pow(max(0, dot(A, B)), 256) * lamp.color;
|
||||
}
|
||||
for (int i = 0; i < spotlight_count; i++) {
|
||||
Pipeline0Spotlight lamp = spotlight_arr[i];
|
||||
}
|
||||
vec3 color = color_off * diffuse_illumination + (0.05 + 0.45 * length(color_off)) * specular_illumination + color_on;
|
||||
vec3 color = color_off * diffuse_illumination + 0.5 * specular_illumination + color_on;
|
||||
fin_color = vec4(color, 1);
|
||||
// fin_color = vec4(length(norm) / 2, 0, 0, 1);
|
||||
}
|
||||
@ -1,14 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 pos;
|
||||
layout(location = 1) in vec3 color;
|
||||
layout(location = 2) in vec3 normal;
|
||||
layout(location = 1) in vec3 normal;
|
||||
|
||||
layout(location = 3) in mat4 model_t;
|
||||
/* 3 <- 4, 5, 6 */
|
||||
layout(location = 2) in mat4 model_t;
|
||||
/* 2 <- 3,4,5 */
|
||||
layout(location = 6) in vec3 color_off;
|
||||
layout(location = 7) in vec3 color_on;
|
||||
layout(location = 8) in mat3 normal_t;
|
||||
/* 8 <- 9, 10 */
|
||||
|
||||
layout(location = 0) out vec3 vsout_normal;
|
||||
layout(location = 1) out vec3 vsout_color_off;
|
||||
@ -20,8 +18,8 @@ layout(push_constant, std430) uniform pc {
|
||||
};
|
||||
|
||||
void main(){
|
||||
vsout_normal = normalize(normal_t * normal);
|
||||
vsout_color_off = color;
|
||||
vsout_normal = normal;
|
||||
vsout_color_off = color_off;
|
||||
vsout_color_on = color_on;
|
||||
vec4 real_pos = model_t * vec4(pos, 1);
|
||||
vsout_pos = real_pos.xyz;
|
||||
135
src/l2/tests/r0/textures/bitmap_converter.py
Executable file
135
src/l2/tests/r0/textures/bitmap_converter.py
Executable file
@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Convert between custom bottom‑up raw files (.r8g8b8a8 / .r8b8g8 / .r8 / .a8)
|
||||
and normal PNG using Pillow.
|
||||
|
||||
Format
|
||||
------
|
||||
uint32 width (little‑endian)
|
||||
uint32 height (little‑endian)
|
||||
pixel data rows bottom‑first:
|
||||
* .r8g8b8a8 : R G B A (4× uint8)
|
||||
* .r8b8g8 : R G B (3× uint8)
|
||||
* .r8 : R (1× uint8 <- grayscale)
|
||||
* .a8 : A (can convert from it, but can't convert to it)
|
||||
|
||||
CLI
|
||||
---
|
||||
raw -> png : python raw_png_conv.py to_png input.raw output.png
|
||||
png -> raw : python raw_png_conv.py to_raw input.png output.raw
|
||||
"""
|
||||
import argparse
|
||||
import struct
|
||||
from pathlib import Path
|
||||
from PIL import Image
|
||||
|
||||
# --------------------------------------------------------------------- #
|
||||
# Helpers
|
||||
# --------------------------------------------------------------------- #
|
||||
|
||||
|
||||
RAW_FORMATS = {
|
||||
".r8g8b8a8": {"pix_size": 4, "mode": "RGBA"},
|
||||
".r8g8b8": {"pix_size": 3, "mode": "RGB"},
|
||||
".r8": {"pix_size": 1, "mode": "L"},
|
||||
".a8": {"pix_size": 1, "mode": None}, # special-cased (alpha-only)
|
||||
}
|
||||
|
||||
|
||||
def get_fmt(path: Path):
|
||||
fmt = RAW_FORMATS.get(path.suffix.lower())
|
||||
if not fmt:
|
||||
raise ValueError(f"Unknown raw extension: {path.suffix}")
|
||||
return fmt
|
||||
|
||||
|
||||
def read_header_and_data(path: Path, pix_size: int):
|
||||
with path.open("rb") as f:
|
||||
header = f.read(8)
|
||||
if len(header) != 8:
|
||||
raise ValueError("File too short for header")
|
||||
w, h = struct.unpack("<II", header)
|
||||
expected = w * h * pix_size
|
||||
data = f.read()
|
||||
if len(data) != expected:
|
||||
raise ValueError(
|
||||
f"Pixel data length mismatch: expected {expected}, got {len(data)}"
|
||||
)
|
||||
return w, h, data
|
||||
|
||||
|
||||
def read_raw(path: Path) -> Image.Image:
|
||||
"""Load any supported raw file -> Pillow Image."""
|
||||
spec = get_fmt(path)
|
||||
w, h, data = read_header_and_data(path, spec["pix_size"])
|
||||
|
||||
row_len = w * spec["pix_size"]
|
||||
rows = [data[i : i + row_len] for i in range(0, len(data), row_len)]
|
||||
top_down = b"".join(reversed(rows)) # flip bottom‑up -> top‑down
|
||||
|
||||
# Special handling for .a8 (alpha-only -> LA with black color)
|
||||
if path.suffix.lower() == ".a8":
|
||||
big = bytearray(4 * len(top_down))
|
||||
big[3::4] = top_down
|
||||
big = bytes(big)
|
||||
return Image.frombytes("RGBA", (w, h), big)
|
||||
|
||||
# Normal cases can be constructed directly
|
||||
return Image.frombytes(spec["mode"], (w, h), top_down)
|
||||
|
||||
|
||||
def write_raw(img: Image.Image, path: Path) -> None:
|
||||
"""Write Pillow Image -> raw file chosen by path suffix."""
|
||||
ext = path.suffix.lower()
|
||||
spec = get_fmt(path)
|
||||
|
||||
if ext == ".a8":
|
||||
raise ValueError("Don't convert to .a8 format")
|
||||
|
||||
target_mode = spec["mode"]
|
||||
if img.mode != target_mode:
|
||||
img = img.convert(target_mode)
|
||||
|
||||
w, h = img.size
|
||||
data = img.tobytes()
|
||||
row_len = w * spec["pix_size"]
|
||||
rows = [data[i : i + row_len] for i in range(0, len(data), row_len)]
|
||||
bottom_first = b"".join(reversed(rows)) # top‑down -> bottom‑up
|
||||
|
||||
with path.open("wb") as f:
|
||||
f.write(struct.pack("<II", w, h))
|
||||
f.write(bottom_first)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------- #
|
||||
# CLI
|
||||
# --------------------------------------------------------------------- #
|
||||
|
||||
def to_png(src: Path, dst: Path):
|
||||
read_raw(src).save(dst, "PNG")
|
||||
|
||||
|
||||
def to_raw(src: Path, dst: Path):
|
||||
write_raw(Image.open(src), dst)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="Convert raw <-> PNG")
|
||||
sub = ap.add_subparsers(dest="cmd", required=True)
|
||||
p_png = sub.add_parser("to_png", help="raw -> png")
|
||||
p_png.add_argument("src", type=Path)
|
||||
p_png.add_argument("dst", type=Path)
|
||||
p_raw = sub.add_parser("to_raw", help="png -> raw")
|
||||
p_raw.add_argument("src", type=Path)
|
||||
p_raw.add_argument("dst", type=Path)
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.cmd == "to_png":
|
||||
to_png(args.src, args.dst)
|
||||
else:
|
||||
to_raw(args.src, args.dst)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
@ -105,7 +105,7 @@ const LizaInstrument_Table LizaInstrument_Table_WeirdGuitar = {
|
||||
BoxLizaInstrument BoxLizaInstrument_from_WeirdGuitar(WeirdGuitar obj) {
|
||||
void* mem = safe_malloc(sizeof(WeirdGuitar));
|
||||
memcpy(mem, &obj, sizeof(WeirdGuitar));
|
||||
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_WeirdGuitar};
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_WeirdGuitar};
|
||||
}
|
||||
|
||||
/* ElectroBlaster which produces AmplitudeModulationSound */
|
||||
@ -192,7 +192,7 @@ const LizaInstrument_Table LizaInstrument_Table_AMKeys = {
|
||||
BoxLizaInstrument BoxLizaInstrument_from_AMKeys(AMKeys obj) {
|
||||
void* mem = safe_malloc(sizeof(AMKeys));
|
||||
memcpy(mem, &obj, sizeof(AMKeys));
|
||||
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_AMKeys};
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_AMKeys};
|
||||
}
|
||||
|
||||
/* FMKeys which produces FrequencyModulationSound */
|
||||
@ -278,7 +278,7 @@ const LizaInstrument_Table LizaInstrument_Table_FMKeys = {
|
||||
BoxLizaInstrument BoxLizaInstrument_from_FMKeys(FMKeys obj) {
|
||||
void* mem = safe_malloc(sizeof(FMKeys));
|
||||
memcpy(mem, &obj, sizeof(FMKeys));
|
||||
return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_FMKeys};
|
||||
return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_FMKeys};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -100,8 +100,7 @@ static void r2a_app_h_pw_stream_process(void *ug){
|
||||
return;
|
||||
}
|
||||
struct spa_buffer *buf = b->buffer;
|
||||
assert(buf->n_datas >= 1);
|
||||
const uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS;
|
||||
uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS;
|
||||
uint32_t n_frames = buf->datas[0].maxsize / stride;
|
||||
if (b->requested)
|
||||
n_frames = SPA_MIN(b->requested, n_frames);
|
||||
@ -516,12 +515,12 @@ static void r2a_app_h_wl_keyboard_key(
|
||||
};
|
||||
if (state->selected_instrument < state->instruments.len) {
|
||||
// todo: add box to ref and box to mref methods
|
||||
BoxLizaInstrument* instrument = &VecMyInstrument_mat(&state->instruments, state->selected_instrument)->liza;
|
||||
const BoxLizaInstrument* instrument = &VecMyInstrument_at(&state->instruments, state->selected_instrument)->liza;
|
||||
for (int i = 0; i < ARRAY_SIZE(octave); i++) {
|
||||
if (keysym == octave[i] && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||
safe_pthread_mutex_lock(&state->audio_thread_bridge->mut);
|
||||
VecBoxLizaSound_append(&state->audio_thread_bridge->cmd.new_sounds,
|
||||
BoxLizaInstrument_ding(instrument, 440 * pow(2, (double)i / 12), 0.9));
|
||||
instrument->t->ding(instrument->m, 440 * pow(2, (double)i / 12), 0.9));
|
||||
safe_pthread_mutex_unlock(&state->audio_thread_bridge->mut);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ void BoxLizaSound_drop(BoxLizaSound self) {
|
||||
free(self.m);
|
||||
}
|
||||
|
||||
#include "../../../../gen/l1/eve/r2/VecBoxLizaSound.h"
|
||||
#include "../../../../gen/l2/eve/r2/VecBoxLizaSound.h"
|
||||
|
||||
typedef struct {
|
||||
bool stop;
|
||||
|
||||
@ -1,232 +0,0 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sound/asound.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define DESIRED_SAMPLE_RATE 44100
|
||||
#define DESIRED_CHANNELS 2 // Prefer stereo, as mono often not supported on hardware
|
||||
#define DESIRED_PERIOD_SIZE 1024
|
||||
#define DESIRED_PERIODS 4
|
||||
#define FORMAT SNDRV_PCM_FORMAT_S16_LE
|
||||
#define DURATION 5 // seconds
|
||||
#define BYTES_PER_SAMPLE 2
|
||||
|
||||
int main() {
|
||||
int card = -1, device = -1;
|
||||
FILE *proc = fopen("/proc/asound/pcm", "r");
|
||||
if (!proc) {
|
||||
perror("Failed to open /proc/asound/pcm");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Opened /proc/asound/pcm\n");
|
||||
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), proc)) {
|
||||
if (strstr(line, "playback")) {
|
||||
sscanf(line, "%02d-%02d", &card, &device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(proc);
|
||||
|
||||
if (card < 0 || device < 0) {
|
||||
fprintf(stderr, "No playback devices found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char devname[64];
|
||||
snprintf(devname, sizeof(devname), "/dev/snd/pcmC%dD%dp", card, device);
|
||||
|
||||
int fd = open(devname, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Failed to open PCM device");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Opened device\n");
|
||||
|
||||
struct snd_pcm_hw_params params;
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
// Initialize to full possible ranges for refinement
|
||||
int i;
|
||||
for (i = SNDRV_PCM_HW_PARAM_FIRST_MASK; i <= SNDRV_PCM_HW_PARAM_LAST_MASK; i++) {
|
||||
struct snd_mask *mask = ¶ms.masks[i - SNDRV_PCM_HW_PARAM_FIRST_MASK];
|
||||
mask->bits[0] = ~0U;
|
||||
mask->bits[1] = ~0U;
|
||||
}
|
||||
for (i = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; i <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; i++) {
|
||||
struct snd_interval *interval = ¶ms.intervals[i - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
interval->min = 0;
|
||||
interval->max = ~0U;
|
||||
interval->openmin = interval->openmax = 0;
|
||||
interval->integer = 0;
|
||||
}
|
||||
params.rmask = ~0U;
|
||||
params.cmask = 0;
|
||||
params.info = ~0U;
|
||||
|
||||
// Refine to hardware-supported ranges
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, ¶ms) < 0) {
|
||||
perror("Failed initial HW_REFINE");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Refined hw params\n");
|
||||
|
||||
// Set access to RW_INTERLEAVED if supported
|
||||
struct snd_mask *access_mask = ¶ms.masks[SNDRV_PCM_HW_PARAM_ACCESS - SNDRV_PCM_HW_PARAM_FIRST_MASK];
|
||||
unsigned int access_bit = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
|
||||
if (!(access_mask->bits[access_bit / 32] & (1U << (access_bit % 32)))) {
|
||||
fprintf(stderr, "RW_INTERLEAVED access not supported\n");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
memset(access_mask, 0, sizeof(*access_mask));
|
||||
access_mask->bits[access_bit / 32] |= (1U << (access_bit % 32));
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_ACCESS);
|
||||
|
||||
// Set format to S16_LE if supported
|
||||
struct snd_mask *format_mask = ¶ms.masks[SNDRV_PCM_HW_PARAM_FORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK];
|
||||
unsigned int format_bit = FORMAT;
|
||||
if (!(format_mask->bits[format_bit / 32] & (1U << (format_bit % 32)))) {
|
||||
fprintf(stderr, "S16_LE format not supported\n");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
memset(format_mask, 0, sizeof(*format_mask));
|
||||
format_mask->bits[format_bit / 32] |= (1U << (format_bit % 32));
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_FORMAT);
|
||||
|
||||
// Set channels to nearest supported (prefer DESIRED_CHANNELS)
|
||||
struct snd_interval *channels_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_CHANNELS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
unsigned int channels = DESIRED_CHANNELS;
|
||||
if (channels < channels_int->min) channels = channels_int->min;
|
||||
if (channels > channels_int->max) channels = channels_int->max;
|
||||
if (channels != DESIRED_CHANNELS) {
|
||||
fprintf(stderr, "Adjusted channels to %u (hardware range: %u-%u)\n", channels, channels_int->min, channels_int->max);
|
||||
}
|
||||
channels_int->min = channels_int->max = channels;
|
||||
channels_int->integer = 1;
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
|
||||
// Set sample rate to nearest supported
|
||||
struct snd_interval *rate_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
unsigned int sample_rate = DESIRED_SAMPLE_RATE;
|
||||
if (sample_rate < rate_int->min) sample_rate = rate_int->min;
|
||||
if (sample_rate > rate_int->max) sample_rate = rate_int->max;
|
||||
if (sample_rate != DESIRED_SAMPLE_RATE) {
|
||||
fprintf(stderr, "Adjusted sample rate to %u Hz (hardware range: %u-%u)\n", sample_rate, rate_int->min, rate_int->max);
|
||||
}
|
||||
rate_int->min = rate_int->max = sample_rate;
|
||||
rate_int->integer = 1;
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_RATE);
|
||||
|
||||
// Set period size to nearest supported
|
||||
struct snd_interval *period_size_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_PERIOD_SIZE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
unsigned int period_size = DESIRED_PERIOD_SIZE;
|
||||
if (period_size < period_size_int->min) period_size = period_size_int->min;
|
||||
if (period_size > period_size_int->max) period_size = period_size_int->max;
|
||||
if (period_size != DESIRED_PERIOD_SIZE) {
|
||||
fprintf(stderr, "Adjusted period size to %u frames (hardware range: %u-%u)\n", period_size, period_size_int->min, period_size_int->max);
|
||||
}
|
||||
period_size_int->min = period_size_int->max = period_size;
|
||||
period_size_int->integer = 1;
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
|
||||
|
||||
// Set periods (less strict, clamp to range)
|
||||
struct snd_interval *periods_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_PERIODS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
|
||||
unsigned int periods = DESIRED_PERIODS;
|
||||
if (periods < periods_int->min) periods = periods_int->min;
|
||||
if (periods > periods_int->max) periods = periods_int->max;
|
||||
if (periods != DESIRED_PERIODS) {
|
||||
fprintf(stderr, "Adjusted periods to %u (hardware range: %u-%u)\n", periods, periods_int->min, periods_int->max);
|
||||
}
|
||||
periods_int->min = periods_int->max = periods;
|
||||
periods_int->integer = 1;
|
||||
params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
|
||||
// Refine again with desired values to confirm
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, ¶ms) < 0) {
|
||||
perror("Failed to refine desired HW params");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Refined hw params the last time\n");
|
||||
|
||||
// Now apply the parameters
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms) < 0) {
|
||||
perror("Failed to set HW params");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("HW params set\n");
|
||||
|
||||
if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0) < 0) {
|
||||
perror("Failed to prepare PCM");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Prepared\n");
|
||||
|
||||
// Generate and play sine wave
|
||||
size_t frame_size = channels * BYTES_PER_SAMPLE;
|
||||
short *buffer = malloc(period_size * frame_size);
|
||||
if (!buffer) {
|
||||
perror("Failed to allocate buffer");
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned long total_frames = (unsigned long)sample_rate * DURATION;
|
||||
unsigned long frames_written = 0;
|
||||
double phase = 0.0;
|
||||
const double freq = 440.0; // Hz
|
||||
const double phase_inc = 2.0 * M_PI * freq / sample_rate;
|
||||
|
||||
while (frames_written < total_frames) {
|
||||
size_t frames_to_write = period_size;
|
||||
if (frames_written + frames_to_write > total_frames) {
|
||||
frames_to_write = total_frames - frames_written;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < frames_to_write; ++j) {
|
||||
short sample = (short)(32767.0 * sin(phase));
|
||||
for (unsigned int ch = 0; ch < channels; ++ch) {
|
||||
buffer[j * channels + ch] = sample;
|
||||
}
|
||||
phase += phase_inc;
|
||||
if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI;
|
||||
}
|
||||
|
||||
ssize_t bytes_written = write(fd, buffer, frames_to_write * frame_size);
|
||||
printf("bytes written = %lu\n", bytes_written);
|
||||
if (bytes_written < 0) {
|
||||
if (errno == EPIPE) {
|
||||
// Underrun: recover
|
||||
ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0);
|
||||
continue;
|
||||
}
|
||||
perror("Write failed");
|
||||
break;
|
||||
}
|
||||
|
||||
frames_written += bytes_written / frame_size;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
// Drain remaining data
|
||||
ioctl(fd, SNDRV_PCM_IOCTL_DRAIN, 0);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
@ -608,7 +608,7 @@ int main() {
|
||||
}
|
||||
printf("Finished!\n");
|
||||
vkDeviceWaitIdle(state.device);
|
||||
// todo: destroy instance and all the crrp
|
||||
// todo: destroy instance and all the shit
|
||||
|
||||
|
||||
if (state.wl_callback)
|
||||
|
||||
1
src/l2/tests/r3/shaders/glsl/0/0.frag
Normal file
1
src/l2/tests/r3/shaders/glsl/0/0.frag
Normal file
@ -0,0 +1 @@
|
||||
#version 450
|
||||
1
src/l2/tests/r3/shaders/glsl/0/0.vert
Normal file
1
src/l2/tests/r3/shaders/glsl/0/0.vert
Normal file
@ -0,0 +1 @@
|
||||
#version 450
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user