OpenGL Tetris

OpenGL Tetris

This is just a quick demonstration I made in open gl, its not a complete game but it has the basic mechanics implemented. This was only ever intended to be a quick and dirty clone written in C. I believe if I remember correctly it took around a weekend to develop back in 2015. I’ve decided away from ever adding any additions because of the quick and dirty nature of it. Originally I developed this for 2 reasons

  1. For demonstration purposes
  2. SDL2 hadn’t long been released and around this time I was playing around with the various API changes to see what was possible and how it differentiated from SDL 1.2.

 

 

You can download a demo here: blockrus

The full source code is hosted on github: https://github.com/AJ-Moore/Blockrus

 

Or can be viewed below, for pure convenience:

/*Tetris
Author: Allan J Moore
Date: 18/10/2015
Description: Subset of features/ demonstration, just out of the blue wanted to write tetris
			 just in a single file, turned out slightly larger than planned, 
			 first time tetris in c++.

			This program requires the following libaries and corresponding headers to be linked: 
			SDL2.lib
			SDL2main.lib
			SDL2_image.lib
			glew32.lib
			opengl32.lib

			This program also requires the glm headers be included.

			The program was compiled and tested on windows 10, I can not guarentee the 
			program will compile sucessfully on other platforms, however it should be 
			possible without too much hassle.

			Semi-complete tileset included in GitHub repo
*/

#include <iostream>
#include <vector>

#include <GL/glew.h>
#include <GL/GL.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include <random>
#include <time.h>

//Include the glm headers 
#include <glm/glm.hpp>
#include "glm/gtc/matrix_transform.hpp"
#include <glm/gtc/type_ptr.hpp>

//Define some useful types
typedef unsigned char uint8;
typedef signed char	sint8; 
typedef unsigned short uint16; 
typedef signed short sint16; 
typedef unsigned int uint32; 
typedef signed int sint32; 

class Vec2{
public:
	Vec2(int _x, int _y) { x = _x; y = _y; }
	signed int x; 
	signed int y; 
};

//!< Global Variables 
SDL_Window* window;
bool gameRunning = true; 

//!< Game properties 
Vec2 gridSize(12, 22);
Vec2 windowSize(1280, 720);

//Block types enumeration 
/**
	Standard game of tetris consists of 7 blocks
	Naught == Empty 
*/
	//Inspiring names... 
enum BLOCK_TYPE{
	EMPTY = 0x0,
	BLOCK1 = 0x1 << 0, // Square 
	BLOCK2 = 0x1 << 1, // Line 
	BLOCK3 = 0x1 << 2, 
	BLOCK4 = 0x1 << 3, 
	BLOCK5 = 0x1 << 4, 
	BLOCK6 = 0x1 << 5,
	BLOCK7 = 0x1 << 6, 
	WALL = 0x1 << 7
};

//!< Array to hold grid data
uint8 grid[12 * 22];

//!< Array to hold blocks 
//!< Rather than come up with an eloborate algorithm I've stored the rotations within the arrays
//!< 7 blocks, 4 animations, 4x4 grid 
uint8 Block[7][16] = {
	
  { 1, 1, 0, 0, 
	1, 1, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0 },
	
	{0, 0, 0, 0,
	 1, 1, 1, 1,
	 0, 0, 0, 0,
	 0, 0, 0, 0},

	{1, 0, 0, 0,
	 1, 1, 1, 0,
	 0, 0, 0, 0,
	 0, 0, 0, 0 },

	{0, 0, 1, 0,
	 1, 1, 1, 0,
	 0, 0, 0, 0,
	 0, 0, 0, 0 },

	{0, 0, 0, 0,
	 1, 1, 1, 0,
	 0, 1, 0, 0,
	 0, 0, 0, 0 },

	{0, 1, 1, 0,
	 1, 1, 0, 0,
	 0, 0, 0, 0,
	 0, 0, 0, 0 },

	{1, 1, 0, 0,
	 0, 1, 1, 0,
	 0, 0, 0, 0,
	 0, 0, 0, 0 }

};

