commit e2a0f56261cf47cdaea71dc1bd9f1b8a11c7e6e5 Author: Dan Cojocaru Date: Mon Mar 21 01:39:06 2022 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4d03491 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +program +obj/** \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d5ba7db --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,33 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/program", + "args": [], + "stopAtEntry": false, + "cwd": "${fileDirname}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ], + "preLaunchTask": "build debug" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1e82a33 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "array": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..24717cd --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,27 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "command": "make -B", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "build debug", + "type": "shell", + "options": { + "env": { + "CXX_PARAMS": "-g" + } + }, + "command": "make -B" + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6fb0854 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +LD_PARAMS := -lglut -lGL -lGLU +SRC := src +OBJ := obj +CXX := g++ +LD := g++ + +SOURCES := $(wildcard $(SRC)/*.cpp) +OBJECTS := $(patsubst $(SRC)/%.cpp, $(OBJ)/%.o, $(SOURCES)) + +all: program + +clean: + rm -f program + rm -rf obj + +program: ${OBJECTS} + $(LD) ${LD_PARAMS} $^ -o $@ + +$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.cpp + $(CXX) ${CXX_PARAMS} $< -c -o $@ \ No newline at end of file diff --git a/src/drawable.h b/src/drawable.h new file mode 100644 index 0000000..9e9afe1 --- /dev/null +++ b/src/drawable.h @@ -0,0 +1,6 @@ +#pragma once + +class Drawable { +public: + virtual void draw() = 0; +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..99e527c --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,201 @@ +#include +#include +#include + +#include +#include +#include + +#include "pixel_wise.h" +#include "drawable.h" +#include "utils.hpp" + +GLfloat deltaTime; + +bool gameRunning = false; + +bool mouseDown = false; +int leftScore = 0; +int rightScore = 0; + +int leftMove = 0; +int rightMove = 0; + +void mouse(int button, int state, int x, int y) { + if (state == GLUT_DOWN) { + gameRunning = true; + } +} + +class BoardMiddle : public Drawable { +public: + virtual void draw() { + glBegin(GL_POLYGON); + glColor3ub(0xBD, 0xBD, 0xBD); + glVertex2fv(PW::nm(-2, -1).data()); + glVertex2fv(PW::nm(2, -1).data()); + glVertex2fv(PW::nm(2, 1).data()); + glVertex2fv(PW::nm(-2, 1).data()); + glEnd(); + } +} bm; + +class Ball : public Drawable { +public: + GLfloat radius; + GLfloat x, y; + GLfloat veloX, veloY; + + Ball(GLfloat x, GLfloat y) : x(x), y(y), radius(0.025), veloX(0.4) { + + } + + virtual void draw() { + glBegin(GL_POLYGON); + glColor3ub(0xFF, 0xEE, 0x58); + for (float i = 0; i < 360; i += 0.5) { + const auto rad = Utils::toRad(i); + glVertex2f(x + radius * cos(rad), y + radius * sin(rad)); + } + glEnd(); + } + + void update() { + x += veloX * deltaTime; + y += veloY * deltaTime; + } +} ball {0, 0}; + +class Text : public Drawable { + std::function strObtainer; +public: + std::function x, y; + void *font; + Text(std::function strObtainer, GLfloat x, GLfloat y) : strObtainer(strObtainer), x([=](){return x;}), y([=](){return y;}), font(GLUT_BITMAP_HELVETICA_18) {} + Text(std::function strObtainer, std::function x, std::function y) : strObtainer(strObtainer), x(x), y(y), font(GLUT_BITMAP_HELVETICA_18) {} + Text(std::function strObtainer, std::array pos) : strObtainer(strObtainer), x([=](){return pos[0];}), y([=](){return pos[1];}), font(GLUT_BITMAP_HELVETICA_18) {} + Text(std::function strObtainer, std::function()> pos) : strObtainer(strObtainer), x([=](){return pos()[0];}), y([=](){return pos()[1];}), font(GLUT_BITMAP_HELVETICA_18) {} + + virtual void draw() { + glRasterPos2f(x(), y()); + for (const auto& c: strObtainer()) { + glutBitmapCharacter(font, c); + } + } +} leftScoreText{[](){ return std::to_string(leftScore); }, [](){return PW::tm(-100, 20);}}, + rightScoreText{[](){ return std::to_string(rightScore); }, [](){return PW::tm(100, 20);}}; + +class Paddle : public Drawable { +public: + GLfloat height, width; + GLfloat x, y; + + Paddle(GLfloat x, GLfloat y) : x(x), y(y), height(0.4), width(0.02) {} + + virtual void draw() { + glBegin(GL_POLYGON); + glVertex2f(x, y); + glVertex2f(x + width, y); + glVertex2f(x + width, y + height); + glVertex2f(x, y + height); + glEnd(); + } +} leftPaddle{-0.9, -0.2}, rightPaddle{0.9 - 0.02, -0.2}; + +void display(void) { + glClear(GL_COLOR_BUFFER_BIT); + + bm.draw(); + ball.draw(); + + glColor3ub(0x66, 0xBB, 0x6A); + leftScoreText.draw(); + leftPaddle.draw(); + + glColor3ub(0x42, 0xA5, 0xF5); + rightScoreText.draw(); + rightPaddle.draw(); + + glFlush(); +} + +int gameTime; + +const GLfloat paddleMoveSpeed = 0.75; + +void idle() { + int newTime = glutGet(GLUT_ELAPSED_TIME); + deltaTime = (newTime - gameTime) / 1000.0; + gameTime = newTime; + + if (gameRunning) { + ball.update(); + + // Move paddle + leftPaddle.y += leftMove * paddleMoveSpeed * deltaTime; + rightPaddle.y += rightMove * paddleMoveSpeed * deltaTime; + + // Clamp paddle to stay on screen + if (leftPaddle.y < -1) leftPaddle.y = -1; + if (rightPaddle.y < -1) rightPaddle.y = -1; + if (leftPaddle.y > 1 - leftPaddle.height) leftPaddle.y = 1 - leftPaddle.height; + if (rightPaddle.y > 1 - rightPaddle.height) rightPaddle.y = 1 - rightPaddle.height; + } + + glutPostRedisplay(); +} + +void keyDown(unsigned char key, int x, int y) { + switch(key) { + case 'w': + case 'W': + leftMove = 1; + break; + case 's': + case 'S': + leftMove = -1; + break; + case 'p': + case 'P': + rightMove = 1; + break; + case ';': + case ':': + rightMove = -1; + break; + } +} + +void keyUp(unsigned char key, int x, int y) { + switch(key) { + case 'w': + case 'W': + case 's': + case 'S': + leftMove = 0; + break; + case 'p': + case 'P': + case ';': + case ':': + rightMove = 0; + break; + } +} + +int main(int argc, char** argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); + glutInitWindowSize(600, 600); + glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH) * 0.6, (glutGet(GLUT_SCREEN_HEIGHT) - 600) * 0.5); + glutCreateWindow("Pong"); + glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); + glutKeyboardFunc(keyDown); + glutKeyboardUpFunc(keyUp); + glutDisplayFunc(display); + glutMouseFunc(mouse); + glutIdleFunc(idle); + glutMainLoop(); + return 0; +} diff --git a/src/pixel_wise.cpp b/src/pixel_wise.cpp new file mode 100644 index 0000000..a5736db --- /dev/null +++ b/src/pixel_wise.cpp @@ -0,0 +1,63 @@ +#include "pixel_wise.h" + +#include +#include "utils.hpp" + +// For personal reference: +// x - left->right +// y - bottom->top + +std::array PW::toRelative(GLfloat x, GLfloat y, PW::Anchor anchor) { + auto winWidth = glutGet(GLUT_WINDOW_WIDTH); + auto winHeight = glutGet(GLUT_WINDOW_HEIGHT); + + std::array result; + + switch (anchor) { + case PW::BOTTOM_LEFT: + case PW::MID_LEFT: + case PW::TOP_LEFT: + case PW::NONE_LEFT: + result[0] = Utils::nummap(x, (GLfloat)0, (GLfloat)winWidth, (GLfloat)-1, (GLfloat)1); + break; + case PW::BOTTOM_MID: + case PW::CENTER: + case PW::TOP_MID: + case PW::NONE_MID: + result[0] = Utils::nummap(x, -((GLfloat)winWidth) / 2, ((GLfloat)winWidth) / 2, (GLfloat)-1, (GLfloat)1); + break; + case PW::BOTTOM_RIGHT: + case PW::MID_RIGHT: + case PW::TOP_RIGHT: + case PW::NONE_RIGHT: + result[0] = Utils::nummap(x, -(GLfloat)winWidth, (GLfloat)0, (GLfloat)-1, (GLfloat)1); + break; + default: + result[0] = x; + } + + switch (anchor) { + case PW::TOP_LEFT: + case PW::TOP_MID: + case PW::TOP_RIGHT: + case PW::TOP_NONE: + result[1] = Utils::nummap(y, (GLfloat)0, (GLfloat)winHeight, (GLfloat)1, (GLfloat)-1); + break; + case PW::MID_LEFT: + case PW::CENTER: + case PW::MID_RIGHT: + case PW::MID_NONE: + result[1] = Utils::nummap(y, -((GLfloat)winHeight) / 2, ((GLfloat)winHeight) / 2, (GLfloat)1, (GLfloat)-1); + break; + case PW::BOTTOM_LEFT: + case PW::BOTTOM_MID: + case PW::BOTTOM_RIGHT: + case PW::BOTTOM_NONE: + result[1] = Utils::nummap(y, (GLfloat)0, -(GLfloat)winHeight, (GLfloat)1, (GLfloat)-1); + break; + default: + result[1] = y; + } + + return std::move(result); +} diff --git a/src/pixel_wise.h b/src/pixel_wise.h new file mode 100644 index 0000000..70cc066 --- /dev/null +++ b/src/pixel_wise.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#include + +namespace PW { + enum Anchor + { + MID_LEFT, + TOP_LEFT, + TOP_MID, + TOP_RIGHT, + MID_RIGHT, + BOTTOM_RIGHT, + BOTTOM_MID, + BOTTOM_LEFT, + CENTER, + TOP_NONE, + MID_NONE, + BOTTOM_NONE, + NONE_LEFT, + NONE_MID, + NONE_RIGHT, + }; + + /// Convert pixel-space x and y to relative-space (-1 -> 0 -> 1) coords + std::array toRelative(GLfloat x, GLfloat y, Anchor anchor); + /// Mid-Left `toRelative` + inline std::array ml(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::MID_LEFT); + } + /// Top-Left `toRelative` + inline std::array tl(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::TOP_LEFT); + } + /// Top-Mid `toRelative` + inline std::array tm(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::TOP_MID); + } + /// Top-Right `toRelative` + inline std::array tr(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::TOP_RIGHT); + } + /// Mid-Right `toRelative` + inline std::array mr(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::MID_RIGHT); + } + /// Bottom-Right `toRelative` + inline std::array br(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::BOTTOM_RIGHT); + } + /// Bottom-Mid `toRelative` + inline std::array bm(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::BOTTOM_MID); + } + /// Bottom-Left `toRelative` + inline std::array bl(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::BOTTOM_LEFT); + } + /// Center `toRelative` + inline std::array c(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::CENTER); + } + /// Top-None `toRelative` + inline std::array tn(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::TOP_NONE); + } + /// Mid-None `toRelative` + inline std::array mn(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::MID_NONE); + } + /// Bottom-None `toRelative` + inline std::array bn(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::BOTTOM_NONE); + } + /// None-Left `toRelative` + inline std::array nl(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::NONE_LEFT); + } + /// None-Mid `toRelative` + inline std::array nm(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::NONE_MID); + } + /// None-Right `toRelative` + inline std::array nr(GLfloat x, GLfloat y) { + return PW::toRelative(x, y, PW::NONE_RIGHT); + } +} \ No newline at end of file diff --git a/src/utils.hpp b/src/utils.hpp new file mode 100644 index 0000000..81af62e --- /dev/null +++ b/src/utils.hpp @@ -0,0 +1,16 @@ +#pragma once + +namespace Utils { + const double PI = 3.14159265358979323846; + + template + T nummap(T input, T inMin, T inMax, T outMin, T outMax) { + // From: https://www.arduino.cc/reference/en/language/functions/math/map/ + return (input - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; + } + + template + constexpr T toRad(T deg) { + return deg * PI / 180; + } +} \ No newline at end of file