|
|
|
@ -16,14 +16,18 @@ |
|
|
|
* |
|
|
|
********************************************************************************************/ |
|
|
|
|
|
|
|
#include "raylib.h" |
|
|
|
|
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <math.h> |
|
|
|
#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,32 +44,111 @@ typedef struct PenroseLSystem { |
|
|
|
float theta; |
|
|
|
} PenroseLSystem; |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// Global Variables Definition |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
static TurtleState turtleStack[TURTLE_STACK_MAX_SIZE]; |
|
|
|
static int turtleTop = -1; |
|
|
|
|
|
|
|
void PushTurtleState(TurtleState state) |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// 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 |
|
|
|
//------------------------------------------------------------------------------------ |
|
|
|
int main(void) |
|
|
|
{ |
|
|
|
if (turtleTop < TURTLE_STACK_MAX_SIZE - 1) |
|
|
|
{ |
|
|
|
turtleStack[++turtleTop] = state; |
|
|
|
} |
|
|
|
else |
|
|
|
// Initialization |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
const int screenWidth = 800; |
|
|
|
const int screenHeight = 450; |
|
|
|
|
|
|
|
SetConfigFlags(FLAG_MSAA_4X_HINT); |
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - penrose tile"); |
|
|
|
|
|
|
|
float drawLength = 460.0f; |
|
|
|
int minGenerations = 0; |
|
|
|
int maxGenerations = 4; |
|
|
|
int generations = 0; |
|
|
|
|
|
|
|
PenroseLSystem ls = {0}; |
|
|
|
BuildPenroseLSystem(&ls, drawLength*(generations/(float)maxGenerations), generations); |
|
|
|
|
|
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second |
|
|
|
//--------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
// Main game loop |
|
|
|
while (!WindowShouldClose()) // Detect window close button or ESC key |
|
|
|
{ |
|
|
|
TraceLog(LOG_WARNING, "TURTLE STACK OVERFLOW!"); |
|
|
|
// Update |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
bool rebuild = false; |
|
|
|
if (IsKeyPressed(KEY_UP)) |
|
|
|
{ |
|
|
|
if (generations < maxGenerations) |
|
|
|
{ |
|
|
|
generations++; |
|
|
|
rebuild = true; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (IsKeyPressed(KEY_DOWN)) |
|
|
|
{ |
|
|
|
if (generations > minGenerations) |
|
|
|
{ |
|
|
|
generations--; |
|
|
|
if (generations > 0) rebuild = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (rebuild) BuildPenroseLSystem(&ls, drawLength*(generations/(float)maxGenerations), generations); |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
// Draw |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
BeginDrawing(); |
|
|
|
|
|
|
|
ClearBackground( RAYWHITE ); |
|
|
|
|
|
|
|
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(); |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
} |
|
|
|
|
|
|
|
// De-Initialization |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
CloseWindow(); // Close window and OpenGL context |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
// 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}; |
|
|
|
if (turtleTop >= 0) return turtleStack[turtleTop--]; |
|
|
|
else TraceLog(LOG_WARNING, "TURTLE STACK UNDERFLOW!"); |
|
|
|
|
|
|
|
return (TurtleState){ 0 }; |
|
|
|
} |
|
|
|
|
|
|
|
PenroseLSystem CreatePenroseLSystem(float drawLength) |
|
|
|
@ -77,86 +160,19 @@ PenroseLSystem CreatePenroseLSystem(float drawLength) |
|
|
|
.ruleY = "-WF++XF[+++YF++ZF]-", |
|
|
|
.ruleZ = "--YF++++WF[+ZF++++XF]--XF", |
|
|
|
.drawLength = drawLength, |
|
|
|
.theta = 36.0f // in degrees |
|
|
|
.theta = 36.0f // Degrees |
|
|
|
}; |
|
|
|
ls.production = (char*) malloc(sizeof(char) * STR_MAX_SIZE); |
|
|
|
|
|
|
|
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 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; |
|
|
|
|
|
|
|
return ls; |
|
|
|
} |
|
|
|
|
|
|
|
void BuildProductionStep(PenroseLSystem *ls) |
|
|
|
{ |
|
|
|
char *newProduction = (char*) malloc(sizeof(char) * STR_MAX_SIZE); |
|
|
|
char *newProduction = (char *)RL_MALLOC(sizeof(char)*STR_MAX_SIZE); |
|
|
|
newProduction[0] = '\0'; |
|
|
|
|
|
|
|
int productionLength = strnlen(ls->production, STR_MAX_SIZE); |
|
|
|
@ -177,7 +193,7 @@ void BuildProductionStep(PenroseLSystem *ls) |
|
|
|
{ |
|
|
|
int t = strnlen(newProduction, STR_MAX_SIZE); |
|
|
|
newProduction[t] = step; |
|
|
|
newProduction[t+1] = '\0'; |
|
|
|
newProduction[t + 1] = '\0'; |
|
|
|
} |
|
|
|
} break; |
|
|
|
} |
|
|
|
@ -185,89 +201,75 @@ void BuildProductionStep(PenroseLSystem *ls) |
|
|
|
|
|
|
|
ls->drawLength *= 0.5f; |
|
|
|
strncpy(ls->production, newProduction, STR_MAX_SIZE); |
|
|
|
free( newProduction ); |
|
|
|
|
|
|
|
RL_FREE(newProduction); |
|
|
|
} |
|
|
|
|
|
|
|
void BuildPenroseLSystem(PenroseLSystem *ls, float drawLength, int generations) |
|
|
|
{ |
|
|
|
*ls = CreatePenroseLSystem(drawLength); |
|
|
|
for (int i = 0; i < generations; i++) |
|
|
|
{ |
|
|
|
BuildProductionStep(ls); |
|
|
|
} |
|
|
|
for (int i = 0; i < generations; i++) BuildProductionStep(ls); |
|
|
|
} |
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------ |
|
|
|
// Program main entry point |
|
|
|
//------------------------------------------------------------------------------------ |
|
|
|
int main(void) |
|
|
|
void DrawPenroseLSystem(PenroseLSystem *ls) |
|
|
|
{ |
|
|
|
// Initialization |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
const int screenWidth = 800; |
|
|
|
const int screenHeight = 450; |
|
|
|
|
|
|
|
SetConfigFlags( FLAG_MSAA_4X_HINT ); |
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - penrose tile"); |
|
|
|
|
|
|
|
float drawLength = 460.0f; |
|
|
|
int minGenerations = 0; |
|
|
|
int maxGenerations = 4; |
|
|
|
int generations = 0; |
|
|
|
Vector2 screenCenter = { GetScreenWidth()/2, GetScreenHeight()/2 }; |
|
|
|
|
|
|
|
PenroseLSystem ls = {0}; |
|
|
|
BuildPenroseLSystem(&ls, drawLength * (generations / (float) maxGenerations), generations); |
|
|
|
|
|
|
|
SetTargetFPS(60); // Set our game to run at 60 frames-per-second |
|
|
|
//--------------------------------------------------------------------------------------- |
|
|
|
TurtleState turtle = { |
|
|
|
.origin = {0}, |
|
|
|
.angle = -90.0f |
|
|
|
}; |
|
|
|
|
|
|
|
// Main game loop |
|
|
|
while (!WindowShouldClose()) // Detect window close button or ESC key |
|
|
|
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++) |
|
|
|
{ |
|
|
|
// Update |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
bool rebuild = false; |
|
|
|
if (IsKeyPressed(KEY_UP)) |
|
|
|
char step = ls->production[i]; |
|
|
|
if (step == 'F') |
|
|
|
{ |
|
|
|
if (generations < maxGenerations) |
|
|
|
for (int j = 0; j < repeats; j++) |
|
|
|
{ |
|
|
|
generations++; |
|
|
|
rebuild = true; |
|
|
|
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)); |
|
|
|
} |
|
|
|
} |
|
|
|
else if (IsKeyPressed(KEY_DOWN)) |
|
|
|
|
|
|
|
repeats = 1; |
|
|
|
} |
|
|
|
else if (step == '+') |
|
|
|
{ |
|
|
|
if (generations > minGenerations) |
|
|
|
{ |
|
|
|
generations--; |
|
|
|
rebuild = generations > 0; |
|
|
|
} |
|
|
|
} |
|
|
|
if (rebuild) |
|
|
|
for (int j = 0; j < repeats; j++) turtle.angle += ls->theta; |
|
|
|
|
|
|
|
repeats = 1; |
|
|
|
} |
|
|
|
else if (step == '-') |
|
|
|
{ |
|
|
|
BuildPenroseLSystem(&ls, drawLength * (generations / (float) maxGenerations), generations); |
|
|
|
} |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
for (int j = 0; j < repeats; j++) turtle.angle += -ls->theta; |
|
|
|
|
|
|
|
// Draw |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
BeginDrawing(); |
|
|
|
ClearBackground( RAYWHITE ); |
|
|
|
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(); |
|
|
|
//---------------------------------------------------------------------------------- |
|
|
|
repeats = 1; |
|
|
|
} |
|
|
|
else if (step == '[') |
|
|
|
{ |
|
|
|
PushTurtleState(turtle); |
|
|
|
} |
|
|
|
else if (step == ']') |
|
|
|
{ |
|
|
|
turtle = PopTurtleState(); |
|
|
|
} |
|
|
|
else if ((step >= 48) && (step <= 57)) |
|
|
|
{ |
|
|
|
repeats = (int) step - 48; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// De-Initialization |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
CloseWindow(); // Close window and OpenGL context |
|
|
|
//-------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
turtleTop = -1; |
|
|
|
} |