uint8 currentBlock[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Vec2 blockPosition(0, 0);
uint8 currentBlockType = 0; 
uint8 currentBlockID = 0;

// The camera distance in the scene, hardcoded for simplicity, it is tetris afterall 
float camZDist = 20; 

// Define our view and projection martices 
glm::mat4 viewMat, projMat; 

// Buffer for grid outline
std::vector <float> gridLinesVertices; 
GLuint gridVBO;		//!< Vertex buffer object used by grid 
GLuint gridLinesID; 
GLuint gridPositions; //atrib pointer

// Buffers to hold vertex data for blocks
int _vertBufferSize;
int _texBufferSize;

std::vector <float>	vertices; //!< Holds vertex positions  
std::vector <float> textureCoords; //<! Holds texture coordinates 

// Buffer Ids 
GLuint vertexBufferID;	//!< Position buffer ID
GLuint texBufferID;		//!< Texture Coordinate Buffer ID

//Attribute locations 
GLint texAtribLocation; 

// Shader program we will use for EVERYTHING
GLuint program;

// Uniform locations 
GLint _useColour; 

// Textures 
GLuint blockTexture; 

//How fast the blocks drop ms
uint16 blockDropDefault = 600; // Level 1 value 
uint16 blockDropFaster = 30;
uint16 blockDropMS = 600; 
float blockDropedElapsed = 0; 
float previousTimeElapsed = 0; 

float inputElapsed = 0; 
float inputDelayMS = 0; 

// pre - declarations 
void rotateBlock(); 
void moveLeft(); 
void moveRight(); 
int loadTexture(const char* FilePath);

//Handles input
void poll(){

	inputElapsed += SDL_GetTicks() - previousTimeElapsed;
		
		SDL_Event _event;
		const Uint8 *keyState = SDL_GetKeyboardState(NULL);
		while (SDL_PollEvent(&_event)){
			//!< QUIT GAME
			if (keyState[SDL_SCANCODE_ESCAPE] || _event.type == SDL_QUIT){
				gameRunning = false;
			}

			if (keyState[SDL_SCANCODE_SPACE]){
				if (inputElapsed > inputDelayMS){
					inputElapsed = 0;
					rotateBlock();
				}
			}

			if (keyState[SDL_SCANCODE_LEFT]){
				moveLeft();
			}

			if (keyState[SDL_SCANCODE_RIGHT]){
				moveRight(); 
			}

			if (keyState[SDL_SCANCODE_DOWN]){
				blockDropMS = blockDropFaster;
			}
			else{
				//set drop speed back to current 
				blockDropMS = blockDropDefault; // - level * somevalue
			}
			
		}
	
}

void glCheck(){
	GLuint err = glGetError();
	if (err != GL_NO_ERROR)
		std::cerr << std::hex << err << std::endl;
}

void loadShaders(){
	GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
	GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);

	std::string vertexShader =
		"#version 330 core \n "
		"layout (location = 0) in vec4 Vertex;"
		"layout (location = 1) in vec2 texCoordAtrib;"
		"uniform mat4 wvpMat;"
		//"out vec2 texCoord;"
		"varying vec2 texCoord;"
		"void main(){"
		"	texCoord = texCoordAtrib;"
		"	gl_Position = wvpMat * Vertex;"
		"}";

	std::string fragmentShader =
		"#version 330 core  \n "
		"uniform sampler2D tex;"
		"uniform bool useColour;"
		"in vec2 texCoord;"
		"layout (location = 0) out vec4 colour;"
		"void main(){"
		" if (useColour){colour = vec4(0,0,1,1);} else{colour = texture(tex, texCoord);}"
		"}";

	const char* vertSource = vertexShader.c_str();
	const char* fragSource = fragmentShader.c_str();

	glShaderSource(vShader, 1, &vertSource, NULL);
	glCompileShader(vShader);
	glShaderSource(fShader, 1, &fragSource, NULL); 
	glCompileShader(fShader);

	// Check if shaders compiled successfully 
	GLint success = 0;
	glGetShaderiv(vShader, GL_COMPILE_STATUS, &success);
	if (success == GL_FALSE){
		GLint logSize = 0;
		
		glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &logSize);
		char* log = new char[4000]; 
		GLsizei length;
		glGetShaderInfoLog(vShader, 4000, &length, log);
		std::cout << "Vertex Shader Failed: " << log<< std::endl; 
	}
	glGetShaderiv(fShader, GL_COMPILE_STATUS, &success);
	if (success == GL_FALSE){
		GLint logSize = 0;
		glGetShaderiv(vShader, GL_INFO_LOG_LENGTH, &logSize);
		char* log = new char[4000];
		GLsizei length;
		glGetShaderInfoLog(fShader, 4000, &length, log);
		std::cout << "Frag Shader Failed" << log << std::endl;
	}

	program = glCreateProgram(); 
	glAttachShader(program, vShader);
	glAttachShader(program, fShader);
	glLinkProgram(program);

	glUseProgram(program);


	glBindAttribLocation(program, 0, "Vertex");
	glBindAttribLocation(program, 1, "texCoordAtrib");

	GLint _wvpMat = glGetUniformLocation(program, "wvpMat");
	GLint _texture = glGetUniformLocation(program, "tex");
	_useColour = glGetUniformLocation(program, "useColour");

	glUniformMatrix4fv(_wvpMat, 1, false, glm::value_ptr(projMat * viewMat ));
	glUniform1i(_texture, 0);
	glUniform1i(_useColour, 0);


}

void init(){

	//Retrieve the window size 
	int w = 0, h = 0;
	SDL_GetWindowSize(window, &w, &h);

	glm::vec3 _position(0.0f, 0.0f, camZDist);
	glm::vec3 _target(0.0f, 0.0f, 0.0f);
	glm::vec3 _up(0.0, 1.0f, 0.0f);

	// Initialise our view + projection matrices 
	viewMat = glm::lookAt(_position, _target, _up);

	projMat = glm::perspective(45.0f, (float)w / (float)h, 0.1f, 1000.0f);

	// Set viewport
	glViewport(0, 0, w, h);
	
	//Set grid to naught 
	for (int _g = 0; _g < gridSize.x*gridSize.y; _g++){
		grid[_g] = 0; 
	}

	//initialise grid lines array 

	// Resize vector for our data, each point is represented
	// (vertex)3 floats * 2 vertex per line * total gridlines 
	gridLinesVertices.resize((3 * 2)*(gridSize.x + gridSize.y));

	for (int _x = 0; _x < gridSize.x; _x++){
		gridLinesVertices[(_x * 6)] = (-(gridSize.x/2)) + _x;							
		gridLinesVertices[(_x * 6) + 1] = gridSize.y / 2;			
		gridLinesVertices[(_x * 6) + 2] = 0.0f;						
		gridLinesVertices[(_x * 6) + 3] = (-(gridSize.x / 2)) + _x;
		gridLinesVertices[(_x * 6) + 4] = -(gridSize.y / 2);		
		gridLinesVertices[(_x * 6) + 5] = 0.0f;						
	}
	for (int _y = 0; _y < gridSize.y; _y++){
		gridLinesVertices[(gridSize.x * 6) + (_y * 6)] = -(gridSize.x/2);							
		gridLinesVertices[(gridSize.x * 6) + (_y * 6) + 1] = (-(gridSize.y / 2)) + _y;		
		gridLinesVertices[(gridSize.x * 6) + (_y * 6) + 2] = 0.0f;					
		gridLinesVertices[(gridSize.x * 6) + (_y * 6) + 3] = gridSize.x / 2;
		gridLinesVertices[(gridSize.x * 6) + (_y * 6) + 4] = (-(gridSize.y / 2)) + _y;
		gridLinesVertices[(gridSize.x * 6) + (_y * 6) + 5] = 0.0f; 
	}

	//glGenVertexArrays(1, &gridVBO);
	//glBindVertexArray(gridVBO);

	glGenBuffers(1, &gridLinesID);
	glGenBuffers(1, &vertexBufferID);
	glGenBuffers(1, &texBufferID);

	glBindBuffer(GL_ARRAY_BUFFER, gridLinesID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * gridLinesVertices.size(), 
									&gridLinesVertices[0], GL_STATIC_DRAW);

	//load textures 
	blockTexture = loadTexture("blocks.png"); //!< Texture for all blocks 
	glBindTexture(GL_TEXTURE_2D, blockTexture);

	//Load our shaders 
	loadShaders();
	
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);

	vertices.resize(((gridSize.x*gridSize.y)*(3*6)));
	textureCoords.resize((gridSize.x*gridSize.y) * 12);
	std::fill(vertices.begin(), vertices.end(), 0);
	std::fill(textureCoords.begin(), textureCoords.end(), 0);
	
	// Set bricks at side 
	for (uint8 _gridY = 0; _gridY < gridSize.y; _gridY++){
		grid[_gridY*gridSize.x] = 8; 
		grid[(_gridY*gridSize.x) + (gridSize.x - 1)] = 8; 
	}

}

// Generates/ regenerates the buffer for the blocks in the grid 
void genBlockBuffer(){

	//Top left quardinates 
	Vec2 tLeft(-(float)gridSize.x / 2, (float)gridSize.y / 2);

	_vertBufferSize = 0; 
	_texBufferSize = 0; 
	
	uint16 _blockCoords[16];

	// Assign vertices for current block 
	for (uint8 p = 0; p < 4; p++){
		for (uint8 q = 0; q < 4; q++){
			if (currentBlock[(q * 4) + p] == 1){
				uint8 _gridX = blockPosition.x - 1 + p;
				uint8 _gridY = blockPosition.y - 1 + q;

				// If  outside grid bounds 
				if (_gridX < 0 || _gridY < 0)
					continue;

				float _texWidth = 1.0f / 8;
				float _texStartX = currentBlockID * _texWidth;

				// Every three represents a vertex 
				textureCoords[_texBufferSize + 0] = _texStartX;
				textureCoords[_texBufferSize + 1] = 1;
				textureCoords[_texBufferSize + 2] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 3] = 1;
				textureCoords[_texBufferSize + 4] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 5] = 0;
				textureCoords[_texBufferSize + 6] = _texStartX;
				textureCoords[_texBufferSize + 7] = 0;
				textureCoords[_texBufferSize + 8] = _texStartX;
				textureCoords[_texBufferSize + 9] = 1;
				textureCoords[_texBufferSize + 10] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 11] = 0;

				vertices[_vertBufferSize + 0] = tLeft.x + _gridX;
				vertices[_vertBufferSize + 1] = tLeft.y - _gridY;
				
				vertices[_vertBufferSize + 3] = tLeft.x + _gridX + 1;
				vertices[_vertBufferSize + 4] = tLeft.y - _gridY;

				vertices[_vertBufferSize + 6] = tLeft.x + _gridX + 1;
				vertices[_vertBufferSize + 7] = tLeft.y - _gridY - 1;

				vertices[_vertBufferSize + 9] = tLeft.x + _gridX;
				vertices[_vertBufferSize + 10] = tLeft.y - _gridY - 1;

				vertices[_vertBufferSize + 12] = tLeft.x + _gridX;
				vertices[_vertBufferSize + 13] = tLeft.y - _gridY;

				vertices[_vertBufferSize + 15] = tLeft.x + _gridX + 1;
				vertices[_vertBufferSize + 16] = tLeft.y - _gridY - 1;

				_vertBufferSize += 18;
				_texBufferSize += 12; 

			}

		}
	}

	// Calculate new buffer size and prepare vertex array
	for (int x = 0; x < gridSize.x; x++){
		for (int y = 0; y < gridSize.y; y++){

			if (grid[(y*gridSize.x) + x] > 0 ){
	
				float _texWidth = 1.0f / 8;
				float _texStartX = (grid[(y*gridSize.x) + x]-1) * _texWidth;

				// Every three represents a vertex 
				textureCoords[_texBufferSize + 0] = _texStartX;
				textureCoords[_texBufferSize + 1] = 1;
				textureCoords[_texBufferSize + 2] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 3] = 1;
				textureCoords[_texBufferSize + 4] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 5] = 0;
				textureCoords[_texBufferSize + 6] = _texStartX;
				textureCoords[_texBufferSize + 7] = 0;
				textureCoords[_texBufferSize + 8] = _texStartX;
				textureCoords[_texBufferSize + 9] = 1;
				textureCoords[_texBufferSize + 10] = _texStartX + _texWidth;
				textureCoords[_texBufferSize + 11] = 0;

				// Every three represents a vertex 
				vertices[_vertBufferSize + 0] = tLeft.x + x;
				vertices[_vertBufferSize + 1] = tLeft.y - y;

				vertices[_vertBufferSize + 3] = tLeft.x + x + 1;
				vertices[_vertBufferSize + 4] = tLeft.y - y;

				vertices[_vertBufferSize + 6] = tLeft.x + x + 1;
				vertices[_vertBufferSize + 7] = tLeft.y - y - 1;

				vertices[_vertBufferSize + 9] = tLeft.x + x;
				vertices[_vertBufferSize + 10] = tLeft.y - y - 1;

				vertices[_vertBufferSize + 12] = tLeft.x + x;
				vertices[_vertBufferSize + 13] = tLeft.y - y;

				vertices[_vertBufferSize + 15] = tLeft.x + x + 1;
				vertices[_vertBufferSize + 16] = tLeft.y - y - 1;

				_texBufferSize += 12;
				_vertBufferSize += 18;
			}
		}
	}
	
	glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (_vertBufferSize + _texBufferSize),
		0, GL_DYNAMIC_DRAW);

	glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * _vertBufferSize, &vertices[0]);
	glBufferSubData(GL_ARRAY_BUFFER, sizeof(float) * _vertBufferSize, 
								sizeof(float) * _texBufferSize, &textureCoords[0]);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(sizeof(float)*_vertBufferSize));

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

}

// Randomonly select a block/ reset position to the top of the grid.
void newBlock(){
	//random number between 0 and 7
	uint8 _block = (rand() % 7);
	currentBlockType = (0x1 << (_block));
	currentBlockID = _block; 

	//copys the block to the current block array 
	for (uint8 _i = 0; _i < 16; _i++){
		currentBlock[_i] = Block[_block][_i];
	}

	// If start position obstructed clear grid 
	if (grid[gridSize.x / 2]){
		for (int _x = 1; _x < gridSize.x-1; _x++)
			for (int _y = 0; _y < gridSize.y; _y++)
				grid[(_y*gridSize.x) + _x] = 0;
			
	}

	blockPosition = Vec2(gridSize.x/2, 0);
}

// Returns true if the current block is colliding with anything in grid.
bool checkCollision(){

	for (uint8 x = 0; x < 4; x++){
		for (uint8 y = 0; y < 4; y++){
			if (currentBlock[(y * 4) + x]){
				uint8 _gridX = blockPosition.x - 1 + x; 
				uint8 _gridY = blockPosition.y - 1 + y;

				if (_gridX < 0 || _gridY < 0 || _gridX >= gridSize.x || _gridY >= gridSize.y){
					return true; 
				}

				if (grid[(_gridY * gridSize.x) + _gridX]){
					return true; 
				}

			}
		}
	}

	return false; 


}

// Rotates the current block. 
void rotateBlock(){
	//rather than doing anything too elobarate 
	//square is not to rotate// line is speical case, everything else treated as a 3x3 matrix 

	// Is square block 
	if (currentBlockType & BLOCK_TYPE::BLOCK1){
		return; 
	}

	//Copy block to temp array 
	uint8 temp[16];
	for (uint8 i = 0; i < 16; i++)
		temp[i] = currentBlock[i];

	// Is line block 
	if (currentBlockType & BLOCK_TYPE::BLOCK2){
		// Hard coded solution is simpler 
		if (currentBlock[4] != 0){
			for (uint8 i = 0; i < 16; i++){
					currentBlock[i] = 0;
			}
			currentBlock[1] = 1; 
			currentBlock[5] = 1;
			currentBlock[9] = 1;
			currentBlock[13] = 1;
		}
		else{
			for (uint8 i = 0; i < 16; i++){
				currentBlock[i] = Block[1][i];
			}
		}
	
	}
	else if (currentBlockType >= BLOCK_TYPE::BLOCK6){ // Z blocks
		
		uint8 i = 0;

		if (temp[0] == 0 && temp[1] == 0){
			for (i = 0; i < 3; i++){
				for (uint8 p = 0; p < 3; p++)
					currentBlock[(p * 4) + i] = temp[((2 - i) * 4) + p];
			}
		}
		else{
			for (i = 0; i < 3; i++){
				for (uint8 p = 0; p < 3; p++)
					currentBlock[(p * 4) + i] = temp[((i) * 4) + (2 - p)];
			}
		}
	}
	else{	//!< every other block.

		uint8 i = 0;

		for (i = 0; i < 3; i++){
			for (uint8 p = 0; p < 3; p++)
				currentBlock[(p * 4) + i] = temp[((2-i) * 4) + p];
		}
	}

	// If collision after rotating, reset previous position
	if (checkCollision()){
		for (uint8 i = 0; i < 16; i++)
			currentBlock[i] = temp[i];
	}

}

