Hey i’ve written a little 2d-renderer that updates every object using glMapBufferRange() and i have positions and colors in separate VBO’s but i render evertying with one call to glDrawElements.
however my framrate is at about 83 miliseconds when i render 50K rectangles.
The bottleneck is obviously that i iterate over all 50k objects in a for-loop each frame, but what if i wanted to update 50k objects of different sizes and textures but still keep the framrate low, how would one go about to get that performance?
is there someother way to render a lot more rectangles for a 2D game?
I thought updating vertices with glMapBufferRange and using one glDrawElements was supposed to be faster then using uniforms and one drawcall per transform-update.
VertexShader.glgl:
#version 330 core
layout (location = 0) in vec4 inPos;
layout (location = 3) in vec4 inCol;
out vec4 colorVS;
uniform vec2 windowDimensions;
void main()
{
vec4 vertexPosition;
vertexPosition.xyz = inPos.xyz;
vertexPosition.x = (2 * vertexPosition.x / windowDimensions.x) - 1.0f;
vertexPosition.y = 1.0f - (2 * vertexPosition.y / windowDimensions.y);
vertexPosition.z = 0.0f;
vertexPosition.w = 1.0f;
gl_Position = vertexPosition;
colorVS = inCol;
}
FragmentShader.glgl:
#version 330 core
in vec4 colorVS;
out vec4 fragmentColor;
uniform vec4 iColorData;
void main()
{
vec4 result_Color = colorVS;
//result_Color.r /= iColorData.r;
//result_Color.g /= iColorData.g;
//result_Color.b /= iColorData.b;
//result_Color.a /= iColorData.a;
fragmentColor = result_Color;
}
Main.cpp:
#include "glad\glad.c"
#include "GLFW\glfw3.h"
#include "glm\glm.hpp"
#include "glm\gtc\matrix_transform.hpp"
#include "glm\gtc\type_ptr.hpp"
#include <iostream>
#include <time.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <CJGL_Input.h>
#define SCR_WIDTH 1920
#define SCR_HEIGHT 1080
#define NUMOBJECTS 50000
GLFWwindow* windowSetup(int width, int height);
char* loadShaderFile(char* filePath);
GLenum err;
bool running = true;
struct Time
{
double startTime;
double endTime;
double dt_s;
double dt_ms;
double getMiliSeconds()
{
return dt_ms;
}
double getSeconds()
{
return dt_s;
}
void start()
{
dt_s = startTime - endTime;
dt_ms = dt_s * 1000.0f;
endTime = startTime;
startTime = glfwGetTime();
}
};
struct GameObject
{
float x;
float y;
float width;
float height;
float r, g, b, a;
float vertices[28];
float vertex_Positions[16];
float vertex_Colors[16];
float vertex_TextureCoords[8];
int bufferIndex;
int positionVBO;
int colorVBO;
int textureVBO;
float *pPosition;
float *pColor;
float getX()
{
return x;
}
float getY()
{
return y;
}
float getWidth()
{
return width;
}
float getHeight()
{
return height;
}
void setPositionVBO(unsigned int in_VBO)
{
positionVBO = in_VBO;
}
void setColorVBO(unsigned int in_VBO)
{
colorVBO = in_VBO;
}
void setTextureVBO(unsigned int in_VBO)
{
textureVBO = in_VBO;
}
void bindPositionVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
}
void bindColorVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
}
void bindTextureVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, textureVBO);
}
void init(float in_x, float in_y, float in_width, float in_height)
{
pPosition = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Positions), sizeof(vertex_Positions), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
x = in_x;
y = in_y;
width = in_width;
height = in_height;
//color = in_color;
pPosition[0] = x;
pPosition[4] = x;
pPosition[8] = x + width;
pPosition[12] = x + width;
pPosition[1] = y;
pPosition[5] = y + height;
pPosition[9] = y + height;
pPosition[13] = y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setX(float in_x)
{
x = in_x;
pPosition = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Positions), sizeof(vertex_Positions), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pPosition[0] = x;
pPosition[4] = x;
pPosition[8] = x + width;
pPosition[12] = x + width;
pPosition[1] = y;
pPosition[5] = y + height;
pPosition[9] = y + height;
pPosition[13] = y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setY(float in_y)
{
y = in_y;
pPosition = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Positions), sizeof(vertex_Positions), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pPosition[0] = x;
pPosition[4] = x;
pPosition[8] = x + width;
pPosition[12] = x + width;
pPosition[1] = y;
pPosition[5] = y + height;
pPosition[9] = y + height;
pPosition[13] = y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setWidth(float in_width)
{
width = in_width;
pPosition = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Positions), sizeof(vertex_Positions), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pPosition[0] = x;
pPosition[4] = x;
pPosition[8] = x + width;
pPosition[12] = x + width;
pPosition[1] = y;
pPosition[5] = y + height;
pPosition[9] = y + height;
pPosition[13] = y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setHeight(float in_height)
{
height = in_height;
pPosition = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Positions), sizeof(vertex_Positions), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pPosition[0] = x;
pPosition[4] = x;
pPosition[8] = x + width;
pPosition[12] = x + width;
pPosition[1] = y;
pPosition[5] = y + height;
pPosition[9] = y + height;
pPosition[13] = y;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setPosition( float in_x, float in_y)
{
x = in_x;
y = in_y;
pPosition[0] = in_x;
pPosition[4] = in_x;
pPosition[8] = in_x + width;
pPosition[12] = in_x + width;
pPosition[1] = in_y;
pPosition[5] = in_y;
pPosition[9] = in_y + height;
pPosition[13] = in_y + height;
}
void setDimensions(float in_width, float in_height)
{
width = in_width;
height = in_height;
pPosition[8] = x + in_width;
pPosition[12] = x + in_width;
pPosition[5] = y + in_height;
pPosition[9] = y + in_height;
}
void setSolidColor(float in_r, float in_g, float in_b, float in_a)
{
r = in_r;
g = in_g;
b = in_b;
a = in_a;
pColor = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Colors), sizeof(vertex_Colors), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pColor[0] = r; pColor[1] = g; pColor[2] = b; pColor[3] = a;
pColor[4] = r; pColor[5] = g; pColor[6] = b; pColor[7] = a;
pColor[8] = r; pColor[9] = g; pColor[10] = b; pColor[11] = a;
pColor[12] = r; pColor[13] = g; pColor[14] = b; pColor[15] = a;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setColorBottomLeft(float r, float g, float b, float a)
{
pColor = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Colors), 4 * sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pColor[0] = r;
pColor[1] = g;
pColor[2] = b;
pColor[3] = a;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setColorTopLeft(float r, float g, float b, float a)
{
pColor = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Colors) + 4 * sizeof(float), 4 * sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pColor[0] = r;
pColor[1] = g;
pColor[2] = b;
pColor[3] = a;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setColorTopRight(float r, float g, float b, float a)
{
pColor = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Colors) + 8 * sizeof(float), 4 * sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pColor[0] = r;
pColor[1] = g;
pColor[2] = b;
pColor[3] = a;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
void setColorBottomRight(float r, float g, float b, float a)
{
pColor = (float*)glMapBufferRange(GL_ARRAY_BUFFER, bufferIndex * sizeof(vertex_Colors) + 12 * sizeof(float), 4 * sizeof(float), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
pColor[0] = r;
pColor[1] = g;
pColor[2] = b;
pColor[3] = a;
glUnmapBuffer(GL_ARRAY_BUFFER);
}
};
struct GameBufferObject
{
unsigned int positionVBO = 0;
unsigned int colorVBO = 0;
unsigned int textureVBO = 0;
unsigned int IBO = 0;
unsigned int VAO = 0;
void genVertexArray()
{
glGenVertexArrays(1, &VAO);
}
void genBuffers()
{
glGenBuffers(1, &positionVBO);
glGenBuffers(1, &colorVBO);
glGenBuffers(1, &textureVBO);
}
void bindVAO()
{
glBindVertexArray(VAO);
}
void bindPositionVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, positionVBO);
}
void bindColorVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, colorVBO);
}
void bindTextureVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, textureVBO);
}
void bindIBO()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
}
};
struct GameBuffer
{
float vData[16];
};
int main()
{
srand(time(NULL));
GLFWwindow *window = windowSetup(SCR_WIDTH, SCR_HEIGHT);
char *shaderTextBuffer = loadShaderFile("vertexShader.glsl");
char *fragmentTextBuffer = loadShaderFile("fragmentShader.glsl");
unsigned int VS = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(VS, 1, &shaderTextBuffer, 0);
glCompileShader(VS);
int success;
char infoLog[1080];
glGetShaderiv(VS, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(VS, 1080, 0, infoLog);
printf("VERTEX_SHADER: %s\n", infoLog);
}
unsigned int FS = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(FS, 1, &fragmentTextBuffer, 0);
glCompileShader(FS);
glGetShaderiv(FS, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(FS, 1080, 0, infoLog);
printf("FRAGMENT_SHADER: %s\n", infoLog);
}
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, VS);
glAttachShader(shaderProgram, FS);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if(!success)
{
glGetProgramInfoLog(shaderProgram, 1080, 0, infoLog);
printf("LINK_PROGRAM: %s\n", infoLog);
}
/*
int indices[] =
{
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
8, 9 ,
9, 10,
10, 11,
11, 8
};
*/
/*
int indices[] =
{
0, 1, 2, 2, 3, 0, 4, 5, 6, 6, 7, 4
};
*/
int gameObjIndices[NUMOBJECTS * 6] = {};
for(int i = 0; i < NUMOBJECTS; i++)
{
gameObjIndices[0 + i * 6] = i * 4;
gameObjIndices[1 + i * 6] = i * 4 + 1;
gameObjIndices[2 + i * 6] = i * 4 + 2;
gameObjIndices[3 + i * 6] = i * 4 + 2;
gameObjIndices[4 + i * 6] = i * 4 + 3;
gameObjIndices[5 + i * 6] = i * 4;
}
int boundingBoxIndices[8] = {};
for(int i = 0; i < 1; i++)
{
boundingBoxIndices[0 + i * 8] = i * 4;
boundingBoxIndices[1 + i * 8] = i * 4 + 1;
boundingBoxIndices[2 + i * 8] = i * 4 + 1;
boundingBoxIndices[3 + i * 8] = i * 4 + 2;
boundingBoxIndices[4 + i * 8] = i * 4 + 2;
boundingBoxIndices[5 + i * 8] = i * 4 + 3;
boundingBoxIndices[6 + i * 8] = i * 4 + 3;
boundingBoxIndices[7 + i * 8] = i * 4;
}
GameObject gameObj[NUMOBJECTS] = {};
GameBuffer gameObjPosBuffer[NUMOBJECTS] = {};
GameBuffer gameObjColBuffer[NUMOBJECTS] = {};
for(int i = 0; i < NUMOBJECTS; i++)
{
gameObj[i].bufferIndex = i;
}
GameBufferObject gameObjBuffObject = {};
glGenVertexArrays(1, &gameObjBuffObject.VAO);
glGenBuffers(1, &gameObjBuffObject.positionVBO);
glGenBuffers(1, &gameObjBuffObject.colorVBO);
glGenBuffers(1, &gameObjBuffObject.IBO);
glBindVertexArray(gameObjBuffObject.VAO);
// POSITION ATTRIB
gameObjBuffObject.bindPositionVBO();
glBufferData(GL_ARRAY_BUFFER, sizeof(gameObjPosBuffer), gameObjPosBuffer, GL_STREAM_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
// COLOR ATTRIB
gameObjBuffObject.bindColorVBO();
glBufferData(GL_ARRAY_BUFFER, sizeof(gameObjColBuffer), gameObjColBuffer, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
// INDEX BUFFER
gameObjBuffObject.bindIBO();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(gameObjIndices), gameObjIndices, GL_STATIC_DRAW);
gameObjBuffObject.bindPositionVBO();
for(int i = 0; i < NUMOBJECTS; i++)
{
float randX = (rand() % 1920) ;
float randY = (rand() % 1080) ;
float randW = (rand() % 80 ) ;
float randH = (rand() % 80 ) ;
gameObj[i].init(randX, randY, randW, randH);
}
gameObjBuffObject.bindColorVBO();
for(int i = 0; i < NUMOBJECTS; i++)
{
float randC = (((float)rand() / (RAND_MAX))+ 1.0f) - 0.3f;
if(randC < 0.05f)
{
randC = 0.09f;
}
if(i % 2 == 0)
{
gameObj[i].setColorBottomLeft(randC, 0.0f, 0.0f, 1.0f);
gameObj[i].setColorTopLeft(0.0f, randC, 0.0f, 1.0f);
gameObj[i].setColorBottomRight(0.0f, 0.0f, randC, 1.0f);
gameObj[i].setColorTopRight(randC, 0.0f, 0.0f, 1.0f);
}
else if(i % 3 == 0)
{
gameObj[i].setSolidColor(0.0f, randC, 0.0f, 1.0f);
}
else if(i % 5 == 0)
{
gameObj[i].setSolidColor(0.0f, 0.0f, randC, 1.0f);
}
else
{
gameObj[i].setSolidColor(0.5f, 0.0f, 0.5f, 1.0f);
}
}
GameObject boundingBox = {};
GameBuffer boundingBoxPositionBuffer = {};
GameBuffer boundingBoxColorBuffer = {};
boundingBox.bufferIndex = 0;
GameBufferObject boundingBoxBufferObject = {};
glGenVertexArrays(1, &boundingBoxBufferObject.VAO);
glGenBuffers(1, &boundingBoxBufferObject.positionVBO);
glGenBuffers(1, &boundingBoxBufferObject.colorVBO);
glGenBuffers(1, &boundingBoxBufferObject.IBO);
// POSITION VBO
glBindVertexArray(boundingBoxBufferObject.VAO);
boundingBoxBufferObject.bindPositionVBO();
glBufferData(GL_ARRAY_BUFFER, sizeof(boundingBoxPositionBuffer), &boundingBoxPositionBuffer, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
// COLOR VBO
boundingBoxBufferObject.bindColorVBO();
glBufferData(GL_ARRAY_BUFFER, sizeof(boundingBoxColorBuffer), &boundingBoxColorBuffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
// INDEX BUFFER
boundingBoxBufferObject.bindIBO();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(boundingBoxIndices), boundingBoxIndices, GL_STATIC_DRAW);
// SETTING COLORS
boundingBoxBufferObject.bindColorVBO();
boundingBox.setSolidColor(1.0f, 0.3f, 0.1f, 1.0f);
glViewport(0, 0, 800, 600);
glUseProgram(shaderProgram);
int winWidth = 0;
int winHeight = 0;
double mouseCurPosX = 0;
double mouseCurPosY = 0;
int winDimLoc = glGetUniformLocation(shaderProgram, "windowDimensions");
char windowTitle[100] = {};
int boundBox_X = 0;
int boundBox_Y = 0;
float movU = 0.0f;
float movD = 0.0f;
float movR = 0.0f;
float movL = 0.0f;
Time time = {};
while(!glfwWindowShouldClose(window) && running)
{
time.start();
printf("seconds: %f\n", time.getMiliSeconds());
glfwGetWindowSize(window, &winWidth, &winHeight);
glUniform2f(winDimLoc, (float)winWidth, (float)winHeight);
glViewport(0, 0, winWidth, winHeight);
checkInput(window);
glClearColor(0.0f, 0.05f, 0.05f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwGetCursorPos(window, &mouseCurPosX, &mouseCurPosY);
sprintf(windowTitle, "CJGL Game - MouseCursor: %4.3f, %4.3f - Window (width/height): %d/%d)", mouseCurPosX, mouseCurPosY, winWidth, winHeight);
glfwSetWindowTitle(window, windowTitle);
boundingBoxBufferObject.bindPositionVBO();
if(keyPressed[LEFT_MOUSE_BUTTON])
{
boundingBox.setX(boundBox_X);
boundingBox.setY(boundBox_Y);
boundingBox.setWidth(mouseCurPosX - boundBox_X);
boundingBox.setHeight(mouseCurPosY- boundBox_Y);
}
else
{
boundingBox.setX(0.0f);
boundingBox.setY(0.0f);
boundingBox.setWidth(0.0f);
boundingBox.setHeight(0.0f);
boundBox_X = mouseCurPosX;
boundBox_Y = mouseCurPosY;
}
if(keyPressed[RIGHT_MOUSE_BUTTON])
{
}
if(keyPressed[ESC])
{
running = false;
}
if(keyPressed['W'])
{
}
if(keyPressed['S'])
{
}
if(keyPressed['A'])
{
}
if(keyPressed['D'])
{
}
boundingBoxBufferObject.bindColorVBO();
if(keyPressed['K'])
{
}
if(keyPressed['I'])
{
}
if(keyPressed['O'])
{
}
if(keyPressed['L'])
{
}
gameObjBuffObject.bindPositionVBO();
if(keyPressed[LEFT_ARROW])
{
movL = -0.5f * time.getMiliSeconds();
}
else
{
movL = 0.0f;
}
if(keyPressed[RIGHT_ARROW])
{
movR = +0.5f * time.getMiliSeconds();
}
else
{
movR = 0.0f;
}
if(keyPressed[UP_ARROW])
{
movU = -0.5f * time.getMiliSeconds();
}
else
{
movU = 0.0f;
}
if(keyPressed[DOWN_ARROW])
{
movD = +0.5f * time.getMiliSeconds();
}
else
{
movD = 0.0f;
}
for(int i = 0; i < NUMOBJECTS; i++)
{
gameObj[i].setX(gameObj[i].getX() + movR + movL);
gameObj[i].setY(gameObj[i].getY() + movU + movD);
}
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
gameObjBuffObject.bindVAO();
glBindBuffer(GL_ARRAY_BUFFER, gameObjBuffObject.positionVBO);
glDrawElements(GL_TRIANGLES, NUMOBJECTS * 6, GL_UNSIGNED_INT, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
boundingBoxBufferObject.bindVAO();
glBindBuffer(GL_ARRAY_BUFFER, boundingBoxBufferObject.positionVBO);
glDrawElements(GL_LINES, 8, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteShader(VS);
glDeleteShader(FS);
glDeleteProgram(shaderProgram);
glDeleteBuffers(1, &boundingBoxBufferObject.positionVBO);
glDeleteBuffers(1, &boundingBoxBufferObject.colorVBO);
glDeleteBuffers(1, &boundingBoxBufferObject.IBO);
glDeleteBuffers(1, &boundingBoxBufferObject.VAO);
glDeleteBuffers(1, &gameObjBuffObject.positionVBO);
glDeleteBuffers(1, &gameObjBuffObject.colorVBO);
glDeleteBuffers(1, &gameObjBuffObject.IBO);
glDeleteBuffers(1, &gameObjBuffObject.VAO);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
char* loadShaderFile(char* in_filePath)
{
FILE *fileHandle = {};
char *filePath = in_filePath;
fileHandle = fopen(filePath, "r");
if(!fileHandle)
{
printf("Couldn't open %s\n", filePath);
}
const int nCharsInFile = 2000;
char fileTextBuffer[nCharsInFile] = {};
char* shaderTextBuffer = (char*)malloc(nCharsInFile);
strcpy(shaderTextBuffer, "");
while(fgets(fileTextBuffer, nCharsInFile, fileHandle) != 0)
{
strcat(shaderTextBuffer, fileTextBuffer);
}
return shaderTextBuffer;
printf("%s\n", shaderTextBuffer);
fclose(fileHandle);
}
GLFWwindow* windowSetup(int width, int height)
{
if(!glfwInit())
{
printf("FAILED TO INIT\n");
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window;
window = glfwCreateWindow(width, height, "GL GAME", 0, 0);
glfwMakeContextCurrent(window);
if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
printf("GLAD FAILED\n");
}
glfwSwapInterval(1);
return window;
}