Compare commits

...

6 Commits

Author SHA1 Message Date
Maddie Busig
8a05e20c33 Fix rotations and add second token value
Rotations only took cosine of the angle, but this is not enough to
determine all possible angles. create_rotation now takes sin of the
angle too. Modified tokens to have a second value to accomodate this
change
2025-05-06 23:55:50 -07:00
Maddie Busig
28c606643c Configure ETL to throw exceptions 2025-05-06 22:53:10 -07:00
Maddie Busig
722a7eb202 Move token marking identifier into token_t, remove marking rules
This has the side effect that each token can only have one mark assigned
to it.
2025-05-06 22:51:52 -07:00
Maddie Busig
83130ba7bd Fix rotation usage not using cos of angle
Storing the cosine of the angle inside the token allows for faster
rotation matrix computation. Because the rotation matrix uses the
sin/cos of the angle, we can precompute the cosine and find the sine
quickly using cosx^2+sinx^2=1. This means we only need to compute the
sin/cos once, and we can potentially precompute it at compile time.
2025-05-06 22:28:44 -07:00
Maddie Busig
8a99a5e09e Add create_rotation helper function
Rotation matrix construction not implemented in MTL yet
2025-05-06 22:24:12 -07:00
Maddie Busig
651596f76f Add beginning of generator declarations and example usage 2025-05-06 02:53:31 -07:00
4 changed files with 90 additions and 52 deletions

View File

@ -16,10 +16,13 @@ if (EXCEPTIONS STREQUAL OFF)
message("NO RTTI")
endif()
add_compile_definitions(ETL_THROW_EXCEPTIONS)
add_link_options("-Wl,--print-memory-usage")
add_executable(${PROJECT_NAME})
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 17)
# Normal source and header files
file(GLOB proj_sources LIST_DIRECTORIES false CONFIGURE_DEPENDS src/*.cpp src/*.c src/*.s)
set(proj_include "include")

View File

@ -6,6 +6,10 @@
#include <mtl/fixed.hpp>
#include <mtl/vec.hpp>
#include <mtl/mat.hpp>
#include <mtl/exception.hpp>
// TODO: Implement in MTL and create version that doesn't need cos of the angle
mtl::mat<2, 2> create_rotation(mtl::fixed angle_cos, mtl::fixed angle_sin);
namespace fractal {
@ -13,15 +17,15 @@ constexpr size_t g_max_tokens = 16;
constexpr size_t g_max_groups = 8;
constexpr size_t g_max_wgroups = 4;
constexpr size_t g_max_branch_rules = 8;
constexpr size_t g_max_mark_rules = 4;
constexpr size_t g_max_cgroup_tokens = 16;
constexpr size_t g_max_wgroup_weights = 8;
constexpr size_t g_max_match_groups = 8;
constexpr size_t g_max_match_wgroups = 4;
using token_id_t = uint32_t;
using group_id_t = uint32_t;
using weighted_group_id_t = uint32_t;
using branch_rule_id_t = uint32_t;
using mark_rule_id_t = uint32_t;
enum class token_type_e {
empty,
@ -32,6 +36,8 @@ enum class token_type_e {
struct token_t {
token_type_e m_type = token_type_e::empty;
mtl::fixed m_value;
mtl::fixed m_value2;
uint32_t m_mark;
};
struct group_characteristic_t {
@ -56,7 +62,7 @@ struct weighted_leaf_t {
mtl::mat<2, 2> m_orientation;
};
struct group_t {
struct group_output_t {
static constexpr size_t g_max_child_leafs = 16;
static constexpr size_t g_max_child_markers = 8;
@ -64,6 +70,11 @@ struct group_t {
etl::vector<marker_t, g_max_child_markers> m_child_markers;
};
struct token_match_t {
etl::vector<group_id_t, g_max_match_groups> m_groups;
etl::vector<weighted_group_id_t, g_max_match_wgroups> m_wgroups;
};
struct weighted_group_t {
etl::vector<group_id_t, g_max_wgroup_weights> m_groups;
etl::vector<uint32_t, g_max_wgroup_weights> m_weights;
@ -81,11 +92,6 @@ struct branch_rule_t {
} m_group;
};
struct mark_rule_t {
token_id_t m_match;
uint32_t m_tag;
};
class ruleset_t {
private:
etl::vector<token_t, g_max_tokens> m_tokens;
@ -93,7 +99,6 @@ private:
etl::vector<weighted_group_t, g_max_wgroups> m_weighted_groups;
etl::vector<branch_rule_t, g_max_branch_rules> m_branch_rules;
etl::vector<mark_rule_t, g_max_mark_rules> m_mark_rules;
public:
/**
@ -118,7 +123,7 @@ public:
*
* @exception @c mtl::length_error if the maximum number of tokens is reached
*/
token_id_t add_token(token_type_e type, mtl::fixed value = 0);
token_id_t add_token(token_type_e type, mtl::fixed value = 0, mtl::fixed value2 = 0, uint32_t mark = 0);
/**
* @brief Checks if the maximum number of group characteristics has been reached
@ -214,29 +219,39 @@ public:
*/
branch_rule_id_t add_branch_rule_weighted(token_id_t match, weighted_group_id_t wgroup);
/**
* @brief Checks if the maximum number of mark rules has been reached
*
* @ret @c true if the number of mark rules in the ruleset equals @c g_max_mark_rules, @c false otherwise
*/
bool mark_rules_full() const {
return m_mark_rules.full();
}
/** @brief Add a new marking rule to the ruleset
};
class generator_t {
etl::vector<weighted_group_t, g_max_wgroups> m_weighted_groups;
etl::vector<group_output_t, g_max_groups> m_group_outputs;
etl::vector<token_match_t, g_max_tokens> m_token_matches;
group_id_t m_axiom;
uint32_t m_gen_num;
public:
generator_t(const ruleset_t& ruleset);
/**
* @brief Steps one generation, outputting generated markers
*
* Mark rules describe what tokens should have their positions output
* each generation. If a token has a match, its position and a tag is output.
* @tparam CONTAINER_T Container type of @c marker_t that supplies an @c insert member
* function taking an iterator and value, @c size , and @c max_size functions
*
* @param match Token to match and mark
* @param tag Marking identifier, does not need to be unique
* @param out_markers Reference to a container to append generated markers to
*
* @ret @c mark_rule_id_t of the newly added mark rule
* @ret false if there is not enough room for the child leafs (internally)
* or there is not enough room for the generated markers in @p out_markers, true otherwise
*
* @exception @c mtl::invalid_argument if an invalid token was supplied
* @exception @c mtl::length_error if the maximum number of mark rules was reached
* Steps one generation of the fractal, and appends any child markers of
* the current generation to @p out_markers. If there is not enough room
* for all of the child markers, @p out_markers is unmodified.
*/
mark_rule_id_t add_mark_rule(token_id_t match, uint32_t tag);
template <typename CONTAINER_T>
bool step_generation(CONTAINER_T& out_markers);
uint32_t generation_num() const { return m_gen_num; }
};
#if 0

View File