void moveLeft(){

	bool _isColliding = false; 

	for (uint8 x = 0; x < 4; x++){
		for (uint8 y = 0; y < 4; y++){
			if (currentBlock[(y*4)+x]){
				if (blockPosition.x-2+x < 0 || blockPosition.y-1+y < 0){
					_isColliding = true; 
					break; 
				}

				if (grid[((blockPosition.y - 1 + y)*gridSize.x) + blockPosition.x - 2 + x]){
					_isColliding = true;
					break;
				}


			}
		}
	}
	if (!_isColliding){
		blockPosition.x -= 1;
	}
}

void moveRight(){
	bool _isColliding = false;

	for (uint8 x = 0; x < 4; x++){
		for (uint8 y = 0; y < 4; y++){
			if (currentBlock[(y * 4) + x]){
				if (blockPosition.x  + x >= gridSize.x || blockPosition.y - 1 + y > gridSize.y){
					_isColliding = true;
					break;
				}

				if (grid[((blockPosition.y - 1 + y)*gridSize.x) + blockPosition.x  + x]){
					_isColliding = true;
					break;
				}


			}
		}
	}
	if (!_isColliding){
		blockPosition.x += 1;
	}
}

//Remove a line by a given y coordinate
void removeLine(uint8 y){

	// Remove the enteries in grid#
	for (uint8 _x = 1; _x < gridSize.x - 1; _x++){
		grid[(y * gridSize.x) + _x] = 0; 
	}

	// Move all blocks above down by 1 
	for (uint8 _x = 1; _x < gridSize.x - 1; _x++){
		for (uint8 _y = y; gridSize.y - _y != 0; _y--){		
			// set to block above
			grid[(y * gridSize.x) + _x] = grid[((y - 1) * gridSize.x) + _x];
		}
	}

}

void checkLineComplete(){
	//Accounts for brick outline 
	for (uint8 _y = 0; _y < gridSize.y; _y++){
		bool lineComplete = true; 
		for (uint8 _x = 1; _x < gridSize.x-1; _x++){
			
			if (grid[(_y * gridSize.x) + _x] > 0){
				continue; 
			}
			else{
				lineComplete = false; 
				break; 
			}
		}

		if (lineComplete){
			removeLine(_y);
		}
	}
}

void dropDown(){
	// Check whether the block is about to collide, Note block pivot ==  1,1 
	// Which will cause a bit of confusion below I'm sure

	//Cordonites for top left of shapes new position 
	Vec2 topLeft = blockPosition;
	topLeft.x -= 1; 
	bool _collisionDetected = false;


	for (uint8 x = 0; x < 4; x++){
		for (uint8 y = 0; y < 4; y++){
			if (topLeft.x + x < 0 ){
				continue;
			}
			else if (topLeft.y + y >= gridSize.y){
				//check within bounds... 
				if (currentBlock[(4 * y) + x]){
					// Hit bottom of grid
					_collisionDetected = true;
					break; 
				}
			}



			if (currentBlock[(4 * y) + x])
				if (grid[((topLeft.y + y)*(gridSize.x)) + topLeft.x + x]){
					// Collision 
					_collisionDetected = true; 
					break; 
				}


		}
	}

	if (_collisionDetected){
		// Assign values in grid, create new block, return 
		for (uint8 x = 0; x < 4; x++)
			for (uint8 y = 0; y < 4; y++){
				if (currentBlock[(4 * y) + x] )
					grid[((blockPosition.y - 1 + y)*(gridSize.x)) + blockPosition.x - 1 + x] = currentBlockID + 1;
			}

		//Checks if any lines are complete. 
		checkLineComplete(); 
		newBlock();
	}
	else{
		blockPosition.y++;
	}
	
}

void update(){

	//glCheck();

	SDL_PumpEvents();
	float _currentTimeElapsed = SDL_GetTicks();
	blockDropedElapsed += (_currentTimeElapsed - previousTimeElapsed) ; 
	previousTimeElapsed = _currentTimeElapsed; 
	if (blockDropedElapsed > blockDropMS){
		blockDropedElapsed = 0; 
		dropDown(); 
	}

}

void render(){
	SDL_GL_SwapWindow(window);
	glClear(GL_COLOR_BUFFER_BIT);

	glBindTexture(GL_TEXTURE_2D, blockTexture);

	/*glUniform1i(_useColour, 1);
	//!< Draw the grid 
	glBindBuffer(GL_ARRAY_BUFFER, gridLinesID);
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glDrawArrays(GL_LINES, 0, gridLinesVertices.size()/3);*/

	glUniform1i(_useColour, 0);

	genBlockBuffer();
	glDrawArrays(GL_TRIANGLES, 0, _vertBufferSize/3);
	
}

// Loads texture and returns id
int loadTexture(const char* FilePath){
	
	SDL_Surface* image = IMG_Load(FilePath);
	if (image == NULL){
		std::cout<<("Unable to load texture?: Error: %s", SDL_GetError());
		return -1;
	}

	//get the opengl Texture + bind it. 
	GLuint texture;
	
	glGenTextures(1, &texture);
	glBindTexture(GL_TEXTURE_2D, texture);

	/*
	uint32 _bufSize = (image->w * image->h);
	GLuint* pixels = new GLuint[_bufSize]();

	//Flips the pixel order 
	for (uint32 _p = 0; _p < _bufSize; _p++){
		pixels[_p] = ((GLuint *)image->pixels)[_bufSize - _p];

	}*/

	//Assuming theres no alpha layer format is set to GL_RGB

	//Texture info passed from sdl surface
	glTexImage2D(GL_TEXTURE_2D,
		0,//Mipmap Level
		GL_RGB, //bit per pixel
		image->w,
		image->h,
		0,//texture border 	
		GL_RGB,
		GL_UNSIGNED_BYTE,
		image->pixels);
	
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	//glGenerateMipmap(GL_TEXTURE_2D);
	//Clear memory
	SDL_FreeSurface(image);
	//Idelete[] pixels;

	return texture;//Returns the ID in opengl 

}

int main(int argc, char** argv){

	//!<Initialise SDL 
	if (SDL_Init(SDL_INIT_EVERYTHING) != 0){
		return 1;
	}

	IMG_Init(IMG_INIT_PNG);

	window = SDL_CreateWindow("Tetris", 100, 100, windowSize.x, windowSize.y, SDL_WINDOW_OPENGL);
	
	if (window == NULL)
		return 1; 

	SDL_GLContext glcontext;

	//!< Create the OpenGl Context for this window 
	glcontext = SDL_GL_CreateContext(window);

	glewInit();

	//!<OpenGl init.. 
	glClearColor(0, 0, 0, 1);
	

	gameRunning = true; 

	//Init the game // set up viewport matrices etc.. 
	init();

	// Create first block 
	newBlock(); 

	while (gameRunning){
		//!< Update the game 
		update(); 

		//!< Render the game 
		render(); 

		//!< Poll for input 
		poll();
	}

	//Clean up 
	glDeleteTextures(1, &blockTexture);

	//Destroy the OGL Context and window 
	SDL_GL_DeleteContext(glcontext);
	SDL_DestroyWindow(window);
	
	SDL_Quit(); 
	return 0; 

}
Blockrus

 

Leave a Reply