diff --git a/examples/shapes/shapes_penrose_tile.c b/examples/shapes/shapes_penrose_tile.c index dee62248d..948a29d12 100644 --- a/examples/shapes/shapes_penrose_tile.c +++ b/examples/shapes/shapes_penrose_tile.c @@ -16,14 +16,18 @@ * ********************************************************************************************/ +#include "raylib.h" + #include #include #include -#include "raylib.h" -#define STR_MAX_SIZE 10000 -#define TURTLE_STACK_MAX_SIZE 50 +#define STR_MAX_SIZE 10000 +#define TURTLE_STACK_MAX_SIZE 50 +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- typedef struct TurtleState { Vector2 origin; double angle; @@ -40,162 +44,21 @@ typedef struct PenroseLSystem { float theta; } PenroseLSystem; +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- static TurtleState turtleStack[TURTLE_STACK_MAX_SIZE]; static int turtleTop = -1; -void PushTurtleState(TurtleState state) -{ - if (turtleTop < TURTLE_STACK_MAX_SIZE - 1) - { - turtleStack[++turtleTop] = state; - } - else - { - TraceLog(LOG_WARNING, "TURTLE STACK OVERFLOW!"); - } -} - -TurtleState PopTurtleState(void) -{ - if (turtleTop >= 0) - { - return turtleStack[turtleTop--]; - } - else - { - TraceLog(LOG_WARNING, "TURTLE STACK UNDERFLOW!"); - } - return (TurtleState) {0}; -} - -PenroseLSystem CreatePenroseLSystem(float drawLength) -{ - PenroseLSystem ls = { - .steps = 0, - .ruleW = "YF++ZF4-XF[-YF4-WF]++", - .ruleX = "+YF--ZF[3-WF--XF]+", - .ruleY = "-WF++XF[+++YF++ZF]-", - .ruleZ = "--YF++++WF[+ZF++++XF]--XF", - .drawLength = drawLength, - .theta = 36.0f // in degrees - }; - ls.production = (char*) malloc(sizeof(char) * STR_MAX_SIZE); - ls.production[0] = '\0'; - strncpy(ls.production, "[X]++[X]++[X]++[X]++[X]", STR_MAX_SIZE); - return ls; -} - -void DrawPenroseLSystem(PenroseLSystem *ls) -{ - Vector2 screenCenter = {GetScreenWidth()/2, GetScreenHeight()/2}; - - TurtleState turtle = { - .origin = {0}, - .angle = -90.0f - }; - - int repeats = 1; - int productionLength = (int) strnlen(ls->production, STR_MAX_SIZE); - ls->steps += 12; - - if (ls->steps > productionLength) - { - ls->steps = productionLength; - } - - for (int i = 0; i < ls->steps; i++) - { - char step = ls->production[i]; - if ( step == 'F' ) - { - for ( int j = 0; j < repeats; j++ ) - { - Vector2 startPosWorld = turtle.origin; - float radAngle = DEG2RAD * turtle.angle; - turtle.origin.x += ls->drawLength * cosf(radAngle); - turtle.origin.y += ls->drawLength * sinf(radAngle); - Vector2 startPosScreen = {startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y}; - Vector2 endPosScreen = {turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y}; - DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2)); - } - repeats = 1; - } - else if ( step == '+' ) - { - for ( int j = 0; j < repeats; j++ ) - { - turtle.angle += ls->theta; - } - repeats = 1; - } - else if ( step == '-' ) - { - for ( int j = 0; j < repeats; j++ ) - { - turtle.angle += -ls->theta; - } - repeats = 1; - } - else if ( step == '[' ) - { - PushTurtleState(turtle); - } - else if ( step == ']' ) - { - turtle = PopTurtleState(); - } - else if ( ( step >= 48 ) && ( step <= 57 ) ) - { - repeats = (int) step - 48; - } - } - - turtleTop = -1; - -} - -void BuildProductionStep(PenroseLSystem *ls) -{ - char *newProduction = (char*) malloc(sizeof(char) * STR_MAX_SIZE); - newProduction[0] = '\0'; - - int productionLength = strnlen(ls->production, STR_MAX_SIZE); - - for (int i = 0; i < productionLength; i++) - { - char step = ls->production[i]; - int remainingSpace = STR_MAX_SIZE - strnlen(newProduction, STR_MAX_SIZE) - 1; - switch (step) - { - case 'W': strncat(newProduction, ls->ruleW, remainingSpace); break; - case 'X': strncat(newProduction, ls->ruleX, remainingSpace); break; - case 'Y': strncat(newProduction, ls->ruleY, remainingSpace); break; - case 'Z': strncat(newProduction, ls->ruleZ, remainingSpace); break; - default: - { - if (step != 'F') - { - int t = strnlen(newProduction, STR_MAX_SIZE); - newProduction[t] = step; - newProduction[t+1] = '\0'; - } - } break; - } - } - - ls->drawLength *= 0.5f; - strncpy(ls->production, newProduction, STR_MAX_SIZE); - free( newProduction ); -} - -void BuildPenroseLSystem(PenroseLSystem *ls, float drawLength, int generations) -{ - *ls = CreatePenroseLSystem(drawLength); - for (int i = 0; i < generations; i++) - { - BuildProductionStep(ls); - } -} +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +static void PushTurtleState(TurtleState state); +static TurtleState PopTurtleState(void); +static PenroseLSystem CreatePenroseLSystem(float drawLength); +static void BuildProductionStep(PenroseLSystem *ls); +static void BuildPenroseLSystem(PenroseLSystem *ls, float drawLength, int generations); +static void DrawPenroseLSystem(PenroseLSystem *ls); //------------------------------------------------------------------------------------ // Program main entry point @@ -207,7 +70,7 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - SetConfigFlags( FLAG_MSAA_4X_HINT ); + SetConfigFlags(FLAG_MSAA_4X_HINT); InitWindow(screenWidth, screenHeight, "raylib [shapes] example - penrose tile"); float drawLength = 460.0f; @@ -216,7 +79,7 @@ int main(void) int generations = 0; PenroseLSystem ls = {0}; - BuildPenroseLSystem(&ls, drawLength * (generations / (float) maxGenerations), generations); + BuildPenroseLSystem(&ls, drawLength*(generations/(float)maxGenerations), generations); SetTargetFPS(60); // Set our game to run at 60 frames-per-second //--------------------------------------------------------------------------------------- @@ -240,26 +103,25 @@ int main(void) if (generations > minGenerations) { generations--; - rebuild = generations > 0; + if (generations > 0) rebuild = true; } } - if (rebuild) - { - BuildPenroseLSystem(&ls, drawLength * (generations / (float) maxGenerations), generations); - } + + if (rebuild) BuildPenroseLSystem(&ls, drawLength*(generations/(float)maxGenerations), generations); //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- BeginDrawing(); + ClearBackground( RAYWHITE ); - if (generations > 0) - { - DrawPenroseLSystem(&ls); - } + + if (generations > 0) DrawPenroseLSystem(&ls); + DrawText("penrose l-system", 10, 10, 20, DARKGRAY); DrawText("press up or down to change generations", 10, 30, 20, DARKGRAY); DrawText(TextFormat("generations: %d", generations), 10, 50, 20, DARKGRAY); + EndDrawing(); //---------------------------------------------------------------------------------- } @@ -270,4 +132,144 @@ int main(void) //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +void PushTurtleState(TurtleState state) +{ + if (turtleTop < (TURTLE_STACK_MAX_SIZE - 1)) turtleStack[++turtleTop] = state; + else TraceLog(LOG_WARNING, "TURTLE STACK OVERFLOW!"); +} + +TurtleState PopTurtleState(void) +{ + if (turtleTop >= 0) return turtleStack[turtleTop--]; + else TraceLog(LOG_WARNING, "TURTLE STACK UNDERFLOW!"); + + return (TurtleState){ 0 }; +} + +PenroseLSystem CreatePenroseLSystem(float drawLength) +{ + PenroseLSystem ls = { + .steps = 0, + .ruleW = "YF++ZF4-XF[-YF4-WF]++", + .ruleX = "+YF--ZF[3-WF--XF]+", + .ruleY = "-WF++XF[+++YF++ZF]-", + .ruleZ = "--YF++++WF[+ZF++++XF]--XF", + .drawLength = drawLength, + .theta = 36.0f // Degrees + }; + + ls.production = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE); + ls.production[0] = '\0'; + strncpy(ls.production, "[X]++[X]++[X]++[X]++[X]", STR_MAX_SIZE); + + return ls; +} + +void BuildProductionStep(PenroseLSystem *ls) +{ + char *newProduction = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE); + newProduction[0] = '\0'; + + int productionLength = strnlen(ls->production, STR_MAX_SIZE); + + for (int i = 0; i < productionLength; i++) + { + char step = ls->production[i]; + int remainingSpace = STR_MAX_SIZE - strnlen(newProduction, STR_MAX_SIZE) - 1; + switch (step) + { + case 'W': strncat(newProduction, ls->ruleW, remainingSpace); break; + case 'X': strncat(newProduction, ls->ruleX, remainingSpace); break; + case 'Y': strncat(newProduction, ls->ruleY, remainingSpace); break; + case 'Z': strncat(newProduction, ls->ruleZ, remainingSpace); break; + default: + { + if (step != 'F') + { + int t = strnlen(newProduction, STR_MAX_SIZE); + newProduction[t] = step; + newProduction[t + 1] = '\0'; + } + } break; + } + } + + ls->drawLength *= 0.5f; + strncpy(ls->production, newProduction, STR_MAX_SIZE); + + RL_FREE(newProduction); +} + +void BuildPenroseLSystem(PenroseLSystem *ls, float drawLength, int generations) +{ + *ls = CreatePenroseLSystem(drawLength); + for (int i = 0; i < generations; i++) BuildProductionStep(ls); +} + +void DrawPenroseLSystem(PenroseLSystem *ls) +{ + Vector2 screenCenter = { GetScreenWidth()/2, GetScreenHeight()/2 }; + + TurtleState turtle = { + .origin = {0}, + .angle = -90.0f + }; + + int repeats = 1; + int productionLength = (int)strnlen(ls->production, STR_MAX_SIZE); + ls->steps += 12; + + if (ls->steps > productionLength) ls->steps = productionLength; + + for (int i = 0; i < ls->steps; i++) + { + char step = ls->production[i]; + if (step == 'F') + { + for (int j = 0; j < repeats; j++) + { + Vector2 startPosWorld = turtle.origin; + float radAngle = DEG2RAD*turtle.angle; + turtle.origin.x += ls->drawLength*cosf(radAngle); + turtle.origin.y += ls->drawLength*sinf(radAngle); + Vector2 startPosScreen = { startPosWorld.x + screenCenter.x, startPosWorld.y + screenCenter.y }; + Vector2 endPosScreen = { turtle.origin.x + screenCenter.x, turtle.origin.y + screenCenter.y }; + + DrawLineEx(startPosScreen, endPosScreen, 2, Fade(BLACK, 0.2)); + } + + repeats = 1; + } + else if (step == '+') + { + for (int j = 0; j < repeats; j++) turtle.angle += ls->theta; + + repeats = 1; + } + else if (step == '-') + { + for (int j = 0; j < repeats; j++) turtle.angle += -ls->theta; + + repeats = 1; + } + else if (step == '[') + { + PushTurtleState(turtle); + } + else if (step == ']') + { + turtle = PopTurtleState(); + } + else if ((step >= 48) && (step <= 57)) + { + repeats = (int) step - 48; + } + } + + turtleTop = -1; +}