328 lines
8.7 KiB
C
328 lines
8.7 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;
|
|
|
|
void updateBall(double *ballX, double *ballY, double *ballVX, double *ballVY, double paddleX, int paddleWidth, int winWidth, int winHeight);
|
|
|
|
void drawPaddle(double paddleX, int paddleWidth, int winWidth, int winHeight, colour *c);
|
|
void drawBall(double ballX, double ballY, 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;
|
|
|
|
int paddleWidth=50;
|
|
double paddleX=(winWidth/2)-(paddleWidth/2);
|
|
double ballX = 0;
|
|
double ballY = 0;
|
|
double ballVX = 0.2;
|
|
double ballVY = -0.3;
|
|
|
|
/*
|
|
* ----------------
|
|
* Let's go!
|
|
* ----------------
|
|
*/
|
|
|
|
|
|
go=1;
|
|
while(go) {
|
|
/* ----------------
|
|
* Timing control
|
|
* ----------------
|
|
*
|
|
*/
|
|
|
|
|
|
Uint32 tickspassed=SDL_GetTicks()-timer;
|
|
timer=SDL_GetTicks();
|
|
int fps=1000/(tickspassed+1);
|
|
printf("Time to draw: %u, fps: %i \r", tickspassed, 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;
|
|
}
|
|
}
|
|
|
|
paddleX += moveX*0.1;
|
|
|
|
updateBall(&ballX, &ballY, &ballVX, &ballVY, paddleX, paddleWidth, winWidth, winHeight);
|
|
ballX += ballVX*0.1;
|
|
ballY += ballVY*0.1;
|
|
|
|
/*
|
|
* ----------------
|
|
* 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*/
|
|
|
|
drawPaddle(paddleX, paddleWidth, winWidth, winHeight, &paddleCol);
|
|
drawBall(ballX, ballY, &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 updateBall(double *ballX, double *ballY, double *ballVX, double *ballVY, double paddleX, int paddleWidth, int winWidth, int winHeight) {
|
|
double ballNX = *ballX + *ballVX; // Calculates the position of the ball on the next step
|
|
double ballNY = *ballY + *ballVY;
|
|
double paddleRX = paddleX - (double)(winWidth / 2);
|
|
double paddleRY = 20 - (double)(winHeight / 2);
|
|
|
|
if (ballNX > paddleRX && ballNY<paddleRY) { // If to the right or below the top left corner of paddle
|
|
if (ballNX < paddleRX + (double)paddleWidth) { // ...and to the left of the right side of the paddle (i.e. about to go inside inside the paddle)
|
|
*ballVY *= -1.0;
|
|
*ballVX = ((ballNX - paddleRX - (double)(paddleWidth/2))/((double)paddleWidth/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
|
|
*ballVX *= -1.0;
|
|
}
|
|
if (ballNY > winHeight / 2) { // Collision with ceiling
|
|
*ballVY *= -1.0;
|
|
}
|
|
if (ballNY < (-1.0*winHeight/2)) { // Collision with floor
|
|
*ballX = 0;
|
|
*ballY = 0;
|
|
*ballVX = -0.1;
|
|
*ballVY = -0.5;
|
|
}
|
|
}
|
|
|
|
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(double paddleX, int paddleWidth, int winWidth, int winHeight, colour *c) {
|
|
GLint matrixmode = 0;
|
|
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
|
|
glPushMatrix();
|
|
glTranslated((GLdouble)(paddleX)-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, 10.0, 0.0);
|
|
glVertex3d((double)paddleWidth, 10.0, 0.0);
|
|
glVertex3d((double)paddleWidth, 0.0, 0.0);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(matrixmode);
|
|
}
|
|
|
|
void drawBall(double ballX, double ballY, colour *c) {
|
|
GLint matrixmode = 0;
|
|
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
|
|
glPushMatrix();
|
|
glTranslated(ballX, ballY, 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);
|
|
}
|