370 lines
9.8 KiB
C

#ifdef _WIN32
#include <Windows.h>
#include <SDL.h>
#define _
#else
#include <SDL2/SDL.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct colour {
double r;
double g;
double b;
double a;
} colour;
typedef struct paddle {
int width;
int height;
double x;
} paddle;
typedef struct ball {
double x;
double y;
double vX;
double vY;
double initVX;
double initVY;
double radius;
} ball;
void updatePaddle(Uint32 tickrate, paddle *thePaddle, char moveX, int winWidth, int winHeight);
void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth, int winHeight);
void drawPaddle(paddle *thePaddle, int winWidth, int winHeight, colour *c);
void drawBall(ball *theBall, colour *c);
void drawBg(int winWidth, int winHeight, colour *c1, colour *c2);
int main(void) {
/*
* RETURN CODES
* 0: Success
* 1: SDL init fail
* 2: Error creating Window
* 3: Error creating context
*
*/
/* ----------------
* SDL Init
* ----------------
*/
if (SDL_Init(SDL_INIT_EVERYTHING)!=0) {
perror("[FAILED] Initialising SDL: ");
return 1;
}
int go; //Var for loop control
/* ----------------
* Main Window
* ----------------
* Create the main output Window for SDL
*/
// Window vars
int winPosX = 100; int winPosY = 100;
int winWidth = 480; int winHeight = 720;
Uint32 timer;
SDL_Window *window1 = SDL_CreateWindow(
"Main Window",
winPosX, winPosY,
winWidth, winHeight,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL
);
if (window1==NULL) {
fprintf(stderr, "[FAILED] Creating Window window1");
return 2; //Error creating Window
}
/*
* ----------------
* Renderer
* ----------------
* Creates the main renderer (tied to main window)
*/
//SDL_Renderer * renderer1 = SDL_CreateRenderer(window1, -1, 0);
//if (renderer1==NULL) {
// fprintf(stderr, "[FAILED] Creating renderer renderer1 for window1");
// return 3;
//}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); // Specifies the version of the OpenGL context
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); // (here, 1.5) -- hello, 2003!
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); // Allows deprecated functions to be used
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); // Set depth buffer to 16 bits, if OpenGL agrees (see below)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Enable double buffering
SDL_GLContext context1 = SDL_GL_CreateContext(window1); // Use SDL_GL_MakeCurrent function to switch contexts
if (context1 == NULL) {
fprintf(stderr, "[FAILED] Creating render context context1 for window1");
return 3;
}
glFrontFace(GL_CCW); // Counter-clockwise winding
glEnable(GL_NORMALIZE); // Vectors normalized after transforming to keep units consistent for lighting
glShadeModel(GL_SMOOTH); // GL_FLAT for flat shading instead
glEnable(GL_DEPTH_TEST); // Enables depth comparisons
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_PROJECTION); // Sets our matrix mode (initially) to work with the projection stack
glLoadIdentity(); // Projection matrix is now the identity matrix, so we can work in 2D space
gluOrtho2D(
-1.0*(GLdouble)(winWidth / 2), // Left
(GLdouble)(winWidth / 2), // Right
-1.0*(GLdouble)(winHeight / 2), // Bottom
(GLdouble)(winHeight / 2) // Top
);
glViewport(0, 0, winWidth, winHeight); // Set the viewport to fill the window
timer = SDL_GetTicks();
/*
* ----------------
* Game variables
* ----------------
*/
char moveX=0;
ball theBall = {
.x = 0,
.y = 0,
.vX = 0.4f,
.vY = -1.5f,
.initVX = theBall.vX,
.initVY = theBall.vY,
.radius = 4
};
paddle thePaddle = {
.width = 50,
.height = 10,
.x = (winWidth/2)-(thePaddle.width/2)
};
/*
* ----------------
* Let's go!
* ----------------
*/
go=1;
while(go) {
/* ----------------
* Timing control
* ----------------
*
*/
Uint32 tickrate=SDL_GetTicks()-timer;
timer=SDL_GetTicks();
int fps=1000/(tickrate+1);
//printf("Time to draw: %u, fps: %i \r", tickrate, fps); fflush(stdout);
/*
* ----------------
* Event handling
* ----------------
*/
SDL_Event incomingEvent;
while (SDL_PollEvent(&incomingEvent)) {
switch (incomingEvent.type) {
case SDL_QUIT:
// User requested program quit - e.g. window close
go=0;
break;
case SDL_KEYDOWN:
switch(incomingEvent.key.keysym.sym) {
case SDLK_ESCAPE:
go=0;
break;
case SDLK_LEFT:
moveX=-1;
break;
case SDLK_RIGHT:
moveX=1;
break;
}
break;
case SDL_KEYUP:
switch(incomingEvent.key.keysym.sym) {
case SDLK_LEFT:
moveX=0;
break;
case SDLK_RIGHT:
moveX=0;
break;
}
break;
}
}
/*
* ----------------
* Update elements
* ----------------
*/
updatePaddle(tickrate, &thePaddle, moveX, winWidth, winHeight);
updateBall(tickrate, &theBall, &thePaddle, winWidth, winHeight);
/*
* ----------------
* Draw to buffer
* ----------------
*/
SDL_GL_MakeCurrent(window1, context1);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
colour paddleCol;
paddleCol.r = 1.0; paddleCol.g = 1.0; paddleCol.b = 1.0; paddleCol.a = 1.0;
colour bgcol1; colour bgcol2;
//bgcol1.r = 0.0824; /*21*/ bgcol2.r = 0.7216; /*184*/
//bgcol1.g = 0.0901; /*23*/ bgcol2.g = 0.2471; /*63*/
//bgcol1.b = 0.4431; /*113*/ bgcol2.b = 0.6078; /*155*/
//bgcol1.a = 1.0000; /*255*/ bgcol2.a = 1.0000; /*255*/
bgcol1.r = 0.1500; bgcol2.r = 0.3500;
bgcol1.g = 0.1500; bgcol2.g = 0.3500;
bgcol1.b = 0.1500; bgcol2.b = 0.3500;
bgcol1.a = 1.0000; bgcol2.a = 1.0000;
drawPaddle(&thePaddle, winWidth, winHeight, &paddleCol);
drawBall(&theBall, &paddleCol);
drawBg(winWidth, winHeight, &bgcol1, &bgcol2);
glFlush();
/*
* --------------------------------
* Output to Window
* --------------------------------
*/
SDL_GL_SwapWindow(window1);
}
/*
* --------------------------------
* Clean up after ourselves
* --------------------------------
*/
SDL_GL_DeleteContext(context1);
SDL_DestroyWindow(window1);
SDL_Quit();
return 0;
}
void updatePaddle(Uint32 tickrate, paddle *thePaddle, char moveX, int winWidth, int winHeight) {
thePaddle->x += moveX * 0.5 * tickrate;
if (thePaddle->x < 0-(thePaddle->width/2)) thePaddle->x = 0-(thePaddle->width/2);
if (thePaddle->x > winWidth-(thePaddle->width/2)) thePaddle->x = winWidth-(thePaddle->width/2);
}
void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth, int winHeight) {
double ballNX = theBall->x + theBall->vX; // Calculates the position of the ball on the next step
double ballNY = theBall->y + theBall->vY;
double paddleRX = thePaddle->x - (double)(winWidth / 2);
double paddleRY = 20 - (double)(winHeight / 2);
if (ballNX+theBall->radius > paddleRX && ballNY-theBall->radius < paddleRY && // If to the right and below the top left corner of paddle
ballNX-theBall->radius < paddleRX + (double)thePaddle->width && // ...and to the left of the right side of the paddle
ballNY > (paddleRY-thePaddle->height)) { // ...and above the bottom of the paddle (all now compensating for ball radius)
theBall->vY *= -1.0;
theBall->vX = ((ballNX - paddleRX - (double)(thePaddle->width/2))/((double)thePaddle->width/2))*0.5; // Sets X velocity to be proportional to the relative position of the ball and the paddle on collision
}
if (ballNX > winWidth / 2 || ballNX < (-1.0*winWidth/2)) { // Collision with walls
theBall->vX *= -1.0;
}
if (ballNY > winHeight / 2) { // Collision with ceiling
theBall->vY *= -1.0;
}
if (ballNY < (-1.0*winHeight/2)) { // Collision with floor
theBall->x = 0;
theBall->y = 0;
theBall->vX = theBall->initVX;
theBall->vY = theBall->initVY;
}
theBall->x += theBall->vX * 0.1 * tickrate;
theBall->y += theBall->vY * 0.1 * tickrate;
}
void drawBg(int winWidth, int winHeight, colour *c1, colour *c2) {
GLint matrixmode = 0;
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
glPushMatrix();
glTranslated((GLdouble)(-1*winWidth/2), (GLdouble)(-1*winHeight/2), 0.0);
glBegin(GL_QUADS);
//Top colour
glColor3f(c1->r, c1->g, c1->b);
glVertex2f(winWidth, 0.0);
glVertex2f(0.0,0.0);
//Bottom colour
glColor3f(c2->r, c2->g, c2->b);
glVertex2f(0.0,winHeight);
glVertex2f(winWidth, winHeight);
glEnd();
}
void drawPaddle(paddle *thePaddle, int winWidth, int winHeight, colour *c) {
GLint matrixmode = 0;
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
glPushMatrix();
glTranslated((GLdouble)(thePaddle->x)-winWidth/2, (GLdouble)(20-winHeight/2), 0.0);
glBegin(GL_QUADS);
glColor3f(c->r, c->g, c->b);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, (double)thePaddle->height, 0.0);
glVertex3d((double)thePaddle->width, (double)thePaddle->height, 0.0);
glVertex3d((double)thePaddle->width, 0.0, 0.0);
glEnd();
glPopMatrix();
glMatrixMode(matrixmode);
}
void drawBall(ball *theBall, colour *c) {
GLint matrixmode = 0;
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
glPushMatrix();
glTranslated(theBall->x, theBall->y, 0.0);
glBegin(GL_QUADS);
glColor3f(c->r, c->g, c->b);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 8.0, 0.0);
glVertex3d(8.0, 8.0, 0.0);
glVertex3d(8.0, 0.0, 0.0);
glEnd();
glPopMatrix();
glMatrixMode(matrixmode);
}