Compare commits
8 Commits
d95602fecd
...
193aaad305
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
193aaad305 | ||
|
|
6c309a0265 | ||
|
|
faf9f7af3b | ||
|
|
513d000e11 | ||
|
|
32e0b9280f | ||
|
|
ba5f3206bf | ||
|
|
22f87a9c9e | ||
|
|
924bd2b94c |
@ -17,6 +17,9 @@ if (EXCEPTIONS STREQUAL OFF)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(ETL_THROW_EXCEPTIONS)
|
||||
add_compile_options("-fstack-usage")
|
||||
add_compile_options("-fcallgraph-info=su")
|
||||
add_compile_options("-Wstack-usage=1000")
|
||||
add_link_options("-Wl,--print-memory-usage")
|
||||
|
||||
add_executable(${PROJECT_NAME})
|
||||
|
||||
@ -21,6 +21,8 @@ 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;
|
||||
constexpr size_t g_max_leafs = 128;
|
||||
constexpr size_t g_max_wleafs = 128;
|
||||
|
||||
using token_id_t = uint32_t;
|
||||
using group_id_t = uint32_t;
|
||||
@ -251,12 +253,46 @@ 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;
|
||||
bool m_has_ruleset = false;
|
||||
group_id_t m_axiom;
|
||||
mtl::fixed m_scale = 1;
|
||||
|
||||
etl::vector<leaf_t, g_max_leafs> m_leaf_buf1;
|
||||
etl::vector<leaf_t, g_max_leafs> m_leaf_buf2;
|
||||
|
||||
etl::vector<weighted_leaf_t, g_max_leafs> m_wleaf_buf1;
|
||||
etl::vector<weighted_leaf_t, g_max_leafs> m_wleaf_buf2;
|
||||
|
||||
// Need to use pointers betwen etl::ivector does not implement swap :(
|
||||
etl::ivector<leaf_t>* m_leafs_prev = &m_leaf_buf1;
|
||||
etl::ivector<leaf_t>* m_leafs_cur = &m_leaf_buf2;
|
||||
|
||||
etl::ivector<weighted_leaf_t>* m_wleafs_prev = &m_wleaf_buf1;
|
||||
etl::ivector<weighted_leaf_t>* m_wleafs_cur = &m_wleaf_buf2;
|
||||
|
||||
uint32_t m_gen_num = 0;
|
||||
|
||||
void parse_group_characteristic(group_id_t gid, group_output_t& output, const ruleset_t& ruleset);
|
||||
|
||||
void swap_buffers();
|
||||
void clear_current_buffers();
|
||||
void clear_previous_buffers();
|
||||
void clear_all_buffers();
|
||||
|
||||
bool generate_group(group_id_t gid, mtl::vec2 pos, mtl::mat<2, 2> orient, etl::ivector<marker_t>& out_markers);
|
||||
bool generate_axiom(etl::ivector<marker_t>& out_markers);
|
||||
bool generate_leafs(etl::ivector<marker_t>& out_markers);
|
||||
|
||||
public:
|
||||
generator_t(const ruleset_t& ruleset);
|
||||
generator_t() : m_axiom(0) { }
|
||||
generator_t(const ruleset_t& ruleset) : m_axiom(0) {
|
||||
parse_ruleset(ruleset);
|
||||
}
|
||||
|
||||
void set_scale(mtl::fixed scale) { m_scale = scale; }
|
||||
|
||||
void parse_ruleset(const ruleset_t& ruleset);
|
||||
|
||||
/**
|
||||
* @brief Steps one generation, outputting generated markers
|
||||
@ -273,229 +309,11 @@ public:
|
||||
* the current generation to @p out_markers. If there is not enough room
|
||||
* for all of the child markers, @p out_markers is unmodified.
|
||||
*/
|
||||
template <typename CONTAINER_T>
|
||||
bool step_generation(CONTAINER_T& out_markers);
|
||||
bool step_generation(etl::ivector<marker_t>& out_markers);
|
||||
|
||||
uint32_t generation_num() const { return m_gen_num; }
|
||||
};
|
||||
|
||||
#if 0
|
||||
class generator_t {
|
||||
private:
|
||||
static constexpr size_t g_max_groups = 32;
|
||||
static constexpr size_t g_max_weighted_groups = 32;
|
||||
static constexpr size_t g_max_tokens = 32;
|
||||
static constexpr size_t g_max_leafs_per_gen = 1024; // Maximum leafs per generation
|
||||
static constexpr size_t g_max_rules_basic = 16;
|
||||
static constexpr size_t g_max_rules_marking = 4;
|
||||
|
||||
// We are creating two buffers are leafs. One for the current generation
|
||||
// and one for the next generation. These will be accessed through current/next
|
||||
// ivectors that will point to different buffers as they are swapped.
|
||||
etl::vector<leaf_t, g_max_leafs_per_gen> m_leaf_buf1;
|
||||
etl::vector<leaf_t, g_max_leafs_per_gen> m_leaf_buf2;
|
||||
|
||||
etl::vector<token_t, g_max_tokens> m_tokens;
|
||||
|
||||
etl::vector<group_characteristic_t, g_max_groups> m_group_characteristics;
|
||||
etl::vector<group_t, g_max_groups> m_groups;
|
||||
etl::vector<weighted_group_t, g_max_weighted_groups> m_weighted_groups;
|
||||
|
||||
etl::vector<branch_rule_basic_t, g_max_rules_basic> m_basic_branch_rules;
|
||||
etl::vector<branch_rule_marking_t, g_max_rules_marking> m_marking_branch_rules;
|
||||
|
||||
etl::ivector<leaf_t>* m_leafs_cur;
|
||||
etl::ivector<leaf_t>* m_leafs_next;
|
||||
|
||||
bool m_processed;
|
||||
uint32_t m_generation;
|
||||
|
||||
mtl::fixed m_scale_factor;
|
||||
|
||||
weighted_group_id_t m_axiom;
|
||||
mtl::vec2 m_init_position;
|
||||
mtl::fixed m_init_orientation;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
generator_t() noexcept :
|
||||
m_leafs_cur(&m_leaf_buf1),
|
||||
m_leafs_next(&m_leaf_buf2),
|
||||
m_axiom(0),
|
||||
m_generation(0),
|
||||
m_scale_factor(1),
|
||||
m_processed(false) {}
|
||||
|
||||
/**
|
||||
* @brief Add new token variable that can be used in this generator's group characteristics.
|
||||
*
|
||||
* @param type Type of the token to add
|
||||
* @param value Value of the token. Unused if @p type is @c token_type_e::generate. Defaults to 0
|
||||
*
|
||||
* @ret @c token_id_t of the newly added token, local to this generator.
|
||||
*
|
||||
* @pre preprocess() has not been called on this generator.
|
||||
*
|
||||
* @exception mtl::system_error If the generator has already been preprocessed.
|
||||
* @exception mtl::invalid_argument If the given token type is invalid.
|
||||
* @exception mtl::length_error If the maximum number of tokens is reached.
|
||||
*/
|
||||
token_id_t add_token(token_type_e type, mtl::fixed value = 0);
|
||||
|
||||
/**
|
||||
* @brief Add new group charateristic.
|
||||
*
|
||||
* After all tokens, groups, and rules have been added, the generator's groups
|
||||
* must be processed by calling preprocess(). Once this is done, no new
|
||||
* groups may be added. If an exception occurs, no data is modified.
|
||||
*
|
||||
* @param factor The number of times the group is repeated. Treats the group as if @p tokens was repeated @p factor number of times.
|
||||
* @param tokens @c etl::ivector of @token_id_t that describe how the group functions. Processed in order, front to back.
|
||||
*
|
||||
* @ret @c group_id_t of the newly added group, local to this generator.
|
||||
*
|
||||
* @pre preprocess() has not been called on this generator.
|
||||
*
|
||||
* @exception mtl::system_error If the generator has already been preprocessed.
|
||||
* @exception mtl::invalid_argument If an invalid token was encountered.
|
||||
* @exception mtl::length_error If the maximum number of groups is reached.
|
||||
*/
|
||||
group_id_t add_group_characteristic(uint32_t factor, const etl::ivector<token_id_t>& tokens);
|
||||
/**
|
||||
* @overload
|
||||
*
|
||||
* Convience overload, defaulting to a group with factor 1.
|
||||
*/
|
||||
group_id_t add_group_characteristic(const etl::ivector<token_id_t>& tokens);
|
||||
|
||||
/**
|
||||
* @brief Add a weighted group to the generator.
|
||||
*
|
||||
* Adds weighted group of groups, where each subgroup has a
|
||||
* <tt>(weight) / (total weight)</tt> chance of being selected. Weights
|
||||
* are represented as @c uint32_t. If an exception occurs, no data is modified.
|
||||
*
|
||||
* @param weights @c etl::ivector of @c etl::pair s of @c group_id_it and their corresponding weights.
|
||||
*
|
||||
* @ret @c weighted_group_id_t of the newly added group, local to this generator.
|
||||
*
|
||||
* @pre preprocess() has not been called on this generator.
|
||||
*
|
||||
* @exception mtl::invalid_argument If no groups were supplied, or an invalid group was encountered.
|
||||
* @exception mtl::system_error If the generator has already been preprocessed.
|
||||
* @exception mtl::length_error If the maximum number of weighted groups is reached.
|
||||
*/
|
||||
weighted_group_id_t add_weighted_group(const etl::ivector<etl::pair<group_id_t, uint32_t>>& group_weights);
|
||||
/**
|
||||
* @overload
|
||||
*
|
||||
* Convenience overload. Creates a weighted group for a group with only
|
||||
* one possibility.
|
||||
*/
|
||||
weighted_group_id_t add_weighted_group(group_id_t group);
|
||||
|
||||
/**
|
||||
* @brief Add a basic (non-marking) branch rule to the generator.
|
||||
*
|
||||
* Basic branch rules describe how this generator will create new leafs
|
||||
* each generation.
|
||||
*
|
||||
* @param match Token to match and generate the group in place of.
|
||||
* @param wgroup Weighted group to generate. Only one subgroup will be selected to generate.
|
||||
*
|
||||
* @ret @c branch_rule_basic_id_t of the newly added branch rule, local to this generator.
|
||||
*
|
||||
* @pre preprocess() has not been called on this generator.
|
||||
*
|
||||
* @exception mtl::invalid_argument If no groups were supplied, or an invalid group was encountered.
|
||||
* @exception mtl::system_error If the generator has already been preprocessed.
|
||||
* @exception mtl::length_error If the maximum number of basic branch rules is reached.
|
||||
*/
|
||||
branch_rule_basic_id_t add_basic_branch_rule(token_id_t match, weighted_group_id_t wgroup);
|
||||
|
||||
/**
|
||||
* @brief Add a marking branch rule to the generator.
|
||||
*
|
||||
* Marking branch rules describe what points (markers) this generator
|
||||
* will output to the caller each generator.
|
||||
*
|
||||
* @param match Token to match and mark.
|
||||
* @param marker_id ID to mark the point with.
|
||||
*
|
||||
* @ret @c branch_rule_marking_id_t of the newly added branch rule, local to this generator.
|
||||
*
|
||||
* @pre preprocess() has not been called on this generator.
|
||||
*
|
||||
* @exception mtl::invalid_argument If an invalid token was supplied.
|
||||
* @exception mtl::system_error If the generator has already been preprocessed.
|
||||
* @exception mtl::length_error If the maximum number of marking branch rules is reached.
|
||||
*/
|
||||
branch_rule_marking_id_t add_marking_branch_rule(token_id_t match, uint32_t marker_id);
|
||||
|
||||
/**
|
||||
* @brief Set the axiom used in this generator.
|
||||
*
|
||||
* The "axiom" is used to generate the very first generation of leafs.
|
||||
* Only one subgroup from the weighted group is selected.
|
||||
*
|
||||
* @exception mtl::invalid If an invalid weighted group ID was suppied.
|
||||
*/
|
||||
void set_axiom(weighted_group_id_t wgroup);
|
||||
|
||||
/**
|
||||
* @brief Perform preprocessing on the supplied group characteristics.
|
||||
*
|
||||
* Transforms each group, producing a list of child leafs and markers
|
||||
* that should be generated for each group characteristic. Has no effect
|
||||
* if called more than once.
|
||||
*
|
||||
* @pre All tokens, groups characteristics, weighted groups, and branch
|
||||
* rules have been added.
|
||||
*
|
||||
* @exception mtl::length_error If the number of resulting child leafs
|
||||
* or markers exceeds the maximum allowed for one group.
|
||||
*/
|
||||
void preprocess();
|
||||
|
||||
/**
|
||||
* @brief Set the scale factor used each generation.
|
||||
*
|
||||
* Each time the generation is stepped, the length of each walk is scaled
|
||||
* by @p scale_factor. Can be set to a new value at any time.
|
||||
*
|
||||
* @param scale_factor The new scale factor to use
|
||||
*/
|
||||
void set_scale_factor(mtl::fixed scale_factor) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Set the initial position the axiom is generated in.
|
||||
*
|
||||
* @param position The initial position to use.
|
||||
*/
|
||||
void set_initial_position(mtl::vec2 position) noexcept;
|
||||
/**
|
||||
* @brief Set the initial orientation the axiom is generated in.
|
||||
*
|
||||
* @param orientation The initial orientation to use. Given in radians.
|
||||
*/
|
||||
void set_initial_orientation(mtl::fixed orientation) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Steps one generation in the fractal, generating a vector of markers.
|
||||
*
|
||||
* The vector of markers will NOT be cleared at the beginning of generation.
|
||||
*
|
||||
* @param out_markers An @c etl::ivector of @c marker_t. Each marker
|
||||
* encountered will be appended to this list in the order encountered.
|
||||
*
|
||||
* @ret true if the maximum number of markers was reached, otherwise false.
|
||||
*/
|
||||
bool step_generation(const etl::ivector<marker_t>& out_markers) noexcept;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename CONTGROUP_T, typename CONTWGROUP_T>
|
||||
void ruleset_t::find_token_matches(token_id_t token, CONTGROUP_T& out_groups, CONTWGROUP_T& out_wgroups) const {
|
||||
for (auto rule : m_branch_rules) {
|
||||
|
||||
375
src/fractal.cpp
375
src/fractal.cpp
@ -110,200 +110,223 @@ branch_rule_id_t ruleset_t::add_branch_rule_weighted(token_id_t match, weighted_
|
||||
return m_branch_rules.size() - 1;
|
||||
}
|
||||
|
||||
// ---------- GENERATOR ----------
|
||||
|
||||
#if 0
|
||||
token_id_t generator_t::add_token(token_type_e type, mtl::fixed value) {
|
||||
log::debug << "Adding token with type " << (int)type << endl;
|
||||
void generator_t::parse_ruleset(const ruleset_t& ruleset) {
|
||||
mlog::debug << "Parsing ruleset" << endl;
|
||||
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add token, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
clear_all_buffers();
|
||||
m_has_ruleset = true;
|
||||
m_axiom = ruleset.get_axiom();
|
||||
|
||||
for (weighted_group_id_t wgid = 0; wgid < ruleset.num_weighted_groups(); ++wgid) {
|
||||
m_weighted_groups.push_back(ruleset.get_weighted_group(wgid));
|
||||
}
|
||||
|
||||
if (m_tokens.full()) {
|
||||
log::error << "Failed to add token, tokens full" << endl;
|
||||
throw mtl::length_error();
|
||||
mlog::debug << "Copied " << m_weighted_groups.size() << " weighted groups" << endl;
|
||||
|
||||
for (token_id_t tok = 0; tok < ruleset.num_tokens(); ++tok) {
|
||||
m_token_matches.push_back(token_match_t());
|
||||
token_match_t& cur_match = m_token_matches.back();
|
||||
|
||||
ruleset.find_token_matches(tok, cur_match.m_groups, cur_match.m_wgroups);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case token_type_e::walk:
|
||||
case token_type_e::rotate:
|
||||
case token_type_e::generate:
|
||||
m_tokens.push_back(token_t{type, value});
|
||||
return m_tokens.size() - 1; // IDs are simply index into vector
|
||||
default:
|
||||
log::error << "Failed to add token, invalid token type" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
for (group_id_t gid = 0; gid < ruleset.num_groups(); ++gid) {
|
||||
m_group_outputs.push_back(group_output_t());
|
||||
|
||||
parse_group_characteristic(gid, m_group_outputs.back(), ruleset);
|
||||
}
|
||||
}
|
||||
|
||||
group_id_t generator_t::add_group_characteristic(uint32_t factor, const etl::ivector<token_id_t>& tokens) {
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add characteristic, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
void generator_t::parse_group_characteristic(group_id_t id, group_output_t& output, const ruleset_t& ruleset) {
|
||||
mlog::debug << "Parsing group characteristic for group " << id << endl;
|
||||
|
||||
vec2 cur_pos(0, 0);
|
||||
mat<2, 2> cur_orient = create_rotation(fixed(1), fixed(0));
|
||||
|
||||
const group_characteristic_t& charac = ruleset.get_group_characteristic(id);
|
||||
|
||||
for (uint32_t i = 0; i < charac.m_factor; ++i) {
|
||||
for (token_id_t tokid : charac.m_token_ids) {
|
||||
const token_t& tok = ruleset.get_token(tokid);
|
||||
|
||||
// Process token marking
|
||||
if (tok.m_mark != 0) {
|
||||
marker_t marker { cur_pos, tok.m_mark };
|
||||
|
||||
output.m_child_markers.push_back(marker);
|
||||
mlog::debug << "Group " << id << " has marker ID: " << tok.m_mark << endl;
|
||||
mlog::debug << " at position " << cur_pos << ", cos(angle) = " << cur_orient.e[0][0] << ", sin(angle) = " << cur_orient.e[1][0] << endl;
|
||||
}
|
||||
|
||||
// Process token groups
|
||||
const token_match_t& match = m_token_matches.at(tokid);
|
||||
|
||||
// Regular groups
|
||||
for (group_id_t groupid : match.m_groups) {
|
||||
leaf_t leaf;
|
||||
leaf.m_group_id = groupid;
|
||||
leaf.m_orientation = cur_orient;
|
||||
leaf.m_position = cur_pos;
|
||||
|
||||
output.m_child_leafs.push_back(leaf);
|
||||
|
||||
mlog::debug << "Group " << id << " has child leaf w/ group id " << groupid << endl;
|
||||
mlog::debug << " at position " << cur_pos << ", cos(angle) = " << cur_orient.e[0][0] << ", sin(angle) = " << cur_orient.e[1][0] << endl;
|
||||
}
|
||||
|
||||
// Weighted groups
|
||||
for (weighted_group_id_t wgroupid : match.m_wgroups) {
|
||||
weighted_leaf_t wleaf;
|
||||
wleaf.m_weighted_group_id = wgroupid;
|
||||
wleaf.m_orientation = cur_orient;
|
||||
wleaf.m_position = cur_pos;
|
||||
|
||||
output.m_child_wleafs.push_back(wleaf);
|
||||
|
||||
mlog::debug << "Group " << id << " has weighted child leaf w/ wgroup " << wgroupid << endl;
|
||||
mlog::debug << " at position " << cur_pos << ", cos(angle) = " << cur_orient.e[0][0] << ", sin(angle) = " << cur_orient.e[1][0] << endl;
|
||||
}
|
||||
|
||||
// Apply the token's transformation
|
||||
switch (tok.m_type) {
|
||||
case token_type_e::walk:
|
||||
cur_pos = cur_pos + cur_orient * vec2(0, tok.m_value);
|
||||
mlog::debug << "Transforming with walk of " << tok.m_value << endl;
|
||||
break;
|
||||
case token_type_e::rotate:
|
||||
cur_orient = create_rotation(tok.m_value, tok.m_value2) * cur_orient;
|
||||
mlog::debug << "Transforming with rotation of " << tok.m_value << endl;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_group_characteristics.full()) {
|
||||
log::error << "Failed to add characteristic, vector full" << endl;
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
void generator_t::swap_buffers() {
|
||||
std::swap(m_leafs_cur, m_leafs_prev);
|
||||
std::swap(m_wleafs_cur, m_wleafs_prev);
|
||||
}
|
||||
|
||||
void generator_t::clear_current_buffers() {
|
||||
m_leafs_cur->clear();
|
||||
m_wleafs_cur->clear();
|
||||
}
|
||||
|
||||
void generator_t::clear_previous_buffers() {
|
||||
m_leafs_prev->clear();
|
||||
m_wleafs_prev->clear();
|
||||
}
|
||||
|
||||
void generator_t::clear_all_buffers() {
|
||||
clear_current_buffers();
|
||||
clear_previous_buffers();
|
||||
}
|
||||
|
||||
bool generator_t::generate_axiom(etl::ivector<marker_t>& out_markers) {
|
||||
const group_output_t& axiom_output = m_group_outputs[m_axiom];
|
||||
|
||||
if (m_leafs_cur->capacity() < axiom_output.m_child_leafs.size() ||
|
||||
m_wleafs_cur->capacity() < axiom_output.m_child_wleafs.size() ||
|
||||
out_markers.capacity() < axiom_output.m_child_markers.size()) {
|
||||
mlog::debug << "Reached limit" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to look for invalid tokens AOT, because we only modify the
|
||||
// generator if the supplied data is valid.
|
||||
size_t num_tokens = m_tokens.size();
|
||||
for (token_id_t token : tokens) {
|
||||
if (token >= num_tokens) {
|
||||
log::error << "Failed to add characteristic, invalid token found: " << token << " >= " << num_tokens << endl;
|
||||
throw mtl::invalid_argument();
|
||||
for (const leaf_t& leaf : axiom_output.m_child_leafs) {
|
||||
m_leafs_cur->push_back(leaf);
|
||||
}
|
||||
for (const weighted_leaf_t& wleaf : axiom_output.m_child_wleafs) {
|
||||
m_wleafs_cur->push_back(wleaf);
|
||||
}
|
||||
for (const marker_t& mark : axiom_output.m_child_markers) {
|
||||
out_markers.push_back(mark);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generator_t::generate_group(group_id_t gid, vec2 pos, mat<2, 2> orient, etl::ivector<marker_t>& out_markers) {
|
||||
const group_output_t& group_output = m_group_outputs[gid];
|
||||
|
||||
if (m_leafs_cur->capacity() < group_output.m_child_leafs.size() ||
|
||||
m_wleafs_cur->capacity() < group_output.m_child_wleafs.size() ||
|
||||
out_markers.capacity() < group_output.m_child_markers.size()) {
|
||||
mlog::debug << "Reached limit" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
fixed cur_scale = 1;
|
||||
for (uint32_t i = 1; i < m_gen_num; ++i) { // start @ 1, don't scale axiom
|
||||
cur_scale *= m_scale;
|
||||
}
|
||||
|
||||
for (const leaf_t& leaf : group_output.m_child_leafs) {
|
||||
leaf_t child;
|
||||
|
||||
child.m_group_id = leaf.m_group_id;
|
||||
child.m_position = pos + orient * cur_scale * leaf.m_position;
|
||||
child.m_orientation = leaf.m_orientation * orient;
|
||||
|
||||
m_leafs_cur->push_back(child);
|
||||
}
|
||||
for (const weighted_leaf_t& wleaf : group_output.m_child_wleafs) {
|
||||
weighted_leaf_t child;
|
||||
|
||||
child.m_weighted_group_id = wleaf.m_weighted_group_id;
|
||||
child.m_position = pos + orient * cur_scale * m_gen_num * wleaf.m_position;
|
||||
child.m_orientation = wleaf.m_orientation * orient;
|
||||
|
||||
m_wleafs_cur->push_back(child);
|
||||
}
|
||||
for (const marker_t& mark : group_output.m_child_markers) {
|
||||
marker_t child;
|
||||
|
||||
child.m_id = mark.m_id;
|
||||
child.m_pos = orient * cur_scale * mark.m_pos;
|
||||
|
||||
out_markers.push_back(child);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool generator_t::generate_leafs(etl::ivector<marker_t>& out_markers) {
|
||||
bool good = true;
|
||||
|
||||
for (const leaf_t& leaf : *m_leafs_prev) {
|
||||
good = good && generate_group(leaf.m_group_id, leaf.m_position, leaf.m_orientation, out_markers);
|
||||
|
||||
if (!good) {
|
||||
mlog::debug << "Failed to generate leafs" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_group_characteristics.push_back(group_characteristic_t());
|
||||
|
||||
group_characteristic_t& characteristic = m_group_characteristics.back();
|
||||
characteristic.m_factor = factor;
|
||||
characteristic.m_token_ids.assign(tokens.begin(), tokens.end());
|
||||
|
||||
return m_group_characteristics.size() - 1; // IDs are just the index into vector
|
||||
return true;
|
||||
}
|
||||
|
||||
group_id_t generator_t::add_group_characteristic(const etl::ivector<token_id_t>& tokens) {
|
||||
return add_group_characteristic(1, tokens);
|
||||
bool generator_t::step_generation(etl::ivector<marker_t>& out_markers) {
|
||||
clear_current_buffers();
|
||||
|
||||
bool good = true;
|
||||
|
||||
if (m_leafs_prev->empty() && m_leafs_cur->empty()) {
|
||||
good = generate_axiom(out_markers);
|
||||
} else {
|
||||
good = generate_leafs(out_markers);
|
||||
}
|
||||
|
||||
swap_buffers();
|
||||
|
||||
if (good) {
|
||||
++m_gen_num;
|
||||
}
|
||||
|
||||
return good;
|
||||
}
|
||||
|
||||
weighted_group_id_t generator_t::add_weighted_group(const etl::ivector<etl::pair<group_id_t, uint32_t>>& group_weights) {
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add weighted group, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
}
|
||||
|
||||
if (m_weighted_groups.full()) {
|
||||
log::error << "Failed to add weighted group, vector full" << endl;
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
size_t num_groups = m_group_characteristics.size();
|
||||
for (etl::pair<group_id_t, uint32_t> pair : group_weights) {
|
||||
if (pair.first >= num_groups) {
|
||||
log::error << "Failed to add weighted group, invalid group found: " << pair.first << " >= " << num_groups << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
}
|
||||
|
||||
m_weighted_groups.push_back(weighted_group_t());
|
||||
|
||||
weighted_group_t& wgroup = m_weighted_groups.back();
|
||||
|
||||
uint32_t weight_total = 0;
|
||||
|
||||
for (etl::pair<group_id_t, uint32_t> pair : group_weights) {
|
||||
wgroup.m_groups.push_back(pair.first);
|
||||
wgroup.m_weights.push_back(pair.second);
|
||||
wgroup.m_weight_total += pair.second;
|
||||
}
|
||||
|
||||
wgroup.m_weight_total = weight_total;
|
||||
|
||||
return m_weighted_groups.size() - 1;
|
||||
}
|
||||
|
||||
weighted_group_id_t generator_t::add_weighted_group(group_id_t group) {
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add weighted group, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
}
|
||||
|
||||
if (m_weighted_groups.full()) {
|
||||
log::error << "Failed to add weighted group, vector full" << endl;
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
if (group >= m_group_characteristics.size()) {
|
||||
log::error << "Failed to add weighted group, invalid group encountered" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
|
||||
m_weighted_groups.push_back(weighted_group_t());
|
||||
|
||||
weighted_group_t& wgroup = m_weighted_groups.back();
|
||||
wgroup.m_groups.push_back(group);
|
||||
wgroup.m_weights.push_back(1); // We still need to supply a weight
|
||||
wgroup.m_weight_total = 1;
|
||||
|
||||
return m_weighted_groups.size() - 1;
|
||||
}
|
||||
|
||||
branch_rule_basic_id_t generator_t::add_basic_branch_rule(token_id_t match, weighted_group_id_t wgroup) {
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add basic branch rule, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
}
|
||||
|
||||
if (m_basic_branch_rules.full()) {
|
||||
log::error << "Failed to add basic branch rule, vector full" << endl;
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
if (match >= m_tokens.size()) {
|
||||
log::error << "Failed to add basic branch rule, invalid match token" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
|
||||
if (wgroup >= m_weighted_groups.size()) {
|
||||
log::error << "Failed to add basic branch rule, invalid weighted group" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
|
||||
m_basic_branch_rules.push_back(branch_rule_basic_t{match, wgroup});
|
||||
|
||||
return m_basic_branch_rules.size() - 1;
|
||||
}
|
||||
|
||||
branch_rule_marking_id_t generator_t::add_marking_branch_rule(token_id_t match, uint32_t marker_id) {
|
||||
if (m_processed) {
|
||||
log::error << "Failed to add marking branch rule, already preprocessed" << endl;
|
||||
throw mtl::system_error();
|
||||
}
|
||||
|
||||
if (m_basic_branch_rules.full()) {
|
||||
log::error << "Failed to add marking branch rule, vector full" << endl;
|
||||
throw mtl::length_error();
|
||||
}
|
||||
|
||||
if (match >= m_tokens.size()) {
|
||||
log::error << "Failed to add marking branch rule, invalid match token" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
|
||||
m_marking_branch_rules.push_back(branch_rule_marking_t{match, marker_id});
|
||||
|
||||
return m_marking_branch_rules.size() - 1;
|
||||
}
|
||||
|
||||
void generator_t::set_axiom(weighted_group_id_t wgroup) {
|
||||
if (wgroup >= m_weighted_groups.size()) {
|
||||
log::error << "Failed to set axiom, invalid weighted group" << endl;
|
||||
throw mtl::invalid_argument();
|
||||
}
|
||||
|
||||
m_axiom = wgroup;
|
||||
}
|
||||
|
||||
void generator_t::preprocess() {
|
||||
}
|
||||
|
||||
void generator_t::set_scale_factor(mtl::fixed scale_factor) noexcept {
|
||||
}
|
||||
|
||||
void generator_t::set_initial_position(mtl::vec2 position) noexcept {
|
||||
}
|
||||
|
||||
void generator_t::set_initial_orientation(mtl::fixed orientation) noexcept {
|
||||
}
|
||||
|
||||
bool generator_t::step_generation(const etl::ivector<marker_t>& out_markers) noexcept {
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace fractal
|
||||
|
||||
|
||||
113
src/main.cpp
113
src/main.cpp
@ -9,22 +9,38 @@
|
||||
|
||||
using namespace mtl;
|
||||
using namespace fractal;
|
||||
namespace mlog = mtl::log;
|
||||
|
||||
GBA_EWRAM_DATA ruleset_t rules;
|
||||
GBA_EWRAM_DATA generator_t gen;
|
||||
GBA_EWRAM_DATA etl::vector<marker_t, 100> output;
|
||||
|
||||
int main(void) {
|
||||
REG_DISPCNT = DCNT_MODE3 | DCNT_BG2;
|
||||
|
||||
log::debug << "Hello world!" << mtl::endl;
|
||||
mlog::debug << "Hello world!" << mtl::flush;
|
||||
|
||||
constexpr float cos_PI_2 = std::cos(M_PI_2);
|
||||
constexpr float cos_PI_3 = std::cos(M_PI / 3);
|
||||
constexpr float cos_PI_4 = std::cos(M_PI_4);
|
||||
constexpr float cos_PI_8 = std::cos(M_PI_4 / 2);
|
||||
constexpr float cos_PI_16 = std::cos(M_PI_4 / 4);
|
||||
constexpr float sin_PI_2 = std::sin(M_PI_2);
|
||||
constexpr float sin_PI_3 = std::sin(M_PI / 3);
|
||||
constexpr float sin_PI_4 = std::sin(M_PI_4);
|
||||
constexpr float sin_PI_8 = std::sin(M_PI_4 / 2);
|
||||
constexpr float sin_PI_16 = std::sin(M_PI_4 / 4);
|
||||
|
||||
fixed cos_PI_2_fx = cos_PI_2;
|
||||
fixed cos_PI_3_fx = cos_PI_3;
|
||||
fixed cos_PI_4_fx = cos_PI_4;
|
||||
fixed cos_PI_8_fx = cos_PI_8;
|
||||
fixed cos_PI_16_fx = cos_PI_16;
|
||||
fixed sin_PI_2_fx = sin_PI_2;
|
||||
fixed sin_PI_3_fx = sin_PI_3;
|
||||
fixed sin_PI_4_fx = sin_PI_4;
|
||||
|
||||
ruleset_t rules;
|
||||
fixed sin_PI_8_fx = sin_PI_8;
|
||||
fixed sin_PI_16_fx = sin_PI_16;
|
||||
|
||||
try {
|
||||
fixed branch_angle = M_PI_4;
|
||||
@ -32,18 +48,18 @@ int main(void) {
|
||||
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, 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 rotate_axiom = rules.add_token(token_type_e::rotate, cos_PI_3_fx, sin_PI_3_fx);
|
||||
token_id_t rotate_petal = rules.add_token(token_type_e::rotate, cos_PI_3_fx, -sin_PI_3_fx);
|
||||
token_id_t rotate_branchr = rules.add_token(token_type_e::rotate, cos_PI_8_fx, -sin_PI_8_fx);
|
||||
token_id_t rotate_branchl = rules.add_token(token_type_e::rotate, cos_PI_4_fx, sin_PI_4_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, 0, 0, 1);
|
||||
|
||||
log::info << "Added tokens" << endl;
|
||||
mlog::info << "Added tokens" << endl;
|
||||
|
||||
uint32_t axiom_factor = 4;
|
||||
uint32_t axiom_factor = 6;
|
||||
|
||||
etl::vector axiom_chr{ branch, rotate_axiom };
|
||||
group_id_t axiom_grp = rules.add_group_characteristic(axiom_chr, axiom_factor);
|
||||
@ -54,27 +70,86 @@ int main(void) {
|
||||
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;
|
||||
mlog::info << "Added group characteristics" << endl;
|
||||
|
||||
rules.add_branch_rule(branch, branch_grp);
|
||||
rules.add_branch_rule(petal, petal_grp);
|
||||
|
||||
log::info << "Added rules" << endl;
|
||||
log::info << "Finished configuring ruleset" << endl;
|
||||
mlog::info << "Added rules" << endl;
|
||||
mlog::info << "Finished configuring ruleset" << endl;
|
||||
} catch(const mtl::exception&) {
|
||||
log::info << "Failed to configure ruleset, caught exception" << endl;
|
||||
mlog::info << "Failed to configure ruleset, caught exception" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
generator_t gen(rules);
|
||||
etl::vector<marker_t, 100> output;
|
||||
size_t gen_num = 0;
|
||||
|
||||
while (gen.step_generation(output)) {
|
||||
log::debug << "Stepped generation" << gen.generation_num() << endl;
|
||||
try {
|
||||
constexpr fixed scale = 0.8;
|
||||
gen.parse_ruleset(rules);
|
||||
gen.set_scale(scale);
|
||||
|
||||
for (const marker_t& m : output) {
|
||||
log::debug << ' ' << m.m_id << ", " << m.m_pos << endl;
|
||||
while (gen.step_generation(output) && gen.generation_num() < 6) {
|
||||
mlog::debug << "Stepped generation" << gen.generation_num() << endl;
|
||||
gen_num = gen.generation_num();
|
||||
}
|
||||
} catch (etl::exception& e) {
|
||||
mlog::error << "Caught ETL exception: " << e.what() << endl;
|
||||
} catch (mtl::exception& e) {
|
||||
mlog::error << "Caught MTL exception: " << e.id() << endl;
|
||||
}
|
||||
|
||||
mlog::info << "Stepped " << gen.generation_num() << " generations" << mtl::endl;
|
||||
mlog::debug << "End" << mtl::flush;
|
||||
|
||||
mlog::info << "Output " << output.size() << " markers: " << endl;
|
||||
|
||||
for (const marker_t& marker : output) {
|
||||
mlog::info << " " << marker.m_pos << endl;
|
||||
}
|
||||
|
||||
vec2 origin(120, 80);
|
||||
int imgscale = 8;
|
||||
|
||||
uint8_t r = 0;
|
||||
uint8_t g = 0;
|
||||
uint8_t b = 0;
|
||||
uint8_t a = 0;
|
||||
COLOR color[3] = { CLR_FUCHSIA, CLR_CREAM, CLR_MAROON };
|
||||
|
||||
for (size_t i = 2; i < output.size(); i += 3) {
|
||||
const marker_t& m1 = output[i-2];
|
||||
const marker_t& m2 = output[i-1];
|
||||
const marker_t& m3 = output[i-0];
|
||||
|
||||
r = 0xFF * 2 / i;
|
||||
g = 0xFF * 2 / i;
|
||||
b = 0x33;
|
||||
a = 0xFF;
|
||||
//color = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
clr_rotate(color, 3, 1);
|
||||
|
||||
vec2 v1 = origin + imgscale * m1.m_pos;
|
||||
vec2 v2 = origin + imgscale * m2.m_pos;
|
||||
vec2 v3 = origin + imgscale * m3.m_pos;
|
||||
|
||||
mlog::debug << "Vertices: " << v1 << ", " << v2 << ", " << v3 << endl;
|
||||
|
||||
int32_t iv1_x = v1.x.raw() / 256;
|
||||
int32_t iv1_y = v1.y.raw() / 256;
|
||||
int32_t iv2_x = v2.x.raw() / 256;
|
||||
int32_t iv2_y = v2.y.raw() / 256;
|
||||
int32_t iv3_x = v3.x.raw() / 256;
|
||||
int32_t iv3_y = v3.y.raw() / 256;
|
||||
|
||||
mlog::debug << " (" << iv1_x << ", " << iv1_y << ")" << endl;
|
||||
mlog::debug << " (" << iv2_x << ", " << iv2_y << ")" << endl;
|
||||
mlog::debug << " (" << iv3_x << ", " << iv3_y << ")" << endl;
|
||||
|
||||
bmp16_line(iv1_x, iv1_y, iv2_x, iv2_y, color[0], vid_mem, 480);
|
||||
bmp16_line(iv1_x, iv1_y, iv3_x, iv3_y, color[0], vid_mem, 480);
|
||||
bmp16_line(iv2_x, iv2_y, iv3_x, iv3_y, color[0], vid_mem, 480);
|
||||
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user