797 lines
32 KiB
C
797 lines
32 KiB
C
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#include <SDL.h>
|
|
#include <SDL_ttf.h>
|
|
#include <SDL_image.h>
|
|
#else
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_ttf.h>
|
|
#include <SDL2/SDL_image.h>
|
|
#endif
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef struct coord {
|
|
double x;
|
|
double y;
|
|
} coord;
|
|
|
|
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;
|
|
char isColliding;
|
|
} ball;
|
|
|
|
typedef struct brick {
|
|
char brickType;
|
|
int x;
|
|
int y;
|
|
int width;
|
|
int height;
|
|
char destroyed;
|
|
} brick;
|
|
|
|
typedef struct brickCD {
|
|
char isLeaf;
|
|
int x;
|
|
int y;
|
|
int width;
|
|
int height;
|
|
struct brickCD *container;
|
|
int brickID;
|
|
} brickCD;
|
|
|
|
double heronsFormula(coord a, coord b, coord c) {
|
|
double A = sqrt(pow((a.x - b.x), 2) + pow((a.y - b.y), 2));
|
|
double B = sqrt(pow((b.x - c.x), 2) + pow((b.y - c.y), 2));
|
|
double C = sqrt(pow((c.x - a.x), 2) + pow((c.y - a.y), 2));
|
|
double s = (A + B + C) / 2;
|
|
return sqrt(s*(s - A)*(s - B)*(s - C));
|
|
}
|
|
|
|
int loadTextures(GLuint *texture, const char *imageLoc);
|
|
|
|
char vertexWithinQuad(coord point, coord *quad);
|
|
|
|
void updatePaddle(Uint32 tickrate, paddle *thePaddle, char moveX, int winWidth, int winHeight);
|
|
void updateBall(Uint32 tickrate, ball *theBall, paddle *thePaddle, int winWidth, int winHeight, brick *bricks, int brickCount, int *playerLives);
|
|
void updateScore(int *playerScore, brick *bricks, int brickCount);
|
|
|
|
void drawHearts(GLuint heartFullTex, GLuint heartEmptyTex, int playerLives, int winWidth, int winHeight);
|
|
void drawPaddle(paddle *thePaddle, int winWidth, int winHeight, colour *c);
|
|
void drawBall(ball *theBall, colour *c);
|
|
void drawBricks(brick *bricks, int brickCount, int winWidth, int winHeight, colour *colours);
|
|
void drawBg(int winWidth, int winHeight, colour *c1, colour *c2);
|
|
|
|
void initialiseBricks(brick *bricks, int *brickCount);
|
|
|
|
int main(void) {
|
|
|
|
/*
|
|
* RETURN CODES
|
|
* 0: Success
|
|
* 1: SDL init fail
|
|
* 2: Error creating Window
|
|
* 3: Error creating context
|
|
* 4: SDL_TTF init fail
|
|
* 5: Error loading font(s)
|
|
* 6: Error loading image asset(s)
|
|
*
|
|
*/
|
|
|
|
/* ----------------
|
|
* SDL Init
|
|
* ----------------
|
|
*/
|
|
if (SDL_Init(SDL_INIT_EVERYTHING)!=0) {
|
|
perror("[FAILED] Initialising SDL: ");
|
|
return 1;
|
|
}
|
|
|
|
if (TTF_Init() < 0) {
|
|
perror("[FAILED] Initialising SDL_TTF: ");
|
|
}
|
|
|
|
int go; //Var for loop control
|
|
int step = 0; //Var for step counter
|
|
|
|
/* ----------------
|
|
* Main Window
|
|
* ----------------
|
|
* Create the main output Window for SDL
|
|
*/
|
|
|
|
// Window vars
|
|
int winPosX = 100; int winPosY = 100;
|
|
int winWidth = 480; int winHeight = 720;
|
|
char windowTitle[128] = "Breakout";
|
|
|
|
Uint32 timer;
|
|
|
|
SDL_Window *window1 = SDL_CreateWindow(
|
|
windowTitle,
|
|
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
|
|
glEnable(GL_TEXTURE_2D); // Enables use of textures
|
|
glAlphaFunc(GL_GREATER, 0);
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
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 subSteps = 2; // Draw every N+1 frames, thereby calculating movement more precisely
|
|
int targetFPS = 60; // Limit FPS to this value, to stop unneccessary calculations
|
|
|
|
char moveX=0;
|
|
|
|
brick bricks[128];
|
|
int brickCount;
|
|
colour brickColours[4];
|
|
brickColours[3] = (colour) { .r = 1.0000 /*255*/, .g = 0.2510 /*64 */, .b = 0.6549 /*167*/, .a = 1 };
|
|
brickColours[2] = (colour) { .r = 0.4588 /*117*/, .g = 0.5490 /*140*/, .b = 1.0000 /*255*/, .a = 1 };
|
|
brickColours[1] = (colour) { .r = 0.3490 /*89 */, .g = 0.8706 /*222*/, .b = 1.0000 /*255*/, .a = 1 };
|
|
brickColours[0] = (colour) { .r = 1.0000 /*255*/, .g = 0.7569 /*193*/, .b = 0.1216 /*31 */, .a = 1 };
|
|
initialiseBricks(&bricks, &brickCount);
|
|
|
|
ball theBall = {
|
|
.x = 0,
|
|
.y = 0,
|
|
.vX = 1.5f,
|
|
.vY = -5.0f,
|
|
.initVX = theBall.vX,
|
|
.initVY = theBall.vY,
|
|
.radius = 4,
|
|
.isColliding = 0
|
|
};
|
|
|
|
paddle thePaddle = {
|
|
.width = 50,
|
|
.height = 10,
|
|
.x = (winWidth/2)-(thePaddle.width/2)
|
|
};
|
|
|
|
int playerScore = 0;
|
|
|
|
int playerLives = 3;
|
|
|
|
/*
|
|
* ----------------
|
|
* Font stuff
|
|
* ----------------
|
|
*/
|
|
|
|
TTF_Font* font_main = TTF_OpenFont("assets/font_main.ttf", 24);
|
|
if (font_main == NULL) {
|
|
printf("[FAILED] Unable to load font\n");
|
|
return 5;
|
|
}
|
|
SDL_Color textColour = {
|
|
.a = 255,
|
|
.r = 255,
|
|
.g = 255,
|
|
.b = 255
|
|
};
|
|
|
|
/*
|
|
* --------------------------------
|
|
* Loading required textures
|
|
* --------------------------------
|
|
*/
|
|
|
|
GLuint heartFullTex;
|
|
GLuint heartEmptyTex;
|
|
if (
|
|
loadTextures(&heartEmptyTex, "assets/heartUsed.png") ||
|
|
loadTextures(&heartFullTex, "assets/heartFull.png") > 1) {
|
|
return 6;
|
|
}
|
|
/*
|
|
* ----------------
|
|
* Let's go!
|
|
* ----------------
|
|
*/
|
|
|
|
|
|
go=1;
|
|
while(go) {
|
|
/* ----------------
|
|
* Timing control
|
|
* ----------------
|
|
*
|
|
*/
|
|
|
|
|
|
Uint32 tickrate=SDL_GetTicks()-timer;
|
|
timer=SDL_GetTicks();
|
|
int fps=1000/(tickrate+1);
|
|
|
|
/*
|
|
* ----------------
|
|
* 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, &bricks, brickCount, &playerLives);
|
|
updateScore(&playerScore, &bricks, brickCount);
|
|
if (playerLives < 1) {
|
|
go = 0;
|
|
}
|
|
|
|
if (step % (subSteps+1) == 0) {
|
|
//step = 0;
|
|
/*
|
|
* ----------------
|
|
* Draw to buffer
|
|
* ----------------
|
|
*/
|
|
|
|
SDL_GL_MakeCurrent(window1, context1);
|
|
|
|
sprintf(windowTitle, "Breakout: Score (%d), lives remaining (%d)", playerScore, playerLives);
|
|
SDL_SetWindowTitle(window1, windowTitle);
|
|
|
|
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.7216; /*184*/ bgcol2.r = 0.0824; /*21 */
|
|
bgcol1.g = 0.2471; /*63 */ bgcol2.g = 0.0901; /*23 */
|
|
bgcol1.b = 0.6078; /*155*/ bgcol2.b = 0.4431; /*113*/
|
|
bgcol1.a = 1.0000; /*255*/ bgcol2.a = 1.0000; /*255*/
|
|
|
|
drawHearts(heartFullTex, heartEmptyTex, playerLives, winWidth, winHeight);
|
|
drawPaddle(&thePaddle, winWidth, winHeight, &paddleCol);
|
|
drawBall(&theBall, &paddleCol);
|
|
drawBricks(&bricks, brickCount, winWidth, winHeight, &brickColours);
|
|
drawBg(winWidth, winHeight, &bgcol1, &bgcol2);
|
|
|
|
glFlush();
|
|
|
|
/*
|
|
* --------------------------------
|
|
* Output to Window
|
|
* --------------------------------
|
|
*/
|
|
SDL_GL_SwapWindow(window1);
|
|
}
|
|
if (SDL_GetTicks() - timer < 1000 / (targetFPS * (subSteps+1))) SDL_Delay((1000 / (targetFPS * (subSteps+1))) - (SDL_GetTicks() - timer));
|
|
step++;
|
|
}
|
|
|
|
/*
|
|
* --------------------------------
|
|
* Clean up after ourselves
|
|
* --------------------------------
|
|
*/
|
|
SDL_GL_DeleteContext(context1);
|
|
SDL_DestroyWindow(window1);
|
|
SDL_Quit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int loadTextures(GLuint *texture, const char *imageLoc) {
|
|
char errorMsg[512];
|
|
sprintf(errorMsg, "[FAILED] Opening %s", imageLoc);
|
|
SDL_Surface *surface = IMG_Load(imageLoc);
|
|
if (surface == NULL) {
|
|
fprintf(stderr, errorMsg);
|
|
return 1;
|
|
}
|
|
*texture = 0;
|
|
|
|
// Start of code from SDLTutorials.com
|
|
|
|
int Mode = GL_RGB;
|
|
|
|
glGenTextures(1, texture);
|
|
glBindTexture(GL_TEXTURE_2D, *texture);
|
|
|
|
if (surface->format->BytesPerPixel == 4) {
|
|
Mode = GL_RGBA;
|
|
}
|
|
glTexImage2D(GL_TEXTURE_2D, 0, Mode, surface->w, surface->h, 0, Mode, GL_UNSIGNED_BYTE, surface->pixels);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
// End of code from SDLTutorials.com
|
|
// Tim Jones (2011) SDL Surface to OpenGL Texture, Available at: http://www.sdltutorials.com/sdl-tip-sdl-surface-to-opengl-texture (Accessed: 10/01/2018)
|
|
|
|
return 0;
|
|
}
|
|
|
|
char vertexWithinQuad(coord point, coord *quad) {
|
|
double quadArea = heronsFormula(quad[0], quad[1], quad[2]) + heronsFormula(quad[1], quad[2], quad[3]);
|
|
double testArea = 0;
|
|
testArea += heronsFormula(point, quad[0], quad[1]);
|
|
testArea += heronsFormula(point, quad[1], quad[2]);
|
|
testArea += heronsFormula(point, quad[2], quad[3]);
|
|
testArea += heronsFormula(point, quad[3], quad[0]);
|
|
if ((int)testArea == (int)quadArea) {
|
|
return 1;
|
|
} else {
|
|
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, brick *bricks, int brickCount, int *playerLives) {
|
|
double ballNX = theBall->x + theBall->vX * 0.1 * tickrate; // Calculates the position of the ball's centre on the next step
|
|
double ballNY = theBall->y + theBall->vY * 0.1 * tickrate;
|
|
|
|
double paddleRX = thePaddle->x - (double)(winWidth / 2); // Converts paddle X/Y to coordinates relative to the center of the window as the ball
|
|
double paddleRY = 20 - (double)(winHeight / 2); // (Default is absolute, offset from the top left corner of window)
|
|
|
|
coord paddleQ[4] = {
|
|
{ .x = paddleRX, .y = paddleRY }, // Sets up a quad (coord array) to pass to vertexWithinQuad function later
|
|
{ .x = paddleRX, .y = paddleRY - thePaddle->height },
|
|
{ .x = paddleRX + thePaddle->width, .y = paddleRY - thePaddle->height },
|
|
{ .x = paddleRX + thePaddle->width, .y = paddleRY },
|
|
};
|
|
|
|
// Collision with paddle
|
|
// (Testing each vertex of ball against paddle quad)
|
|
|
|
char colliding = 0;
|
|
int mults[4] = { -1,-1,1,1 };
|
|
|
|
for (int i = 0, j = 3; i < 4; i++, j++) {
|
|
coord ballN = { .x = ballNX + (theBall->radius*mults[i % 4]), .y = ballNY + (theBall->radius*mults[j % 4]) }; // Constructs pairs of coordinates referring to each vertex of the ball
|
|
if (vertexWithinQuad(ballN, paddleQ)) colliding = 1;
|
|
}
|
|
|
|
if (colliding) {
|
|
if (theBall->isColliding == 0) {
|
|
|
|
theBall->isColliding = 1; // This keeps track of any current attepmts to 'solve' collision
|
|
// Without this flag, if the ball ends up within another object and moving slow enough that on the next frame it has not escaped the object,
|
|
// it will repeatedly have its velocity multiplied by -1 and get stuck, effectively moving only along one axis. With this flag,
|
|
// the game will ignore subsequent collisions, until it is no longer colliding. Note this does not solve the same problem where two objects
|
|
// are very close to each other and on exiting one object it enters another, in which case the ball will move through the other objects
|
|
|
|
if (theBall->x + theBall->radius < paddleRX) { // Left side collision
|
|
theBall->vX *= -1.0;
|
|
} else if (theBall->x - theBall->radius > paddleRX + thePaddle->width) { // Right side collision
|
|
theBall->vX *= -1.0;
|
|
} else { // Top or bottom collision
|
|
theBall->vY *= -1.0;
|
|
theBall->vX = ((ballNX - paddleRX - (double)(thePaddle->width / 2)) / ((double)thePaddle->width / 2))*theBall->initVX; // Sets X velocity to be proportional to the relative position of the ball and the paddle on collision
|
|
}
|
|
} else {
|
|
// Already solving a collision
|
|
}
|
|
} else {
|
|
theBall->isColliding = 0;
|
|
}
|
|
|
|
// Collision with bricks
|
|
// (Testing each vertex of ball against every brick)
|
|
|
|
for (int i = 0; i < brickCount; i++) {
|
|
colliding = 0;
|
|
|
|
if (bricks[i].destroyed == 0) {
|
|
coord brick[4] = {
|
|
{.x = bricks[i].x - (winWidth / 2), .y = bricks[i].y },
|
|
{.x = bricks[i].x - (winWidth / 2), .y = bricks[i].y - bricks[i].height },
|
|
{.x = bricks[i].x - (winWidth / 2) + bricks[i].width, .y = bricks[i].y - bricks[i].height },
|
|
{.x = bricks[i].x - (winWidth / 2) + bricks[i].width, .y = bricks[i].y },
|
|
};
|
|
|
|
for (int j = 0, k = 3; j < 4; j++, k++) {
|
|
coord ballN = { .x = ballNX + (theBall->radius*mults[j % 4]),.y = ballNY + (theBall->radius*mults[k % 4]) };
|
|
if (vertexWithinQuad(ballN, brick)) colliding = 1;
|
|
}
|
|
|
|
if (colliding) {
|
|
if (theBall->x + theBall->radius < bricks[i].x - (winWidth / 2)) { // Left side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else if (theBall->x - theBall->radius > bricks[i].x - (winWidth / 2) + bricks[i].width) { // Right side collision
|
|
theBall->vX *= -1.0;
|
|
}
|
|
else {
|
|
theBall->vY *= -1.0;
|
|
}
|
|
bricks[i].destroyed = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Collision with window boundaries
|
|
|
|
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;
|
|
*playerLives -= 1;
|
|
}
|
|
|
|
// Update the ball's position
|
|
|
|
theBall->x += theBall->vX * 0.1 * tickrate;
|
|
theBall->y += theBall->vY * 0.1 * tickrate;
|
|
}
|
|
|
|
void updateScore(int *playerScore, brick *bricks, int brickCount) {
|
|
*playerScore = 0;
|
|
for (int i = 0; i < brickCount; i++) {
|
|
if (bricks[i].destroyed == 1) {
|
|
switch (bricks[i].brickType) {
|
|
case 1:
|
|
*playerScore += 1;
|
|
break;
|
|
case 2:
|
|
*playerScore += 3;
|
|
break;
|
|
case 3:
|
|
*playerScore += 5;
|
|
break;
|
|
case 4:
|
|
*playerScore += 7;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawHearts(GLuint heartFullTex, GLuint heartEmptyTex, int playerLives, int winWidth, int winHeight) {
|
|
coord locations[3] = { {.x = -19, .y = -32}, { .x = 0, .y = -32 }, { .x = 19, .y = -32 } };
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
if (i > playerLives-1) {
|
|
glBindTexture(GL_TEXTURE_2D, heartEmptyTex);
|
|
} else {
|
|
glBindTexture(GL_TEXTURE_2D, heartFullTex);
|
|
}
|
|
GLint matrixmode = 0;
|
|
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
|
|
glPushMatrix();
|
|
glTranslated(0.0, (winHeight/2), 0.0);
|
|
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0, 0); glVertex3d(0.0+locations[i].x, 0.0+locations[i].y, 0.0);
|
|
glTexCoord2f(0, 1); glVertex3d(0.0+locations[i].x, -15.0 + locations[i].y, 0.0);
|
|
glTexCoord2f(1, 1); glVertex3d(15.0+locations[i].x, -15.0 + locations[i].y, 0.0);
|
|
glTexCoord2f(1, 0); glVertex3d(15.0+locations[i].x, 0.0 + locations[i].y, 0.0);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(matrixmode);
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
}
|
|
|
|
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)-1*thePaddle->height, 0.0);
|
|
glVertex3d((double)thePaddle->width, (double)-1*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(-1.0*theBall->radius, 1.0*theBall->radius, 0.0);
|
|
glVertex3d(-1.0*theBall->radius, -1.0*theBall->radius, 0.0);
|
|
glVertex3d( 1.0*theBall->radius, -1.0*theBall->radius, 0.0);
|
|
glVertex3d( 1.0*theBall->radius, 1.0*theBall->radius, 0.0);
|
|
glEnd();
|
|
|
|
glPopMatrix();
|
|
glMatrixMode(matrixmode);
|
|
}
|
|
|
|
void drawBricks(brick *bricks, int brickCount, int winWidth, int winHeight, colour *colours) {
|
|
for (int i = 0; i < brickCount; i++) {
|
|
if (bricks[i].destroyed == 0) {
|
|
GLint matrixmode = 0;
|
|
glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
|
|
glPushMatrix();
|
|
glTranslated((double)bricks[i].x - (winWidth / 2), (double)bricks[i].y, 0.0);
|
|
glBegin(GL_QUADS);
|
|
glColor3f(
|
|
colours[bricks[i].brickType - 1].r,
|
|
colours[bricks[i].brickType - 1].g,
|
|
colours[bricks[i].brickType - 1].b
|
|
);
|
|
glVertex3d(0.0, 0.0, 0.0);
|
|
glVertex3d(0.0, (double)bricks[i].height, 0.0);
|
|
glVertex3d((double)bricks[i].width, (double)bricks[i].height, 0.0);
|
|
glVertex3d((double)bricks[i].width, 0.0, 0.0);
|
|
glEnd();
|
|
glPopMatrix();
|
|
glMatrixMode(matrixmode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void initialiseBricks(brick *bricks, int *brickCount) {
|
|
bricks[0 ] = (brick) { .brickType = 1, .x = 17, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[1 ] = (brick) { .brickType = 1, .x = 49, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[2 ] = (brick) { .brickType = 1, .x = 81, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[3 ] = (brick) { .brickType = 1, .x = 113, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[4 ] = (brick) { .brickType = 1, .x = 145, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[5 ] = (brick) { .brickType = 1, .x = 177, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[6 ] = (brick) { .brickType = 1, .x = 209, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[7 ] = (brick) { .brickType = 1, .x = 241, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[8 ] = (brick) { .brickType = 1, .x = 273, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[9 ] = (brick) { .brickType = 1, .x = 305, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[10 ] = (brick) { .brickType = 1, .x = 337, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[11 ] = (brick) { .brickType = 1, .x = 369, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[12 ] = (brick) { .brickType = 1, .x = 401, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[13 ] = (brick) { .brickType = 1, .x = 433, .y = 130, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[14 ] = (brick) { .brickType = 1, .x = 17, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[15 ] = (brick) { .brickType = 1, .x = 49, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[16 ] = (brick) { .brickType = 1, .x = 81, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[17 ] = (brick) { .brickType = 1, .x = 113, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[18 ] = (brick) { .brickType = 1, .x = 145, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[19 ] = (brick) { .brickType = 1, .x = 177, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[20 ] = (brick) { .brickType = 1, .x = 209, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[21 ] = (brick) { .brickType = 1, .x = 241, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[22 ] = (brick) { .brickType = 1, .x = 273, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[23 ] = (brick) { .brickType = 1, .x = 305, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[24 ] = (brick) { .brickType = 1, .x = 337, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[25 ] = (brick) { .brickType = 1, .x = 369, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[26 ] = (brick) { .brickType = 1, .x = 401, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[27 ] = (brick) { .brickType = 1, .x = 433, .y = 142, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[28 ] = (brick) { .brickType = 2, .x = 17, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[29 ] = (brick) { .brickType = 2, .x = 49, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[30 ] = (brick) { .brickType = 2, .x = 81, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[31 ] = (brick) { .brickType = 2, .x = 113, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[32 ] = (brick) { .brickType = 2, .x = 145, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[33 ] = (brick) { .brickType = 2, .x = 177, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[34 ] = (brick) { .brickType = 2, .x = 209, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[35 ] = (brick) { .brickType = 2, .x = 241, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[36 ] = (brick) { .brickType = 2, .x = 273, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[37 ] = (brick) { .brickType = 2, .x = 305, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[38 ] = (brick) { .brickType = 2, .x = 337, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[39 ] = (brick) { .brickType = 2, .x = 369, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[40 ] = (brick) { .brickType = 2, .x = 401, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[41 ] = (brick) { .brickType = 2, .x = 433, .y = 154, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[42 ] = (brick) { .brickType = 2, .x = 17, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[43 ] = (brick) { .brickType = 2, .x = 49, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[44 ] = (brick) { .brickType = 2, .x = 81, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[45 ] = (brick) { .brickType = 2, .x = 113, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[46 ] = (brick) { .brickType = 2, .x = 145, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[47 ] = (brick) { .brickType = 2, .x = 177, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[48 ] = (brick) { .brickType = 2, .x = 209, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[49 ] = (brick) { .brickType = 2, .x = 241, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[50 ] = (brick) { .brickType = 2, .x = 273, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[51 ] = (brick) { .brickType = 2, .x = 305, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[52 ] = (brick) { .brickType = 2, .x = 337, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[53 ] = (brick) { .brickType = 2, .x = 369, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[54 ] = (brick) { .brickType = 2, .x = 401, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[55 ] = (brick) { .brickType = 2, .x = 433, .y = 166, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[56 ] = (brick) { .brickType = 3, .x = 17, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[57 ] = (brick) { .brickType = 3, .x = 49, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[58 ] = (brick) { .brickType = 3, .x = 81, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[59 ] = (brick) { .brickType = 3, .x = 113, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[60 ] = (brick) { .brickType = 3, .x = 145, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[61 ] = (brick) { .brickType = 3, .x = 177, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[62 ] = (brick) { .brickType = 3, .x = 209, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[63 ] = (brick) { .brickType = 3, .x = 241, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[64 ] = (brick) { .brickType = 3, .x = 273, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[65 ] = (brick) { .brickType = 3, .x = 305, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[66 ] = (brick) { .brickType = 3, .x = 337, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[67 ] = (brick) { .brickType = 3, .x = 369, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[68 ] = (brick) { .brickType = 3, .x = 401, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[69 ] = (brick) { .brickType = 3, .x = 433, .y = 178, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[70 ] = (brick) { .brickType = 3, .x = 17, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[71 ] = (brick) { .brickType = 3, .x = 49, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[72 ] = (brick) { .brickType = 3, .x = 81, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[73 ] = (brick) { .brickType = 3, .x = 113, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[74 ] = (brick) { .brickType = 3, .x = 145, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[75 ] = (brick) { .brickType = 3, .x = 177, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[76 ] = (brick) { .brickType = 3, .x = 209, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[77 ] = (brick) { .brickType = 3, .x = 241, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[78 ] = (brick) { .brickType = 3, .x = 273, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[79 ] = (brick) { .brickType = 3, .x = 305, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[80 ] = (brick) { .brickType = 3, .x = 337, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[81 ] = (brick) { .brickType = 3, .x = 369, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[82 ] = (brick) { .brickType = 3, .x = 401, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[83 ] = (brick) { .brickType = 3, .x = 433, .y = 190, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[84 ] = (brick) { .brickType = 4, .x = 17, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[85 ] = (brick) { .brickType = 4, .x = 49, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[86 ] = (brick) { .brickType = 4, .x = 81, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[87 ] = (brick) { .brickType = 4, .x = 113, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[88 ] = (brick) { .brickType = 4, .x = 145, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[89 ] = (brick) { .brickType = 4, .x = 177, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[90 ] = (brick) { .brickType = 4, .x = 209, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[91 ] = (brick) { .brickType = 4, .x = 241, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[92 ] = (brick) { .brickType = 4, .x = 273, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[93 ] = (brick) { .brickType = 4, .x = 305, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[94 ] = (brick) { .brickType = 4, .x = 337, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[95 ] = (brick) { .brickType = 4, .x = 369, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[96 ] = (brick) { .brickType = 4, .x = 401, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[97 ] = (brick) { .brickType = 4, .x = 433, .y = 202, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[98 ] = (brick) { .brickType = 4, .x = 17, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[99 ] = (brick) { .brickType = 4, .x = 49, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[100] = (brick) { .brickType = 4, .x = 81, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[101] = (brick) { .brickType = 4, .x = 113, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[102] = (brick) { .brickType = 4, .x = 145, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[103] = (brick) { .brickType = 4, .x = 177, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[104] = (brick) { .brickType = 4, .x = 209, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[105] = (brick) { .brickType = 4, .x = 241, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[106] = (brick) { .brickType = 4, .x = 273, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[107] = (brick) { .brickType = 4, .x = 305, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[108] = (brick) { .brickType = 4, .x = 337, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[109] = (brick) { .brickType = 4, .x = 369, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[110] = (brick) { .brickType = 4, .x = 401, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
bricks[111] = (brick) { .brickType = 4, .x = 433, .y = 214, .width = 30, .height = 10, .destroyed = 0 };
|
|
*brickCount = 112;
|
|
}
|