Skip to content
Snippets Groups Projects
Commit 1022a015 authored by florian.burgener's avatar florian.burgener
Browse files

Add OpenGL

parent 88c1ff04
No related branches found
No related tags found
No related merge requests found
......@@ -2,7 +2,6 @@
#define CELESTIAL_OBJECT_H
#include "Vector2.h"
#include "gfx/gfx.h"
typedef struct CelestialObject CelestialObject;
typedef struct CelestialObject {
......
......@@ -2,14 +2,13 @@ TARGET = main
CC:=gcc
# CFLAGS:=-g -Ofast -Wall -Wextra -fsanitize=address -fsanitize=leak -std=gnu11
# CFLAGS:=-fsanitize=address
CFLAGS:=-g -Ofast -Wall -Wextra -std=gnu11
LDFLAGS:=-lm -lSDL2
VPATH:=gfx
CFLAGS:=-g -O3 -Wall -Wextra -std=gnu11
LDFLAGS:=-lm -lGL -lGLU -lglut
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): main.o Vector2.o CelestialObject.o PlanetarySystem.o gfx.o
$(TARGET): main.o Vector2.o CelestialObject.o PlanetarySystem.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean:
......
#include "PlanetarySystem.h"
#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>
#include "CelestialObject.h"
#include "Vector2.h"
#include "gfx/gfx.h"
const uint32_t SCREEN_WIDTH = 1000;
const uint32_t SCREEN_HEIGHT = 1000;
......@@ -30,20 +31,19 @@ const double VENUS_SEMI_MAJOR_AXIS = 108.208475 * 1E9;
const double EARTH_SEMI_MAJOR_AXIS = 149.598262 * 1E9;
const double MARS_SEMI_MAJOR_AXIS = 227.943824 * 1E9;
PlanetarySystem *planetary_system_create(double interval) {
PlanetarySystem *planetary_system_create() {
PlanetarySystem *planetary_system = (PlanetarySystem *)malloc(sizeof(PlanetarySystem));
planetary_system->objects_length = 6;
planetary_system->objects = (CelestialObject **)malloc(sizeof(PlanetarySystem *) * planetary_system->objects_length);
planetary_system->interval = interval;
planetary_system->zoom_factor = 1;
planetary_system->reference_frame_object_index = 0;
planetary_system->objects[0] = celestial_object_create(SUN_MASS, 0, 0, 50, 0x00FFFFFF);
planetary_system->objects[1] = celestial_object_create(MERCURY_MASS, MERCURY_SEMI_MAJOR_AXIS, MERCURY_ECCENTRICITY, 10, 0x00DBCECA);
planetary_system->objects[2] = celestial_object_create(VENUS_MASS, VENUS_SEMI_MAJOR_AXIS, VENUS_ECCENTRICITY, 20, 0x008B7D82);
planetary_system->objects[3] = celestial_object_create(EARTH_MASS, EARTH_SEMI_MAJOR_AXIS, EARTH_ECCENTRICITY, 20, 0x006b93d6);
planetary_system->objects[4] = celestial_object_create(MARS_MASS, MARS_SEMI_MAJOR_AXIS, MARS_ECCENTRICITY, 12, 0x00BC2732);
planetary_system->objects[0] = celestial_object_create(SUN_MASS, 0, 0, 50, 0xFFFFFF);
planetary_system->objects[1] = celestial_object_create(MERCURY_MASS, MERCURY_SEMI_MAJOR_AXIS, MERCURY_ECCENTRICITY, 10, 0xDBCECA);
planetary_system->objects[2] = celestial_object_create(VENUS_MASS, VENUS_SEMI_MAJOR_AXIS, VENUS_ECCENTRICITY, 20, 0x8B7D82);
planetary_system->objects[3] = celestial_object_create(EARTH_MASS, EARTH_SEMI_MAJOR_AXIS, EARTH_ECCENTRICITY, 20, 0x6b93d6);
planetary_system->objects[4] = celestial_object_create(MARS_MASS, MARS_SEMI_MAJOR_AXIS, MARS_ECCENTRICITY, 12, 0xBC2732);
planetary_system->objects[5] = celestial_object_create(7.34767309 * 1E22, 384.399 * 1E6, 0.0549, 5, 0x8A2BE2);
planetary_system->objects[5]->current_position.x += planetary_system->objects[3]->current_position.x;
......@@ -68,7 +68,7 @@ Vector2 calculate_gravitational_acceleration(PlanetarySystem *planetary_system,
return a;
}
void planetary_system_update(PlanetarySystem *planetary_system) {
void planetary_system_update(PlanetarySystem *planetary_system, double interval) {
for (uint32_t i = 1; i < planetary_system->objects_length; i += 1) {
CelestialObject *object = planetary_system->objects[i];
Vector2 current_position = object->current_position;
......@@ -84,20 +84,19 @@ void planetary_system_update(PlanetarySystem *planetary_system) {
double periapsis_velocity_scalar = sqrt((G * star->mass * (1 + object->eccentricity)) / (object->semi_major_axis * (1 - object->eccentricity)));
if (i == 5) {
printf("%lf\n", periapsis_velocity_scalar);
periapsis_velocity_scalar += 30290.322245;
}
Vector2 r = vector2_normalize(vector2_create(current_position.y, -current_position.x));
Vector2 periapsis_velocity = vector2_multiply(r, periapsis_velocity_scalar);
new_position = vector2_add(current_position, vector2_multiply(periapsis_velocity, planetary_system->interval));
new_position = vector2_add(current_position, vector2_multiply(periapsis_velocity, interval));
Vector2 a = calculate_gravitational_acceleration(planetary_system, i);
new_position = vector2_add(new_position, vector2_multiply(a, 0.5 * pow(planetary_system->interval, 2)));
new_position = vector2_add(new_position, vector2_multiply(a, 0.5 * pow(interval, 2)));
} else {
new_position = vector2_substract(vector2_multiply(current_position, 2), object->previous_position);
Vector2 a = calculate_gravitational_acceleration(planetary_system, i);
new_position = vector2_add(new_position, vector2_multiply(a, pow(planetary_system->interval, 2)));
new_position = vector2_add(new_position, vector2_multiply(a, pow(interval, 2)));
}
object->previous_position = object->current_position;
......@@ -106,20 +105,29 @@ void planetary_system_update(PlanetarySystem *planetary_system) {
}
Vector2 scale_position(Vector2 position) {
Vector2 scaled_position = vector2_multiply(position, 1.0 / (250 * 1E9));
Vector2 scaled_position = vector2_multiply(position, 1.0 / (260 * 1E9));
scaled_position = vector2_fit_canvas(scaled_position, SCREEN_WIDTH, SCREEN_HEIGHT);
return scaled_position;
}
void planetary_system_draw(PlanetarySystem *planetary_system, struct gfx_context_t *context) {
gfx_clear(context, COLOR_BLACK);
void planetary_system_draw(PlanetarySystem *planetary_system) {
for (uint32_t i = 0; i < planetary_system->objects_length; i += 1) {
CelestialObject *object = planetary_system->objects[i];
Vector2 tmp = vector2_substract(object->current_position, planetary_system->objects[planetary_system->reference_frame_object_index]->current_position);
tmp = vector2_multiply(tmp, planetary_system->zoom_factor);
Vector2 scaled_position = scale_position(tmp);
Vector2 unscaled_position = vector2_substract(object->current_position, planetary_system->objects[planetary_system->reference_frame_object_index]->current_position);
unscaled_position = vector2_multiply(unscaled_position, planetary_system->zoom_factor);
Vector2 scaled_position = scale_position(unscaled_position);
uint32_t color = object->drawing_color;
glColor3ub((color & 0xFF0000) >> 16, (color & 0x00FF00) >> 8, (color & 0x0000FF) >> 0);
glBegin(GL_POLYGON);
for (uint32_t i = 0; i < 360; i += 1) {
double theta = i * 3.1415 / 180;
double x = scaled_position.x + object->drawing_disc_radius * cos(theta);
double y = scaled_position.y + object->drawing_disc_radius * sin(theta);
glVertex2f(x, y);
}
draw_full_circle(context, scaled_position.x, scaled_position.y, object->drawing_disc_radius, object->drawing_color);
glEnd();
}
}
......@@ -4,7 +4,6 @@
#include <stdint.h>
#include "CelestialObject.h"
#include "gfx/gfx.h"
const uint32_t SCREEN_WIDTH;
const uint32_t SCREEN_HEIGHT;
......@@ -17,8 +16,8 @@ typedef struct {
int32_t reference_frame_object_index;
} PlanetarySystem;
PlanetarySystem *planetary_system_create(double interval);
void planetary_system_update(PlanetarySystem *planetary_system);
void planetary_system_draw(PlanetarySystem *planetary_system, struct gfx_context_t *context);
PlanetarySystem *planetary_system_create();
void planetary_system_update(PlanetarySystem *planetary_system, double interval);
void planetary_system_draw(PlanetarySystem *planetary_system);
#endif
README 0 → 100644
sudo apt-get install freeglut3-dev
/// @file gfx.c
/// @author Florent Gluck
/// @date November 6, 2016
/// Helper routines to render pixels in fullscreen graphic mode.
/// Uses the SDL2 library.
/// Update : Add full circle
/// @author Michaël El Kharroubi
/// @date 19 November 2021
#include "gfx.h"
#include <assert.h>
/// Create a fullscreen graphic window.
/// @param title Title of the window.
/// @param width Width of the window in pixels.
/// @param height Height of the window in pixels.
/// @return a pointer to the graphic context or NULL if it failed.
struct gfx_context_t *gfx_create(char *title, uint32_t width, uint32_t height)
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
goto error;
SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_RESIZABLE);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, width, height);
uint32_t *pixels = malloc(width * height * sizeof(uint32_t));
struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t));
if (!window || !renderer || !texture || !pixels || !ctxt)
goto error;
ctxt->renderer = renderer;
ctxt->texture = texture;
ctxt->window = window;
ctxt->width = width;
ctxt->height = height;
ctxt->pixels = pixels;
SDL_ShowCursor(SDL_DISABLE);
gfx_clear(ctxt, COLOR_BLACK);
return ctxt;
error:
return NULL;
}
/// Draw a pixel in the specified graphic context.
/// @param ctxt Graphic context where the pixel is to be drawn.
/// @param column X coordinate of the pixel.
/// @param row Y coordinate of the pixel.
/// @param color Color of the pixel.
void gfx_putpixel(struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color)
{
if (column < ctxt->width && row < ctxt->height)
ctxt->pixels[ctxt->width * row + column] = color;
}
/// Clear the specified graphic context.
/// @param ctxt Graphic context to clear.
/// @param color Color to use.
void gfx_clear(struct gfx_context_t *ctxt, uint32_t color)
{
int n = ctxt->width * ctxt->height;
while (n)
ctxt->pixels[--n] = color;
}
/// Display the graphic context.
/// @param ctxt Graphic context to clear.
void gfx_present(struct gfx_context_t *ctxt)
{
SDL_UpdateTexture(
ctxt->texture, NULL, ctxt->pixels, ctxt->width * sizeof(uint32_t));
SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL);
SDL_RenderPresent(ctxt->renderer);
}
/// Destroy a graphic window.
/// @param ctxt Graphic context of the window to close.
void gfx_destroy(struct gfx_context_t *ctxt)
{
SDL_ShowCursor(SDL_ENABLE);
SDL_DestroyTexture(ctxt->texture);
SDL_DestroyRenderer(ctxt->renderer);
SDL_DestroyWindow(ctxt->window);
free(ctxt->pixels);
ctxt->texture = NULL;
ctxt->renderer = NULL;
ctxt->window = NULL;
ctxt->pixels = NULL;
SDL_Quit();
free(ctxt);
}
/// If a key was pressed, returns its key code (non blocking call).
/// List of key codes: https://wiki.libsdl.org/SDL_Keycode
/// @return the key that was pressed or 0 if none was pressed.
SDL_Keycode gfx_keypressed()
{
SDL_Event event;
if (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN)
return event.key.keysym.sym;
}
return 0;
}
/// Draw a full circle using Andres's discrete circle algorithm.
/// @param ctxt Graphic context to clear.
/// @param c_column X coordinate of the circle center.
/// @param c_row Y coordinate of the circle center.
/// @param r The radius of circle (in pixels).
/// @param color Color to use.
void draw_full_circle(struct gfx_context_t *ctxt, uint32_t c_column, uint32_t c_row, uint32_t r, uint32_t color)
{
int32_t x = 0, y = r, d = r - 1;
while (y >= x)
{
gfx_putpixel(ctxt, c_column + x, c_row + y, color);
gfx_putpixel(ctxt, c_column + y, c_row + x, color);
gfx_putpixel(ctxt, c_column - x, c_row + y, color);
gfx_putpixel(ctxt, c_column - y, c_row + x, color);
gfx_putpixel(ctxt, c_column + x, c_row - y, color);
gfx_putpixel(ctxt, c_column + y, c_row - x, color);
gfx_putpixel(ctxt, c_column - x, c_row - y, color);
gfx_putpixel(ctxt, c_column - y, c_row - x, color);
if ((2 * x) <= d)
{
d -= 2 * x + 1;
x += 1;
}
else if (d < (2 * (((int32_t)r) - y)))
{
d += 2 * y - 1;
y -= 1;
}
else
{
d -= 2 * (x - y + 1);
y -= 1;
x += 1;
}
}
if (r > 0)
draw_full_circle(ctxt, c_column, c_row, r - 1, color);
}
#ifndef _GFX_H_
#define _GFX_H_
#include <SDL2/SDL.h>
#include <stdbool.h>
#include <stdint.h>
#define MAKE_COLOR(r, g, b) \
((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16))
#define COLOR_GET_B(color) (color & 0xff)
#define COLOR_GET_G(color) ((color >> 8) & 0xff)
#define COLOR_GET_R(color) ((color >> 16) & 0xff)
#define COLOR_BLACK 0x00000000
#define COLOR_RED 0x00FF0000
#define COLOR_GREEN 0x0000FF00
#define COLOR_BLUE 0x000000FF
#define COLOR_WHITE 0x00FFFFFF
#define COLOR_YELLOW 0x00FFFF00
struct gfx_context_t
{
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
uint32_t *pixels;
uint32_t width;
uint32_t height;
};
extern void gfx_putpixel(
struct gfx_context_t *ctxt, uint32_t column, uint32_t row, uint32_t color);
extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color);
extern struct gfx_context_t *gfx_create(char *text, uint32_t width, uint32_t height);
extern void gfx_destroy(struct gfx_context_t *ctxt);
extern void gfx_present(struct gfx_context_t *ctxt);
extern SDL_Keycode gfx_keypressed();
extern void draw_full_circle(struct gfx_context_t *ctxt, uint32_t c_column, uint32_t c_row, uint32_t r, uint32_t color);
#endif
#include <GL/glut.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -5,79 +6,115 @@
#include "PlanetarySystem.h"
#include "Vector2.h"
#include "gfx/gfx.h"
int main() {
// srand(time(NULL));
// srand(0);
#define WINDOW_NAME "Solar System"
#define REFRESH_RATE 100
#define UPDATE_RATE 10000
#define TIME_ELASPING_PER_SECOND 3600 * 24 * 30
// https://stackoverflow.com/questions/3417837/what-is-the-best-way-to-suppress-a-unused-variable-x-warning
#ifdef UNUSED
#elif defined(__GNUC__)
#define UNUSED(x) UNUSED_##x __attribute__((unused))
#elif defined(__LCLINT__)
#define UNUSED(x) /*@unused@*/ x
#else
#define UNUSED(x) x
#endif
PlanetarySystem *planetary_system;
uint32_t elapsed_time = 0;
uint32_t true_time_shift = 0;
void draw_timer() {
glutPostRedisplay();
glutTimerFunc(1000 / REFRESH_RATE, draw_timer, 0);
elapsed_time += 1;
}
void update_timer() {
for (uint32_t i = 0; i < UPDATE_RATE / REFRESH_RATE; i += 1) {
planetary_system_update(planetary_system, (double)TIME_ELASPING_PER_SECOND / UPDATE_RATE);
}
struct gfx_context_t *context = gfx_create("Solar System", SCREEN_WIDTH, SCREEN_HEIGHT);
glutTimerFunc(1000 / REFRESH_RATE, update_timer, 0);
}
void draw() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
if (!context) {
fprintf(stderr, "Graphics initialization failed!\n");
return EXIT_FAILURE;
if (elapsed_time % REFRESH_RATE == 0) {
char title[100];
sprintf(title, "Solar System (%d : %ld)", elapsed_time / REFRESH_RATE, (time(NULL) - true_time_shift) % 1000);
glutSetWindowTitle(title);
}
int32_t time_elapsing_per_second = 3600 * 24 * 5;
int32_t refresh_rate = 240;
int32_t elapsed_time = 0;
double sleep_duration = 1.0 / refresh_rate * 1E9;
printf("%lf\n", (double)time_elapsing_per_second / refresh_rate);
planetary_system_draw(planetary_system);
PlanetarySystem *planetary_system = planetary_system_create((double)time_elapsing_per_second / refresh_rate);
glFlush();
}
int64_t tmp = time(NULL) % 1000;
void handle_keyboard_input(unsigned char key, int UNUSED(x), int UNUSED(y)) {
if (key == 27) {
exit(0);
}
}
while (true) {
planetary_system_update(planetary_system);
gfx_present(context);
planetary_system_draw(planetary_system, context);
void handle_special_keyboard_input(int key, int UNUSED(x), int UNUSED(y)) {
if (key == GLUT_KEY_LEFT) {
planetary_system->reference_frame_object_index -= 1;
if (elapsed_time % refresh_rate == 0) {
char title[100];
sprintf(title, "Solar System (%d : %ld)", elapsed_time / refresh_rate, (time(NULL) - tmp) % 1000);
SDL_SetWindowTitle(context->window, title);
if (planetary_system->reference_frame_object_index < 0) {
planetary_system->reference_frame_object_index = planetary_system->objects_length - 1;
}
}
SDL_Event event;
if (SDL_PollEvent(&event)) {
if (event.type == SDL_MOUSEWHEEL) {
if (event.wheel.y > 0) {
planetary_system->zoom_factor *= 1.1;
} else if (event.wheel.y < 0) {
planetary_system->zoom_factor /= 1.1;
if (planetary_system->zoom_factor < 1) {
planetary_system->zoom_factor = 1;
}
}
}
if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
break;
}
if (key == GLUT_KEY_RIGHT) {
planetary_system->reference_frame_object_index += 1;
planetary_system->reference_frame_object_index %= planetary_system->objects_length;
}
}
if (event.key.keysym.sym == SDLK_LEFT) {
planetary_system->reference_frame_object_index -= 1;
void handle_mouse_input(int button, int state, int UNUSED(x), int UNUSED(y)) {
if (button == 3 || button == 4) {
if (state == GLUT_UP) return;
if (planetary_system->reference_frame_object_index < 0) {
planetary_system->reference_frame_object_index = planetary_system->objects_length - 1;
}
}
if (button == 3) {
planetary_system->zoom_factor *= 1.1;
} else {
planetary_system->zoom_factor /= 1.1;
if (event.key.keysym.sym == SDLK_RIGHT) {
planetary_system->reference_frame_object_index += 1;
planetary_system->reference_frame_object_index %= planetary_system->objects_length;
}
if (planetary_system->zoom_factor < 1) {
planetary_system->zoom_factor = 1;
}
}
struct timespec t = {.tv_sec = 0, .tv_nsec = sleep_duration};
nanosleep(&t, NULL);
elapsed_time += 1;
}
}
int main(int argc, char *argv[]) {
planetary_system = planetary_system_create();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(SCREEN_WIDTH, SCREEN_HEIGHT);
glutCreateWindow(WINDOW_NAME);
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
glutDisplayFunc(draw);
glutKeyboardFunc(handle_keyboard_input);
glutSpecialFunc(handle_special_keyboard_input);
glutMouseFunc(handle_mouse_input);
true_time_shift = time(NULL) % 1000;
glutTimerFunc(1000 / REFRESH_RATE, update_timer, 0);
glutTimerFunc(1000 / REFRESH_RATE, draw_timer, 0);
glutMainLoop();
gfx_destroy(context);
return EXIT_SUCCESS;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment