/******************************************************************************************* * * raylib [models] example - rlgl module usage with push/pop matrix transformations * * This example uses [rlgl] module funtionality (pseudo-OpenGL 1.1 style coding) * * This example has been created using raylib 2.5 (www.raylib.com) * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) * * Copyright (c) 2018 Ramon Santamaria (@raysan5) * Copyright (c) 2019 Aldrin Martoq (@aldrinmartoq) * ********************************************************************************************/ #include "raylib.h" #include "rlgl.h" #define MAX_BODY_CHILDREN 10 float rotationSpeed = 0.2; // A celestial body that has children bodies orbiting around typedef struct Body { const char *label; // label of the body, for ex: moon float radius; // object radius float orbitRadius; // orbit average radius float orbitPeriod; // time the body takes to do a full loop Color color; // color of the body float orbitPosition; // current orbit position Vector2 labelPosition; // label position in screen struct Body *children[MAX_BODY_CHILDREN]; // children array int childrenCount; // children count } Body; //------------------------------------------------------------------------------------ // Module Functions Declaration //------------------------------------------------------------------------------------ Body CreateBody(float radius, float orbitRadius, float orbitPeriod, Color color, const char *label); // Initializes a new Body with the given parameters void AddBodyChildren(Body *parent, Body *children); // Add a children body to the parent body void DrawSphereBasic(Color color); // Draw sphere without any matrix transformation void DrawBody(Body *body, Camera *camera); // Draw body and its children, updating labelPosition void DrawLabels(Body *body); // Draw body label and its children labels //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ int main(void) { // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 1024; const int screenHeight = 768; const char *text; bool gridEnabled = true; bool helpEnabled = false; bool labelEnabled = true; bool cameraParametersEnabled = true; InitWindow(screenWidth, screenHeight, "raylib [models] example - rlgl module usage with push/pop matrix transformations"); // Define the camera to look into our 3d world Camera camera = { 0 }; camera.position = (Vector3){ 8.0f, 8.0f, 8.0f }; camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; camera.fovy = 45.0f; camera.type = CAMERA_PERSPECTIVE; SetCameraMode(camera, CAMERA_FREE); SetTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- // Create Bodies Body sun = CreateBody(0.2, 0.0, 0, GOLD, "sun"); Body moon = CreateBody(0.05, 0.200, 24, GRAY, "moon"); Body mercury = CreateBody(0.05, 0.396, 90, GRAY, "mercury"); Body venus = CreateBody(0.05, 0.723, 210, MAGENTA, "venus"); Body earth = CreateBody(0.05, 1.000, 365, BLUE, "earth"); Body mars = CreateBody(0.05, 1.523, 690, RED, "mars"); Body jupiter = CreateBody(0.05, 5.200, 4260, BROWN, "jupiter"); Body saturn = CreateBody(0.05, 9.532, 10620, GREEN, "saturn"); Body uranus = CreateBody(0.05, 19.180, 30270, SKYBLUE, "uranus"); Body neptune = CreateBody(0.05, 30.056, 59370, PURPLE, "neptune"); Body pluto = CreateBody(0.05, 39.463, 89310, DARKGREEN, "pluto"); AddBodyChildren(&sun, &mercury); AddBodyChildren(&sun, &venus); AddBodyChildren(&sun, &earth); AddBodyChildren(&sun, &mars); AddBodyChildren(&sun, &jupiter); AddBodyChildren(&sun, &saturn); AddBodyChildren(&sun, &uranus); AddBodyChildren(&sun, &neptune); AddBodyChildren(&sun, &pluto); AddBodyChildren(&earth, &moon); // Main game loop while (!WindowShouldClose()) // Detect window close button or ESC key { // Update //---------------------------------------------------------------------------------- UpdateCamera(&camera); if (IsKeyPressed(KEY_G)) { gridEnabled = !gridEnabled; } if (IsKeyPressed(KEY_H)) { helpEnabled = !helpEnabled; } if (IsKeyPressed(KEY_L)) { labelEnabled = !labelEnabled; } if (IsKeyPressed(KEY_P)) { cameraParametersEnabled = !cameraParametersEnabled; } if (IsKeyPressed(KEY_LEFT)) { rotationSpeed -= 0.1; } if (IsKeyPressed(KEY_RIGHT)) { rotationSpeed += 0.1; } // Draw //---------------------------------------------------------------------------------- BeginDrawing(); ClearBackground(RAYWHITE); BeginMode3D(camera); DrawBody(&sun, &camera); // Some reference elements (not affected by previous matrix transformations) if (gridEnabled) { DrawGrid(80, 1.0f); } EndMode3D(); if (labelEnabled) { DrawLabels(&sun); } DrawText("FULL SOLAR SYSTEM", 400, 10, 20, MAROON); text = FormatText("SPEED: %2.2f", rotationSpeed); DrawText(text, 1024 / 2 - MeasureText(text, 20) / 2, 30, 20, MAROON); if (cameraParametersEnabled) { text = FormatText("Camera\nposition: [%3.3f, %3.3f, %3.3f]\ntarget: [%3.3f, %3.3f, %3.3f]\nup: [%3.3f, %3.3f, %3.3f]", camera.position.x, camera.position.y, camera.position.z, camera.target.x, camera.target.y, camera.target.z, camera.up.x, camera.up.y, camera.up.z); DrawText(text, 10, 50, 20, MAROON); } if (helpEnabled) { DrawText("Keys:\n- [g] toggle grid\n- [h] toggle help\n- [l] toggle labels\n- [p] toggle camera parameters\n- [left/right arrows] increase/decrease speed by 0.1", 200, 200, 20, MAROON); } else { DrawText("press [h] for help", 1016 - MeasureText("press [h] for help", 20), 740, 20, MAROON); } DrawFPS(10, 10); EndDrawing(); //---------------------------------------------------------------------------------- } // De-Initialization //-------------------------------------------------------------------------------------- CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; } //-------------------------------------------------------------------------------------------- // Module Functions Definitions (local) //-------------------------------------------------------------------------------------------- // Creates a new body Body CreateBody(float radius, float orbitRadius, float orbitPeriod, Color color, const char *label) { Body body; body.label = label; body.radius = radius; body.orbitRadius = orbitRadius; body.orbitPeriod = orbitPeriod; body.color = color; body.childrenCount = 0; body.orbitPosition = 0.0; return body; } void AddBodyChildren(Body *parent, Body *children) { if (parent->childrenCount >= MAX_BODY_CHILDREN) { TraceLog(LOG_ERROR, "BODY HAS TOO MANY CHILDREN"); } else { parent->children[parent->childrenCount] = children; parent->childrenCount++; } } // Draw body and its children void DrawBody(Body *body, Camera *camera) { rlPushMatrix(); rlScalef(body->radius, body->radius, body->radius); // Scale Sun DrawSphereBasic(body->color); // Draw the body rlPopMatrix(); body->labelPosition = GetWorldToScreen((Vector3) { body->orbitRadius, body->radius, 0.0 }, *camera); for (int i = 0; i < body->childrenCount; i++) { Body *child = body->children[i]; child->orbitPosition += rotationSpeed * 360 / child->orbitPeriod; rlPushMatrix(); rlRotatef(child->orbitPosition, 0.0, 1.0, 0.0); rlTranslatef(child->orbitRadius, 0.0, 0.0); rlRotatef(-child->orbitPosition, 0.0, 1.0, 0.0); DrawBody(child, camera); rlPopMatrix(); DrawCircle3D((Vector3){ 0.0f, 0.0f, 0.0f }, child->orbitRadius, (Vector3){ 1.0f, 0.0f, 0.0f }, 90.0f, child->color); } } // Draw body label and its children labels void DrawLabels(Body *body) { DrawText(body->label, body->labelPosition.x - MeasureText(body->label, 20) / 2, body->labelPosition.y, 20, BLACK); for (int i = 0; i < body->childrenCount; i++) { Body *child = body->children[i]; DrawLabels(child); } } // Draw sphere without any matrix transformation // NOTE: Sphere is drawn in world position ( 0, 0, 0 ) with radius 1.0f void DrawSphereBasic(Color color) { int rings = 16; int slices = 16; rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); for (int i = 0; i < (rings + 2); i++) { for (int j = 0; j < slices; j++) { rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*i)), cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*(j*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*(j*360/slices))); rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*i))*sinf(DEG2RAD*(j*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*i)), cosf(DEG2RAD*(270+(180/(rings + 1))*i))*cosf(DEG2RAD*(j*360/slices))); rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*sinf(DEG2RAD*((j+1)*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*(i))), cosf(DEG2RAD*(270+(180/(rings + 1))*(i)))*cosf(DEG2RAD*((j+1)*360/slices))); rlVertex3f(cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*sinf(DEG2RAD*((j+1)*360/slices)), sinf(DEG2RAD*(270+(180/(rings + 1))*(i+1))), cosf(DEG2RAD*(270+(180/(rings + 1))*(i+1)))*cosf(DEG2RAD*((j+1)*360/slices))); } } rlEnd(); }