diff --git a/.clangd b/.clangd new file mode 100644 index 0000000000000000000000000000000000000000..6a411d6e9e5593225fc5b19ebbc9ef592d584148 --- /dev/null +++ b/.clangd @@ -0,0 +1,4 @@ +CompileFlags: + Add: + - "-DGL_SILENCE_DEPRECATION" + - "-Wno-deprecated-declarations" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ba2906d0666cf726c7eaadd2cd3db615dedfdf3a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +main diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..538f6dc3d1ae4713b4e1d8d4ee2fd73c4aa07266 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CC := clang +CFLAGS := -std=c99 -Wall -Wextra +LDFLAGS := -lm +SYSTEM := $(shell uname -s) + +ifeq ($(SYSTEM), Linux) + LDFLAGS += -lGL -lglut +endif + +ifeq ($(SYSTEM), Darwin) + LDFLAGS += -framework OpenGL -framework GLUT +endif + +main: main.c + clang $(CFLAGS) main.c -o main $(LDFLAGS) diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..219433091ee303fce838ecfd8c7d4d5fdeab7d50 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +sudo xbps-install -S mesa-devel libfreeglut-devel diff --git a/docs/glut-3.spec.pdf b/docs/glut-3.spec.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d8bb89293575ede121533cb579569798a5ea0c0a Binary files /dev/null and b/docs/glut-3.spec.pdf differ diff --git a/docs/openglguide.pdf b/docs/openglguide.pdf new file mode 100644 index 0000000000000000000000000000000000000000..14063f91f2ccf9817e3b2c15aedfec8534fdb38a Binary files /dev/null and b/docs/openglguide.pdf differ diff --git a/main.c b/main.c new file mode 100644 index 0000000000000000000000000000000000000000..dd4f4b8b6f7af43f3282c3a5cdb5af3aa7cfe3bd --- /dev/null +++ b/main.c @@ -0,0 +1,240 @@ +#include +#include +#include + +#ifdef __APPLE__ + #include + #include +#else + #include + #include +#endif + + +typedef struct { + int target_fps; + int width; + int height; + int last_time; + + float x_offset; + float y_offset; + float cube_angle; +} Game; + +Game game = {0}; + +void render_text(float x, float y, void* font, const char* string) { + glRasterPos2f(x, y); + for (const char* c = string; *c != '\0'; c++) { + glutBitmapCharacter(font, *c); + } +} + +void draw_cube(void) { + glBegin(GL_QUADS); + // Front Face (White) + glColor3f(1.0f, 1.0f, 1.0f); + glVertex3f(-0.1f, -0.1f, 0.1f); + glVertex3f( 0.1f, -0.1f, 0.1f); + glVertex3f( 0.1f, 0.1f, 0.1f); + glVertex3f(-0.1f, 0.1f, 0.1f); + + // Back Face (Yellow) + glColor3f(1.0f, 1.0f, 0.0f); + glVertex3f(-0.1f, -0.1f, -0.1f); + glVertex3f(-0.1f, 0.1f, -0.1f); + glVertex3f( 0.1f, 0.1f, -0.1f); + glVertex3f( 0.1f, -0.1f, -0.1f); + + // Top Face (Blue) + glColor3f(0.0f, 0.0f, 1.0f); + glVertex3f(-0.1f, 0.1f, -0.1f); + glVertex3f(-0.1f, 0.1f, 0.1f); + glVertex3f( 0.1f, 0.1f, 0.1f); + glVertex3f( 0.1f, 0.1f, -0.1f); + + // Bottom Face (Red) + glColor3f(1.0f, 0.0f, 1.0f); + glVertex3f(-0.1f, -0.1f, -0.1f); + glVertex3f( 0.1f, -0.1f, -0.1f); + glVertex3f( 0.1f, -0.1f, 0.1f); + glVertex3f(-0.1f, -0.1f, 0.1f); + + // Right Face (Magenta) + glColor3f(1.0f, 0.0f, 1.0f); + glVertex3f( 0.1f, -0.1f, -0.1f); + glVertex3f( 0.1f, 0.1f, -0.1f); + glVertex3f( 0.1f, 0.1f, 0.1f); + glVertex3f( 0.1f, -0.1f, 0.1f); + + // Left Face (Cyan) + glColor3f(0.0f, 1.0f, 1.0f); + glVertex3f(-0.1f, -0.1f, -0.1f); + glVertex3f(-0.1f, -0.1f, 0.1f); + glVertex3f(-0.1f, 0.1f, 0.1f); + glVertex3f(-0.1f, 0.1f, -0.1f); + glEnd(); +} + +void draw_quad() { + glBegin(GL_POLYGON); + glVertex3f (0.25, 0.25, 0.0); + glVertex3f (0.75, 0.25, 0.0); + glVertex3f (0.75, 0.75, 0.0); + glVertex3f (0.25, 0.75, 0.0); + glEnd(); +} + +void render_display(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + // Render Moving Square + /* glPushMatrix(); */ + /* glTranslatef(x_offset, y_offset, 0.0f); */ + /* glColor3f(1.0, 1.0, 1.0); */ + /* draw_quad(); */ + /* glPopMatrix(); */ + + // Render Spinning Cube + glPushMatrix(); + glTranslatef(0.5f, 0.5f, 0.0f); + glRotatef(game.cube_angle, 1.0f, 1.0f, 1.0f); + draw_cube(); + glPopMatrix(); + + // Render UI Text + glLoadIdentity(); + glColor3f(0.0, 1.0, 0.0); + char fps_text[32]; + snprintf(fps_text, sizeof fps_text, "FPS: %d", game.target_fps); + render_text(0.05f, 0.93f, GLUT_BITMAP_HELVETICA_18, fps_text); + + glutSwapBuffers(); +} + +void timer(int value) { + (void)value; + + int current_time = glutGet(GLUT_ELAPSED_TIME); + float delta_time = (current_time - game.last_time) / 1000.0f; + game.last_time = current_time; + + // Rotate 120 degrees per second + game.cube_angle += 120.0f * delta_time; + if (game.cube_angle > 360) game.cube_angle -= 360; + + glutPostRedisplay(); + glutTimerFunc(1000 / game.target_fps, timer, 0); +} + +void init_display(void) { + glClearColor(0.4, 0.4, 1.0, 0.0); + glEnable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); +} + +void handle_mouse_event(int button, int state, int x, int y) { + switch (button) { + case GLUT_LEFT_BUTTON: + if (state == GLUT_DOWN) printf("Left button clicked (x: %d, y: %d)\n", x, y); + break; + case GLUT_MIDDLE_BUTTON: + if (state == GLUT_DOWN) printf("Middle button clicked (x: %d, y: %d)\n", x, y); + break; + case GLUT_RIGHT_BUTTON: + if (state == GLUT_DOWN) printf("Right button clicked (x: %d, y: %d)\n", x, y); + break; + default: break; + } +} + +void handle_keyboard_event(unsigned char key, int x, int y) { + (void)x; (void)y; + float fraction = 0.05f; + + switch (key) { + case 27: exit(0); break; + case 'w': game.y_offset += fraction; break; + case 's': game.y_offset -= fraction; break; + case 'a': game.x_offset -= fraction; break; + case 'd': game.x_offset += fraction; break; + case '+': + game.target_fps += 5; + printf("Target FPS: %d\n", game.target_fps); + break; + case '-': + if (game.target_fps > 5) game.target_fps -= 5; + printf("Target FPS: %d\n", game.target_fps); + break; + default: + printf("Unknown key: %c\n", key); + break; + } +} + +void handle_reshape(int w, int h) { + glViewport (0, 0, (GLsizei) w, (GLsizei) h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +int main(int argc, char** argv) { + static struct option long_options[] = { + {"fps", required_argument, 0, 'f'}, + {"width", required_argument, 0, 'w'}, + {"height", required_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + game.width = 800; + game.height = 600; + game.target_fps = 60; + + int opt; + int option_index = 0; + while ((opt = getopt_long_only(argc, argv, "m:f:w:h:", long_options, &option_index)) != -1) { + switch (opt) { + case 'f': + game.target_fps = atoi(optarg); + break; + case 'w': + game.width = atoi(optarg); + break; + case 'h': + game.height = atoi(optarg); + break; + } + } + + glutInit(&argc, argv); + + int x = (glutGet(GLUT_SCREEN_WIDTH) - game.width) / 2; + int y = (glutGet(GLUT_SCREEN_HEIGHT) - game.height) / 2; + + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowSize(game.width, game.height); + glutInitWindowPosition(x, y); + glutCreateWindow("floating"); + + init_display(); + + game.last_time = glutGet(GLUT_ELAPSED_TIME); + + glutDisplayFunc(render_display); + glutReshapeFunc(handle_reshape); + glutTimerFunc(1000 / game.target_fps, timer, 0); + glutMouseFunc(handle_mouse_event); + glutKeyboardFunc(handle_keyboard_event); + + glutMainLoop(); + return 0; +}