@ -2,18 +2,32 @@
#include <mtl/exception.hpp>
#include <mtl/log.hpp>
#include <cmath>
using mtl::endl;
namespace log = mtl::log;
namespace mlog = mtl::log;
using mtl::fixed;
using mtl::vec2;
using mtl::mat;
mtl::mat<2, 2> create_rotation(mtl::fixed angle_cos, mtl::fixed angle_sin) {
return mat<2, 2>({
{ angle_cos, -angle_sin },
{ angle_sin, angle_cos }
});
}
namespace fractal {
token_id_t ruleset_t::add_token(token_type_e type, mtl::fixed value) {
// ---------- RULESET ----------
token_id_t ruleset_t::add_token(token_type_e type, mtl::fixed value, mtl::fixed value2, uint32_t mark) {
if (m_tokens.full()) {
throw mtl::length_error();
}
token_t tok { .m_type = type, .m_value = value };
token_t tok { .m_type = type, .m_value = value, .m_value2 = value2, .m_mark = mark};
m_tokens.push_back(tok);
return m_tokens.size() - 1;
@ -96,19 +110,6 @@ branch_rule_id_t ruleset_t::add_branch_rule_weighted(token_id_t match, weighted_
return m_branch_rules.size() - 1;
}
mark_rule_id_t ruleset_t::add_mark_rule(token_id_t match, uint32_t tag) {
if (!valid_token(match)) {
throw mtl::invalid_argument();
}
mark_rule_t rule {
.m_match = match,
.m_tag = tag
};
m_mark_rules.push_back(rule);
return m_mark_rules.size() - 1;
}
#if 0
token_id_t generator_t::add_token(token_type_e type, mtl::fixed value) {

View File

@ -14,6 +14,15 @@ int main(void) {
REG_DISPCNT = DCNT_MODE3 | DCNT_BG2;
log::debug << "Hello world!" << mtl::endl;
constexpr float cos_PI_2 = std::cos(M_PI_2);
constexpr float cos_PI_4 = std::cos(M_PI_4);
constexpr float sin_PI_2 = std::sin(M_PI_2);
constexpr float sin_PI_4 = std::sin(M_PI_4);
fixed cos_PI_2_fx = cos_PI_2;
fixed cos_PI_4_fx = cos_PI_4;
fixed sin_PI_2_fx = sin_PI_2;
fixed sin_PI_4_fx = sin_PI_4;
ruleset_t rules;
@ -21,16 +30,16 @@ int main(void) {
fixed branch_angle = M_PI_4;
token_id_t walk_petal_length = rules.add_token(token_type_e::walk, 8);
token_id_t walk_petal_side = rules.add_token(token_type_e::walk, 4);
token_id_t walk_petal_side = rules.add_token(token_type_e::walk, 2);
token_id_t rotate_axiom = rules.add_token(token_type_e::rotate, M_PI_2);
token_id_t rotate_petal = rules.add_token(token_type_e::rotate, M_PI_2);
token_id_t rotate_branchr = rules.add_token(token_type_e::rotate, branch_angle);
token_id_t rotate_branchl = rules.add_token(token_type_e::rotate, branch_angle * -2);
token_id_t rotate_axiom = rules.add_token(token_type_e::rotate, cos_PI_2_fx, sin_PI_2_fx);
token_id_t rotate_petal = rules.add_token(token_type_e::rotate, cos_PI_2_fx, -sin_PI_2_fx);
token_id_t rotate_branchr = rules.add_token(token_type_e::rotate, cos_PI_4_fx, -sin_PI_4_fx);
token_id_t rotate_branchl = rules.add_token(token_type_e::rotate, cos_PI_2_fx, sin_PI_2_fx);
token_id_t branch = rules.add_token(token_type_e::empty);
token_id_t petal = rules.add_token(token_type_e::empty);
token_id_t mark = rules.add_token(token_type_e::empty);
token_id_t mark = rules.add_token(token_type_e::empty, 0, 0, 1);
log::info << "Added tokens" << endl;
@ -42,14 +51,13 @@ int main(void) {
etl::vector branch_chr{ petal, rotate_branchr, branch, rotate_branchl, branch };
group_id_t branch_grp = rules.add_group_characteristic(branch_chr);
etl::vector petal_chr{ mark, walk_petal_length, mark, rotate_petal, walk_petal_length, mark };
etl::vector petal_chr{ mark, walk_petal_length, mark, rotate_petal, walk_petal_side, mark };
group_id_t petal_grp = rules.add_group_characteristic(petal_chr);
log::info << "Added group characteristics" << endl;
rules.add_branch_rule(branch, branch_grp);
rules.add_branch_rule(petal, petal_grp);
rules.add_mark_rule(mark, 1);
log::info << "Added rules" << endl;
log::info << "Finished configuring ruleset" << endl;
@ -58,6 +66,17 @@ int main(void) {
return 0;
}
generator_t gen(rules);
etl::vector<marker_t, 100> output;
while (gen.step_generation(output)) {
log::debug << "Stepped generation" << gen.generation_num() << endl;
for (const marker_t& m : output) {
log::debug << ' ' << m.m_id << ", " << m.m_pos << endl;
}
}
while (true) {
vid_vsync();
}