Compare commits

..

1 Commits

Author SHA1 Message Date
1234debf38 I am tired already 2025-10-08 13:28:59 +03:00
120 changed files with 6230 additions and 6038640 deletions

5
.gitignore vendored
View File

@ -13,7 +13,4 @@ vgcore.*
*_TEMPLATE.png
/out
GRAPH*.gv
GRAPH*.png
SICK_JOKE*
*.hi
*_stub.h
GRAPH*.png

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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>`,

View 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
View 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))
]

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -3,7 +3,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
typedef uint8_t U8;
typedef uint16_t U16;

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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()

View File

@ -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");

View File

@ -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"

View File

@ -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();

View File

@ -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();

View File

@ -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;

View File

@ -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());
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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"));
}

View File

@ -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

View File

@ -1,7 +0,0 @@
#ifndef prototype1_src_l2_gui_label_h
#define prototype1_src_l2_gui_label_h
#include "../lucy/glyph_render.h"
#endif

View File

@ -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

View File

@ -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"

View File

@ -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) */

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@

View 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

View File

@ -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;
}
}

View File

@ -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};
}

View File

@ -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

View File

@ -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, &region);
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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
// }

View File

@ -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;
}

View File

@ -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"));
}

View File

@ -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
View File

@ -0,0 +1 @@
#include "../../../../l1/core/util.h"

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
View 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
View 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

View 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;
}

View File

@ -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);
}

View 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;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""
Convert between custom bottomup raw files (.r8g8b8a8 / .r8b8g8 / .r8 / .a8)
and normal PNG using Pillow.
Format
------
uint32 width (littleendian)
uint32 height (littleendian)
pixel data rows bottomfirst:
* .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 bottomup -> topdown
# 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)) # topdown -> bottomup
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()

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

@ -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};
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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(&params, 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 = &params.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 = &params.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, &params) < 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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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, &params) < 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, &params) < 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;
}

View File

@ -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)

View File

@ -0,0 +1 @@
#version 450

View File

@ -0,0 +1 @@
#version 450

Some files were not shown because too many files have changed in this diff Show More