Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| /* noc_turtle library | |
| * | |
| * Copyright (c) 2015 Guillaume Chereau <guillaume@noctua-software.com> | |
| * | |
| * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| * of this software and associated documentation files (the "Software"), to | |
| * deal in the Software without restriction, including without limitation the | |
| * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
| * sell copies of the Software, and to permit persons to whom the Software is | |
| * furnished to do so, subject to the following conditions: | |
| * | |
| * The above copyright notice and this permission notice shall be included in | |
| * all copies or substantial portions of the Software. | |
| * | |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
| * IN THE SOFTWARE. | |
| */ | |
| /* | |
| * | |
| * This library allows to create procedural graphics from a set of rules, | |
| * The syntax of the rules is somehow similar to the ContextFree project | |
| * (http://www.contextfreeart.org). | |
| * | |
| * I strongly suggest that you first check the sample code in tests/turtle.c | |
| * if you want to get an idea of what it can do. | |
| * | |
| * A rule is defined as a C function that takes a noctt_turtle_t object as | |
| * argument. Since all the rules are actually coroutine relying on macros | |
| * to hide the dirty details, you have to enclose the code with a START and | |
| * END. Here is a basic rule that just renders a square: | |
| * | |
| * void my_rule(noctt_turtle_t *turtle) | |
| * { | |
| * START | |
| * SQUARE(); | |
| * END | |
| * } | |
| * | |
| * Turtles | |
| * ------- | |
| * | |
| * Every rule is executed in the context of a turtle (I use this name since | |
| * this is similar to the turtle in the LOGO language). A turtle possess a | |
| * 4x4 transformation matrix that represents its position, rotation and scale. | |
| * It also has a color and a set of flags and variables that can be set by the | |
| * user. | |
| * | |
| * You can change the turtle properties using operations and the TR macro. | |
| * For example to move the turtle a unit distance in the X direction, we | |
| * can write: | |
| * | |
| * TR(X, 1); | |
| * | |
| * The macro can take an arbitrary number of arguments, so we can chain the | |
| * operations: Here we move the turtle on 1 along X, then rotate it of | |
| * 45 degrees, and finally scale it to half its size: | |
| * | |
| * SQUARE(); // First square at the current pos. | |
| * TR(X, 1, R, 45, S, 0.5); | |
| * SQUARE(); // Second square in the new position. | |
| * | |
| * If we just want to apply a transformation in the context of a rendering | |
| * operation, we can put it as argument of the operation, so the previous | |
| * example can be written as: | |
| * | |
| * SQUARE(); | |
| * SQUARE(X, 1, R, 45, S, 0.5); | |
| * // At the point the turtle is still in its original context. | |
| * | |
| * If you want to apply a transformation only for a block of code, you can | |
| * use the TRANSFORM macro: | |
| * | |
| * TRANSFORM(LIGHT, 0.5) { // Only affect the block. | |
| * SQUARE(); | |
| * CIRCLE(X, 1); | |
| * } | |
| * | |
| * You can have several turtles running at the same time. In order to create | |
| * a new turtle, we can spawn a previously defined rule. To control the | |
| * timing, we need to use the YIELD macro, that tell the turtle to wait one | |
| * iteration before proceeding with the rest of the rule. | |
| * | |
| * void a_rule(noctt_turtle_t *turtle) | |
| * { | |
| * START | |
| * SQUARE(); | |
| * YIELD(); | |
| * SQUARE(S, 0.8, LIGHT, -0.5); | |
| * END | |
| * } | |
| * | |
| * void main_rule(noctt_turtle_t *turtle) | |
| * { | |
| * START | |
| * // Create a new turtle from the current one, scale it, and make it | |
| * // process the rule 'a_rule'. | |
| * SPAWN(a_rule, S, 0.5); | |
| * // The rest of the current rule will run in parallel to a_rule. | |
| * ... | |
| * END | |
| * } | |
| * | |
| * An other way is to use the TRANSFORM_SPAWN macro, that runs a block in | |
| * the context of the new turtle. | |
| * | |
| * Looping | |
| * ------- | |
| * | |
| * The LOOP macro allow to run a loop, with an optional transformation applied | |
| * at every iteration: | |
| * | |
| * // Render 10 circles each one scaled by 0.9 from the previous one, | |
| * // and 10/100 darker. | |
| * LOOP(10, S, 0.9, LIGHT, -0.1) { | |
| * CIRCLE(); | |
| * } | |
| * | |
| * Usage | |
| * ----- | |
| * The library does not do the rendering, instead it relies on the client | |
| * to provide a callback that will be called each time a render operation | |
| * is executed. The signature of the callback is: | |
| * | |
| * void *callback(int n, const noctt_vec3_t *poly, | |
| * const float color[4], | |
| * unsigned int flags, void *user_data); | |
| * | |
| * n : number of vertices to renders. | |
| * poly : pointer to the vertices as float[3] x,y,z values. | |
| * color : the color, as (Hue, Sat, Value, Alpha) tuple. It is up to the | |
| * client to convert to RGBA if needed. | |
| * flags : the current turtle user flag values. This is up to the client | |
| * to define what they mean. | |
| * user_data : can be set by the user. | |
| * | |
| * | |
| * Typically the client would first create a program, with noctt_prog_create, | |
| * passing the pointer to the initial rule to be called: | |
| * | |
| * noctt_prog_t *prog = noctt_prog_create( | |
| * my_rule, // The rule to call. | |
| * 256, // Max number of turtles. | |
| * 0, // Inital seed. | |
| * NULL, // Optional initial transformation matrix. | |
| * 1); // Pixel logical size (used for the G operation). | |
| * | |
| * Then set the rendering callback: | |
| * | |
| * prog->render_callback = my_render_callback; | |
| * prog->render_callback_data = NULL; | |
| * | |
| * Then we can call noctt_prog_iter to step into the rendering, our callback | |
| * will be called appropriately. | |
| * | |
| * while (proc->active) { | |
| * noctt_prg_iter(prog); | |
| * } | |
| * | |
| * Finally when we are done, we can delete the program: | |
| * | |
| * noctt_prog_delete(prog); | |
| * | |
| * | |
| * Some doc about the operations | |
| * ----------------------------- | |
| * | |
| * Since I try to follow the same conventions as ContextFree when possible, we | |
| * can also refer to the doc at: | |
| * http://www.contextfreeart.org/mediawiki/index.php/Shape_adjustment | |
| * | |
| * Rendering calls | |
| * --------------- | |
| * | |
| * All the calls accept extra arguments for the operations to apply before | |
| * the rendering is done. | |
| * | |
| * POLY(n, float (*verts)[3], ...) | |
| * Render a polygon of n vertices. | |
| * // XXX: to implement. | |
| * | |
| * SQUARE(...) | |
| * Render a square | |
| * | |
| * CIRCLE(...) | |
| * Render a circle | |
| * | |
| * RSQUARE(float r, ...) | |
| * Render a rounded square. r is the max size of the rectangle such | |
| * that the rounded radius will be zero. | |
| * | |
| * STAR(int n, float t, float c, ...) | |
| * Render a star with n branches, t is the flatness of the star, | |
| * c define the center of the branch top. Sorry this doc is | |
| * no useful, need to add some examples. | |
| * | |
| * TRIANGLE(...) | |
| * Conveniance for STAR(3, 0, 0) | |
| * | |
| * | |
| * Transformation operations | |
| * ------------------------- | |
| * | |
| * S, x, [y], [z] | |
| * Scale in x, y, and z. If z is not specified, it is set to 1. If y is | |
| * not specified it is set to x. | |
| * | |
| * SN | |
| * Scale so that the x and y ratios are the same. Useful when we want | |
| * to specify the rendered shape regardless of the current scale. | |
| * | |
| * SX, x | |
| * Scale in x only (same as S, x, 1, 1). | |
| * | |
| * SY, y | |
| * Scale in y only (same as S, 1, y, 1). | |
| * | |
| * SZ, z | |
| * Scale in z only (same as S, 1, 1, z). | |
| * | |
| * | |
| * X, x, [y], [z] | |
| * Translate in x, y and z. If y or z are not specified, they are set | |
| * to 0. | |
| * | |
| * Y, y | |
| * Translate in y only (same as X, 0, y). | |
| * | |
| * Z, z | |
| * Translate in z only (same as X, 0, 0, z). | |
| * | |
| * R, a | |
| * Rotate along the z axis of an angle of a (in degree). | |
| * | |
| * FLIP, a | |
| * Flip along the angle a (in degree). | |
| * | |
| * G, x, [y] | |
| * Scale along x and y, such that the size of square grows a fixed amount. | |
| * This is useful for border effects. | |
| * | |
| * | |
| * Color operations | |
| * ---------------- | |
| * | |
| * HUE, SAT, LIGHT and A can be used to modify the color (A is for alpha). | |
| * | |
| * SAT, LIGHT, and A can be used with a single argument, in that case it | |
| * moves the value toward 1 if the argument is positifs and toward 0 if the | |
| * argument is negative. The ratio of change is the absolute value of the | |
| * argument. So an argument of 0 don't do anything, an argument of -1 set | |
| * the value to 0, and an argument of +1 set the value to 1. | |
| * | |
| * With two arguments, the function mix the current value and the second | |
| * argument according to the first argument value, for example: | |
| * | |
| * LIGHT, t, x => light = mix(light, x, t); | |
| * | |
| * | |
| * HUE, [t], x | |
| * Add x to the hue. | |
| * | |
| * SAT, [t], s, | |
| * Adjust the saturation | |
| * | |
| * LIGHT, [t], l | |
| * Adjust the lightness | |
| * | |
| * A, [t], a | |
| * Adjust the alpha value | |
| * | |
| * HSL, [t], h, s, l | |
| * Same as HUE, h, SAT, s, LIGHT, l | |
| * | |
| * | |
| * Other operations | |
| * ---------------- | |
| * | |
| * VAR, i0, v0, [i1, v1, ..., in, vn] | |
| * Set the context variables value. | |
| * | |
| * FLAG f [v], [f2, v2, ..., fn, vn] | |
| * Set the flag value. If v is not defined, the default is 1. | |
| */ | |
| /* Notes about the implementation | |
| * ------------------------------ | |
| * | |
| * Yes, the code is hard to follow, this is what we get from abusing the | |
| * C language to fake coroutines. | |
| * | |
| * The rules are all really based around a big switch that jumps to the | |
| * current state. This has some important implications in what we can do | |
| * inside the rules: | |
| * | |
| * - Since the code make heavy use of the __LINE__ macro, it is not | |
| * possible to put two of them on the same line! So do not write | |
| * something like: LOOP(10) { SQUARE(); }. This might or might not | |
| * work. In the best case the compiler will refuse to compile. | |
| * | |
| * - It is not possible to use local variables. In fact it is possible, | |
| * but you have to be very careful about it, so don't do it if you | |
| * don't know how this thing work, or until I write a doc about it. | |
| * | |
| * - We cannot use switch blocks inside the rules. This is unfortunate. | |
| * Maybe I will try to find a way to fix this... | |
| * | |
| * - However, it is perfectly fine to call any C functions, which is one | |
| * of the advantage over using a script language. | |
| * | |
| */ | |
| /* If NOC_TURTLE_DEFINE_NAMES is defined, then we will create default | |
| * conveniance macros. If you don't do it, then you have to use the names with | |
| * NOCTT_ prefix, or define the macros by yourself. | |
| * | |
| * You can also include this file with NOC_TURTLE_UNDEF_NAMES to undef all | |
| * the names. | |
| * | |
| * So a common use case would be to enclose your rules with two includes to | |
| * define and undefine the macros, like this: | |
| * | |
| * #define NOC_TURTLE_DEFINE_NAMES | |
| * #include "noc_turtle.h" | |
| * | |
| * // All the code here here can use the default names... | |
| * | |
| * #define NOC_TURTLE_UNDEF_NAME | |
| * #include "noc_turtle.h" | |
| * | |
| * | |
| */ | |
| #if defined NOC_TURTLE_UNDEF_NAMES | |
| #undef S | |
| #undef SN | |
| #undef SX | |
| #undef SY | |
| #undef SZ | |
| #undef X | |
| #undef Y | |
| #undef Z | |
| #undef R | |
| #undef FLIP | |
| #undef HUE | |
| #undef SAT | |
| #undef LIGHT | |
| #undef HSL | |
| #undef A | |
| #undef G | |
| #undef VAR | |
| #undef FLAG | |
| #undef TR | |
| #undef START | |
| #undef END | |
| #undef YIELD | |
| #undef CALL | |
| #undef JUMP | |
| #undef SPAWN | |
| #undef KILL | |
| #undef SQUARE | |
| #undef RSQUARE | |
| #undef CIRCLE | |
| #undef STAR | |
| #undef TRIANGLE | |
| #undef POLY | |
| #undef TRANSFORM_SPAWN | |
| #undef TRANSFORM | |
| #undef LOOP | |
| #undef PM | |
| #undef BRAND | |
| #undef FRAND | |
| #elif defined NOC_TURTLE_DEFINE_NAMES | |
| #define S NOCTT_S | |
| #define SN NOCTT_SN | |
| #define SX NOCTT_SX | |
| #define SY NOCTT_SY | |
| #define SZ NOCTT_SZ | |
| #define X NOCTT_X | |
| #define Y NOCTT_Y | |
| #define Z NOCTT_Z | |
| #define R NOCTT_R | |
| #define FLIP NOCTT_FLIP | |
| #define HUE NOCTT_HUE | |
| #define SAT NOCTT_SAT | |
| #define LIGHT NOCTT_LIGHT | |
| #define HSL NOCTT_HSL | |
| #define A NOCTT_A | |
| #define G NOCTT_G | |
| #define VAR NOCTT_VAR | |
| #define FLAG NOCTT_FLAG | |
| #define TR(...) NOCTT_TR(__VA_ARGS__) | |
| #define START NOCTT_START | |
| #define END NOCTT_END | |
| #define YIELD(...) NOCTT_YIELD(__VA_ARGS__) | |
| #define CALL(...) NOCTT_CALL(__VA_ARGS__) | |
| #define JUMP(...) NOCTT_JUMP(__VA_ARGS__) | |
| #define SPAWN(...) NOCTT_SPAWN(__VA_ARGS__) | |
| #define KILL() NOCTT_KILL() | |
| #define SQUARE(...) NOCTT_SQUARE(__VA_ARGS__) | |
| #define RSQUARE(...) NOCTT_RSQUARE(__VA_ARGS__) | |
| #define CIRCLE(...) NOCTT_CIRCLE(__VA_ARGS__) | |
| #define STAR(...) NOCTT_STAR(__VA_ARGS__) | |
| #define TRIANGLE(...) NOCTT_TRIANGLE(__VA_ARGS__) | |
| #define POLY(...) NOCTT_POLY(__VA_ARGS__) | |
| #define TRANSFORM_SPAWN(...) NOCTT_TRANSFORM_SPAWN(__VA_ARGS__) | |
| #define TRANSFORM(...) NOCTT_TRANSFORM(__VA_ARGS__) | |
| #define LOOP(...) NOCTT_LOOP(__VA_ARGS__) | |
| #define PM(x_, y_) noctt_pm(turtle, x_, y_) | |
| #define BRAND(x_) noctt_brand(turtle, x_) | |
| #define FRAND(a_, b_) noctt_frand(turtle, a_, b_) | |
| #endif | |
| #ifndef _NOC_TURTLE_H_ | |
| #define _NOC_TURTLE_H_ | |
| #include <float.h> | |
| #include <stdbool.h> | |
| // Maybe I should remove this, and let the client pass a pointer to his own | |
| // defined structure to hold turtle variables. | |
| #ifndef NOCTT_NB_VARS | |
| # define NOCTT_NB_VARS 3 | |
| #endif | |
| typedef struct { | |
| float x, y, z; | |
| } noctt_vec3_t; | |
| typedef struct noctt_turtle noctt_turtle_t; | |
| typedef void (*noctt_rule_func_t)(noctt_turtle_t*); | |
| typedef struct noctt_prog noctt_prog_t; | |
| struct noctt_turtle { | |
| noctt_prog_t *prog; | |
| float mat[16]; | |
| float scale[2]; // Should we compute it from the matrix? | |
| float color[4]; | |
| int wait; // Index of the turtle we wait for. | |
| noctt_rule_func_t func; | |
| unsigned int iflags; // Internal flags. | |
| unsigned int flags; // User defined flags. | |
| int step; | |
| int time; | |
| int n, i, tmp; | |
| float vars[NOCTT_NB_VARS]; | |
| }; | |
| enum { | |
| NOCTT_OP_END = 0, | |
| NOCTT_OP_S, // Scale, with no arg normalize x/y scale. | |
| NOCTT_OP_SN, // Normalize x/y scale. | |
| NOCTT_OP_SAXIS, // Scale in a single axis. (For SX, SY and SZ). | |
| NOCTT_OP_X, // Translate. | |
| NOCTT_OP_R, // Rotate. | |
| NOCTT_OP_G, // Grow | |
| NOCTT_OP_FLIP, | |
| NOCTT_OP_HSL, | |
| NOCTT_OP_HUE, | |
| NOCTT_OP_SAT, | |
| NOCTT_OP_LIGHT, | |
| NOCTT_OP_A, // Alpha | |
| NOCTT_OP_VAR, | |
| NOCTT_OP_FLAG, | |
| NOCTT_OP_COUNT, | |
| }; | |
| // Internal flags. | |
| enum { | |
| NOCTT_FLAG_DONE = 1 << 0, | |
| NOCTT_FLAG_JUST_CLONED = 1 << 1, | |
| NOCTT_FLAG_WAITING = 1 << 2, | |
| NOCTT_FLAG_BLOCK_DONE = 1 << 3, | |
| }; | |
| #define NOCTT_OP_START FLT_MAX | |
| #define NOCTT_S NOCTT_OP_START, NOCTT_OP_S | |
| #define NOCTT_SN NOCTT_OP_START, NOCTT_OP_SN | |
| #define NOCTT_SX NOCTT_OP_START, NOCTT_OP_SAXIS, 0 | |
| #define NOCTT_SY NOCTT_OP_START, NOCTT_OP_SAXIS, 1 | |
| #define NOCTT_SZ NOCTT_OP_START, NOCTT_OP_SAXIS, 2 | |
| #define NOCTT_X NOCTT_OP_START, NOCTT_OP_X | |
| #define NOCTT_Y NOCTT_X, 0 | |
| #define NOCTT_Z NOCTT_X, 0, 0 | |
| #define NOCTT_R NOCTT_OP_START, NOCTT_OP_R | |
| #define NOCTT_FLIP NOCTT_OP_START, NOCTT_OP_FLIP | |
| #define NOCTT_HUE NOCTT_OP_START, NOCTT_OP_HUE | |
| #define NOCTT_SAT NOCTT_OP_START, NOCTT_OP_SAT | |
| #define NOCTT_LIGHT NOCTT_OP_START, NOCTT_OP_LIGHT | |
| #define NOCTT_HSL NOCTT_OP_START, NOCTT_OP_HSL | |
| #define NOCTT_A NOCTT_OP_START, NOCTT_OP_A | |
| #define NOCTT_G NOCTT_OP_START, NOCTT_OP_G | |
| #define NOCTT_VAR NOCTT_OP_START, NOCTT_OP_VAR | |
| #define NOCTT_FLAG NOCTT_OP_START, NOCTT_OP_FLAG | |
| // If __COUNTER__ is defined (gcc and clang), we use it, since it has the | |
| // advantage of staying the same when we modify the code. It also allows | |
| // to put several on the same line. | |
| // NOCTT_MARKER is used to generate a uniq int that can be used for labels | |
| // If we want to put several on the same line, we have to use a different | |
| // 'n' value for each of them. If we want to get the same value for two | |
| // markers, we need to put the same n, but also set the shift of one to the | |
| // ofset between the two (so that it works with __COUNTER__ too). | |
| #ifdef __COUNTER__ | |
| #define NOCTT_MARKER(n, shift) (__COUNTER__ + shift) | |
| #else | |
| #define NOCTT_MARKER(n, shift) (__LINE__ * 8 + n) | |
| #endif | |
| #define NOCTT_TR(...) do { \ | |
| const float ops_[] = {__VA_ARGS__}; \ | |
| noctt_tr(turtle, sizeof(ops_) / sizeof(float), ops_); \ | |
| } while (0) | |
| #define NOCTT_START \ | |
| switch (turtle->step) { \ | |
| case 0:; | |
| #define NOCTT_END \ | |
| NOCTT_KILL(); \ | |
| } | |
| #define NOCTT_PRIMITIVE_(func, ...) do { \ | |
| const float ops_[] = {__VA_ARGS__}; \ | |
| noctt_turtle_t turtle_ = *turtle; \ | |
| noctt_tr(&turtle_, sizeof(ops_) / sizeof(float), ops_); \ | |
| func; \ | |
| } while (0) | |
| #define NOCTT_SQUARE(...) \ | |
| NOCTT_PRIMITIVE_(noctt_square(&turtle_), __VA_ARGS__) | |
| #define NOCTT_RSQUARE(r, ...) \ | |
| NOCTT_PRIMITIVE_(noctt_rsquare(&turtle_, r), __VA_ARGS__) | |
| #define NOCTT_CIRCLE(...) \ | |
| NOCTT_PRIMITIVE_(noctt_circle(&turtle_), __VA_ARGS__) | |
| #define NOCTT_STAR(n, t, c, ...) \ | |
| NOCTT_PRIMITIVE_(noctt_star(&turtle_, n, t, c), __VA_ARGS__) | |
| #define NOCTT_POLY(n, p, ...) \ | |
| NOCTT_PRIMITIVE_(noctt_poly(&turtle_, n, p), __VA_ARGS__) | |
| #define NOCTT_TRIANGLE(...) NOCTT_STAR(3, 0, 0, ##__VA_ARGS__) | |
| #define NOCTT_COMMA_ , | |
| #define NOCTT_YIELD_(_, n_, ...) do { \ | |
| turtle->tmp = n_; \ | |
| turtle->step = NOCTT_MARKER(0, 1); \ | |
| case NOCTT_MARKER(0, 0):; \ | |
| if (turtle->tmp--) { \ | |
| turtle->iflags |= NOCTT_FLAG_DONE; \ | |
| return; \ | |
| } \ | |
| } while (0) | |
| #define NOCTT_YIELD(...) NOCTT_YIELD_(0, ##__VA_ARGS__, 1) | |
| #define NOCTT_CLONE(mode, ...) do { \ | |
| turtle->step = NOCTT_MARKER(0, 1); \ | |
| const float ops_[] = {__VA_ARGS__}; \ | |
| noctt_clone(turtle, mode, sizeof(ops_) / sizeof(float), ops_); \ | |
| if (mode == 1) return; \ | |
| } while (0); \ | |
| case NOCTT_MARKER(0, 0):; \ | |
| #define NOCTT_CALL(rule, ...) do { \ | |
| NOCTT_CLONE(1, ##__VA_ARGS__); \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) { \ | |
| turtle->iflags &= ~NOCTT_FLAG_JUST_CLONED; \ | |
| turtle->func = rule; \ | |
| turtle->step = 0; \ | |
| return; \ | |
| } \ | |
| } while (0) | |
| #define NOCTT_JUMP(rule, ...) do { \ | |
| TR(__VA_ARGS__); \ | |
| turtle->func = rule; \ | |
| turtle->step = 0; \ | |
| return; \ | |
| } while (0) | |
| #define NOCTT_SPAWN(rule, ...) do { \ | |
| NOCTT_CLONE(0, ##__VA_ARGS__); \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) { \ | |
| turtle->iflags &= ~NOCTT_FLAG_JUST_CLONED; \ | |
| turtle->func = rule; \ | |
| turtle->step = 0; \ | |
| return; \ | |
| } \ | |
| } while (0) | |
| #define NOCTT_UNIQ_LABEL__(n, line) label_ ## line ## _ ## n | |
| #define NOCTT_UNIQ_LABEL_(n, line) NOCTT_UNIQ_LABEL__(n, line) | |
| #define NOCTT_UNIQ_LABEL(n) NOCTT_UNIQ_LABEL_(n, __LINE__) | |
| /* | |
| #define NOCTT_RUN_BLOCK_AND_KILL_ \ | |
| if (1) {goto NOCTT_UNIQ_LABEL(0);} \ | |
| else \ | |
| while (1) \ | |
| if (1) { \ | |
| noctt_kill(turtle); \ | |
| return; \ | |
| } \ | |
| else \ | |
| NOCTT_UNIQ_LABEL(0): | |
| */ | |
| #define NOCTT_RUN_BLOCK_AND_KILL_ \ | |
| for (turtle->iflags &= ~NOCTT_FLAG_BLOCK_DONE; ; \ | |
| turtle->iflags |= NOCTT_FLAG_BLOCK_DONE) \ | |
| if (turtle->iflags & NOCTT_FLAG_BLOCK_DONE) { \ | |
| noctt_kill(turtle); \ | |
| return; \ | |
| } else | |
| #define NOCTT_TRANSFORM_SPAWN(...) \ | |
| NOCTT_CLONE(0, ##__VA_ARGS__); \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) \ | |
| if ((turtle->iflags &= ~NOCTT_FLAG_JUST_CLONED), 1) \ | |
| NOCTT_RUN_BLOCK_AND_KILL_ | |
| #define NOCTT_TRANSFORM(...) \ | |
| NOCTT_CLONE(1, ##__VA_ARGS__); \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) \ | |
| if ((turtle->iflags &= ~NOCTT_FLAG_JUST_CLONED), 1) \ | |
| NOCTT_RUN_BLOCK_AND_KILL_ | |
| #define NOCTT_LOOP(n_, ...) \ | |
| turtle->tmp = n_; \ | |
| NOCTT_CLONE(1); \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) { \ | |
| turtle->step = NOCTT_MARKER(1, 1); case NOCTT_MARKER(1, 0):; \ | |
| turtle->n = turtle->tmp; \ | |
| for (turtle->i = 0; turtle->i < turtle->n; turtle->i++) { \ | |
| turtle->step = NOCTT_MARKER(2, 1); \ | |
| noctt_clone(turtle, 1, 0, 0); \ | |
| NOCTT_TR(__VA_ARGS__); \ | |
| return; \ | |
| case NOCTT_MARKER(2, 0):; \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) { \ | |
| turtle->step = NOCTT_MARKER(3, 1); \ | |
| return; \ | |
| } \ | |
| } \ | |
| noctt_kill(turtle); \ | |
| return; \ | |
| } \ | |
| case NOCTT_MARKER(3, 0):; \ | |
| if (turtle->iflags & NOCTT_FLAG_JUST_CLONED) \ | |
| NOCTT_RUN_BLOCK_AND_KILL_ | |
| #define NOCTT_KILL() do { noctt_kill(turtle); return; } while(0) | |
| noctt_vec3_t noctt_get_pos(const noctt_turtle_t *turtle); | |
| void noctt_square(const noctt_turtle_t *turtle); | |
| void noctt_rsquare(const noctt_turtle_t *turtle, float r); | |
| void noctt_circle(const noctt_turtle_t *turtle); | |
| void noctt_star(const noctt_turtle_t *turtle, int n, float t, float c); | |
| void noctt_poly(const noctt_turtle_t *turtle, int n, const noctt_vec3_t *poly); | |
| void noctt_kill(noctt_turtle_t *turtle); | |
| void noctt_tr(noctt_turtle_t *turtle, int n, const float *ops); | |
| void noctt_clone(noctt_turtle_t *turtle, int mode, int n, const float *ops); | |
| typedef void (*noctt_render_func_t)(int n, const noctt_vec3_t *poly, | |
| const float color[4], | |
| unsigned int flags, void *user_data); | |
| struct noctt_prog { | |
| int nb; // total number of turtles. | |
| int active; // number of active turtles. | |
| unsigned long rand_next; | |
| float pixel_size; | |
| noctt_render_func_t render_callback; | |
| void *render_callback_data; | |
| // Kill context if x or y scale get below this value. | |
| float min_scale; | |
| noctt_turtle_t turtles[]; | |
| }; | |
| float noctt_frand(noctt_turtle_t *turtle, float a, float b); | |
| bool noctt_brand(noctt_turtle_t *turtle, float x); | |
| float noctt_pm(noctt_turtle_t *turtle, float x, float a); | |
| noctt_prog_t *noctt_prog_create(noctt_rule_func_t rule, int nb, | |
| int seed, float rect[16], float pixel_size); | |
| void noctt_prog_delete(noctt_prog_t *prog); | |
| void noctt_prog_iter(noctt_prog_t *prog); | |
| #endif // _NOC_TURTLE_H_ |