Created
November 22, 2019 17:36
-
-
Save neuro-sys/866fc1a47e3a2c2cc0675cc33babd02e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile: cc minimal.c `pkg-config glew sdl2 SDL2_image --libs --cflags` -lm | |
// Download: https://0fps.files.wordpress.com/2013/07/terrain.png | |
#include <stdio.h> | |
#include <GL/glew.h> | |
#include <SDL.h> | |
#include <SDL_render.h> | |
#include <SDL_opengl.h> | |
#include <SDL_image.h> | |
const char* vertexShaderSource = | |
"#version 130\n" | |
"in vec3 position;\n" | |
"in vec2 texCoord;\n" | |
"uniform vec3 translate;\n" | |
"out vec2 outTexCoord;\n" | |
"void main()\n" | |
"{\n" | |
"outTexCoord = texCoord;\n" | |
"gl_Position = vec4(vec3(position + translate), 1.0);\n" | |
"}\n"; | |
const char* fragmentShaderSource = | |
"#version 130\n" | |
"in vec2 outTexCoord;\n" | |
"uniform sampler2D tex;\n" | |
"void main()\n" | |
"{\n" | |
"vec4 c = texture(tex, outTexCoord);\n" | |
/* "if (c.a < 0.1) { discard; }\n" */ | |
"gl_FragColor = c;\n" | |
"}\n"; | |
int main() | |
{ | |
SDL_Window *window; | |
SDL_Renderer *renderer; | |
SDL_GLContext glContext; | |
SDL_Surface *texture_atlas; | |
int width = 800, height = 800; | |
if (SDL_Init(SDL_INIT_VIDEO)) { | |
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Init error.", "Unable to initialize SDL.", NULL); | |
exit(0); | |
} | |
if (!(window = SDL_CreateWindow("Game", 50, 50, width, height, SDL_WINDOW_OPENGL))) { | |
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Init error.", "Unable to create window.", NULL); | |
exit(0); | |
} | |
if (!(renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED))) { | |
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Init error.", "Unable to create renderer.", NULL); | |
exit(0); | |
} | |
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | |
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | |
if (!(glContext = SDL_GL_CreateContext(window))) { | |
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Init error.", "Unable to create gl context.", NULL); | |
exit(0); | |
}; | |
if (!(texture_atlas = IMG_Load("terrain.png"))) { | |
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Init error.", "Unable to load texture.", NULL); | |
exit(0); | |
} | |
glewInit(); | |
int maj; | |
int min; | |
glGetIntegerv(GL_MAJOR_VERSION, &maj); | |
glGetIntegerv(GL_MINOR_VERSION, &min); | |
printf("OpenGL Version: %d,%d\n", maj, min); | |
glEnable(GL_DEPTH); | |
glEnable(GL_DEPTH_TEST); | |
// Create Shaders | |
GLuint shaderProgram; | |
GLuint vertexShader; | |
GLuint fragmentShader; | |
// Compile Vertex Shader | |
vertexShader = glCreateShader(GL_VERTEX_SHADER); | |
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); | |
glCompileShader(vertexShader); | |
// Compile Fragment Shader | |
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); | |
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); | |
glCompileShader(fragmentShader); | |
// Link Shader Program | |
shaderProgram = glCreateProgram(); | |
glAttachShader(shaderProgram, vertexShader); | |
glAttachShader(shaderProgram, fragmentShader); | |
glLinkProgram(shaderProgram); | |
// Create textures | |
GLuint texture; | |
glGenTextures(1, &texture); | |
glActiveTexture(GL_TEXTURE0); | |
glBindTexture(GL_TEXTURE_2D, texture); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_atlas->w, texture_atlas->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_atlas->pixels); | |
// Create VAO | |
GLuint VAO; | |
glGenVertexArrays(1, &VAO); | |
glBindVertexArray(VAO); | |
// Create VBO | |
GLfloat VBOData[] = { | |
-1.0 / 8.0, -1.0 / 8.0, 0.0, | |
-1.0 / 8.0, 1.0 / 8.0, 0.0, | |
1.0 / 8.0, 1.0 / 8.0, 0.0, | |
-1.0 / 8.0, -1.0 / 8.0, 0.0, | |
1.0 / 8.0, -1.0 / 8.0, 0.0, | |
1.0 / 8.0, 1.0 / 8.0, 0.0, | |
}; | |
GLuint VBO; | |
glGenBuffers(1, &VBO); | |
glBindBuffer(GL_ARRAY_BUFFER, VBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(VBOData), VBOData, GL_STATIC_DRAW); | |
GLint positionAttrib = glGetAttribLocation(shaderProgram, "position"); | |
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); | |
glEnableVertexAttribArray(positionAttrib); | |
GLfloat TBOData[] = { | |
0.0 / 16.0, 1.0 / 16.0, | |
0.0 / 16.0, 0.0 / 16.0, | |
1.0 / 16.0, 0.0 / 16.0, | |
0.0 / 16.0, 1.0 / 16.0, | |
1.0 / 16.0, 1.0 / 16.0, | |
1.0 / 16.0, 0.0 / 16.0, | |
}; | |
GLuint TBO; | |
glGenBuffers(1, &TBO); | |
glBindBuffer(GL_ARRAY_BUFFER, TBO); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(TBOData), TBOData, GL_DYNAMIC_DRAW); | |
GLint textureAttrib = glGetAttribLocation(shaderProgram, "texCoord"); | |
glVertexAttribPointer(textureAttrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0); | |
glEnableVertexAttribArray(textureAttrib); | |
int sprite_x = 0; | |
int sprite_y = 0; | |
unsigned int t1 = SDL_GetTicks(); | |
int alpha_sprite_x = 12; | |
int alpha_sprite_y = 0; | |
GLfloat TBOSubData[sizeof(TBOData) / sizeof(TBOData[0])]; | |
glEnable(GL_BLEND); | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
while (1) { | |
SDL_Event e; | |
while (SDL_PollEvent(&e)) { | |
if (e.type == SDL_QUIT) { | |
exit(0); | |
} | |
} | |
glClearColor(0.1, 0.1, 0.1, 1); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// Enable VAO | |
glBindVertexArray(VAO); | |
glBindTexture(GL_TEXTURE_2D, texture); | |
glUseProgram(shaderProgram); | |
GLint translate = glGetUniformLocation(shaderProgram, "translate"); | |
unsigned int t2 = SDL_GetTicks(); | |
float x = sin(t2 / 1000.0) * 0.5; | |
float y = cos(t2 / 1000.0) * 0.5; | |
GLfloat spritePos[] = { x, y, 0.0 }; | |
for (int i = 0; i < sizeof(TBOData) / sizeof(TBOData[0]); i += 2) { | |
TBOSubData[i + 0] = TBOData[i + 0] + sprite_x * 1.0 / 16.0; | |
TBOSubData[i + 1] = TBOData[i + 1] + sprite_y * 1.0 / 16.0; | |
} | |
glBindBuffer(GL_ARRAY_BUFFER, TBO); | |
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TBOSubData), TBOSubData); | |
glUniform3fv(translate, 1, spritePos); | |
glDrawArrays(GL_TRIANGLES, 0, 6); | |
for (int i = 0; i < sizeof(TBOData) / sizeof(TBOData[0]); i += 2) { | |
TBOSubData[i + 0] = TBOData[i + 0] + alpha_sprite_x * 1.0 / 16.0; | |
TBOSubData[i + 1] = TBOData[i + 1] + alpha_sprite_y * 1.0 / 16.0; | |
} | |
glBindBuffer(GL_ARRAY_BUFFER, TBO); | |
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(TBOSubData), TBOSubData); | |
spritePos[2] = -1e-3; | |
glUniform3fv(translate, 1, spritePos); | |
glDrawArrays(GL_TRIANGLES, 0, 6); | |
SDL_GL_SwapWindow(window); | |
// Every second update texture coordinates to display a different sprite | |
if (t1 + 1000 < SDL_GetTicks()) { | |
t1 = SDL_GetTicks(); | |
sprite_x += 1; | |
if (sprite_x >= 16) { | |
sprite_x = 0; | |
} | |
sprite_y += 1; | |
if (sprite_y >= 16) { | |
sprite_y = 0; | |
} | |
} | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment