diff --git a/Makefile b/Makefile index 2881fc0..858ae12 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,13 @@ CC=gcc CFLAGS=-O1 -DDEBUG -g -ggdb -std=c23 LIBS=`pkg-config sdl3 --cflags --libs` -lGL -lGLEW -lm -OBJ = main.o +HEADER = opengl.h readfile.h +OBJ = main.o opengl.o readfile.o all: mobiground -%.o: %.c # Add all .o and .c files to compiler - $(CC) -c -o $@ $< $(CFLAGS) # compile, generate, all output, prerequisite implicit rule, compile flags. +%.o: %.c $(HEADER) + $(CC) -c -o $@ $< $(CFLAGS) mobiground: $(OBJ) $(CC) -o $@ $^ $(CFLAGS) $(LIBS) diff --git a/main.c b/main.c index 8732666..d1abf51 100644 --- a/main.c +++ b/main.c @@ -6,24 +6,15 @@ #include #include #include // only include this one in the source file with main()! +#include "opengl.h" #define INITIAL_FPS 60 -SDL_Window* window = NULL; -SDL_GLContext glcontext = NULL; - -GLuint program; -GLuint vbo; -GLuint ibo; -GLuint projMatrLoc; - static double FPS = INITIAL_FPS; static double FrameTime = 1.0 / INITIAL_FPS; static double PerformancePeriod; -static void panicError ( void ) __attribute__((noreturn)); - static double GetTime( void ) { return PerformancePeriod * SDL_GetPerformanceCounter(); @@ -45,6 +36,7 @@ float toRad ( float deg ) void resizeWindow ( int width, int height ) { + shaderProgram_t sp; float n = 1.0f; // near float f = 3.0f; // far float fov = toRad(90); // 90 or 65 for console @@ -55,196 +47,20 @@ void resizeWindow ( int width, int height ) float projMatr[] = { n/r, 0, 0, 0, 0, n/t, 0, 0, - 0, 0, (f+n)/(n-f), -1, + 0, 0, (f+n)/(n-f), -1, 0, 0, 2.0f*n*f/(n-f), 0 }; // it's not rows, it's columns, 'GL_FALSE' SDL_LogVerbose(SDL_LOG_CATEGORY_RENDER, "n=%.1f f=%.1f fov=%.2f aspect=%.2f t=%.2f r=%.2f\n", n, f, fov, aspect, t, r); - glUseProgram(program); - glUniformMatrix4fv(projMatrLoc, 1, GL_FALSE, projMatr); + glUseProgram(sp.program); + glUniformMatrix4fv(sp.projMatrLoc, 1, GL_FALSE, projMatr); glUseProgram(0); glViewport(0, 0, (GLsizei)width, (GLsizei)height); } -void panicError ( void ) -{ - SDL_GL_DestroyContext(glcontext); - SDL_DestroyWindow(window); - SDL_Quit(); - exit(EXIT_FAILURE); -} - -char *readFile ( const char *fileName ) -{ - SDL_IOStream *ioStream = SDL_IOFromFile(fileName, "rb"); - if (!ioStream) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "ioStream: %s.", SDL_GetError()); - panicError(); - } - if (SDL_SeekIO(ioStream, 0, SDL_IO_SEEK_END) == -1) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_SeekIO_END: %s.", SDL_GetError()); - panicError(); - } - long len = SDL_TellIO(ioStream); - if (len == -1) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_TellIO: %s.", SDL_GetError()); - panicError(); - } - if (SDL_SeekIO(ioStream, 0, SDL_IO_SEEK_SET) == -1) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_IO_SEEK_SET: %s.", SDL_GetError()); - panicError(); - } - char *res = SDL_malloc(len + 1); - if (!res) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_malloc: %s.", SDL_GetError()); - panicError(); - } - if (SDL_ReadIO(ioStream, res, len) != (size_t)len) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_ReadIO: %s.", SDL_GetError()); - panicError(); - } - if (!SDL_CloseIO(ioStream)) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_CloseIO: %s.", SDL_GetError()); - panicError(); - } - res[len] = 0; - return res; -} - -GLuint createShader ( const char *shaderFile, GLenum shaderType ) -{ - const char *strShaderType; - if (shaderType == GL_VERTEX_SHADER) { - strShaderType = "vertex"; - } else if (shaderType == GL_GEOMETRY_SHADER) { - strShaderType = "geometry"; - } else if (shaderType == GL_FRAGMENT_SHADER) { - strShaderType = "fragment"; - } else { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Unrecognized shader type."); - panicError(); - } - GLuint shader = glCreateShader(shaderType); - if (!shader) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Error create shader type %s.", strShaderType); - panicError(); - } - GLchar *content = readFile(shaderFile); - glShaderSource(shader, 1, (const GLchar **)&content, NULL); - SDL_free(content); - glCompileShader(shader); - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLint infoLen; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); - GLchar *info = SDL_malloc(sizeof(GLchar) * (infoLen + 1)); - glGetShaderInfoLog(shader, infoLen, NULL, info); - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Filed to compile %s shader:\n%s.", strShaderType, info); - panicError(); - } - return shader; -} - -void createProgram ( GLuint *shaders, int len ) -{ - program = glCreateProgram(); - if (!program) { - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Can't to create shader program."); - panicError(); - } - for (int i = 0; i < len; i++) { - glAttachShader(program, shaders[i]); - } - glLinkProgram(program); - GLint status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLint infoLen; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); - GLchar *info = SDL_malloc(sizeof(GLchar) * (infoLen + 1)); - glGetProgramInfoLog(program, infoLen, NULL, info); - SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Link failed: %s", info); - panicError(); - } -} - -void createBuffer ( void ) -{ - GLushort indices[] = { - 0, 1, 2, - 0, 2, 3 - }; - float vertices[] = { - -1.0f, -1.0f, -2.0f, 1.0f, // left-bottom - -1.0f, 1.0f, -2.0f, 1.0f, // left-top - 1.0f, 1.0f, -2.0f, 1.0f, // right-top - 1.0f, -1.0f, -2.0f, 1.0f, // right-bottom - - // colours - 1.0f, 0.0f, 0.0f, 1.0f, // red - 0.0f, 1.0f, 0.0f, 1.0f, // green - 1.0f, 0.0f, 1.0f, 1.0f, // purple - 1.0f, 1.0f, 0.0f, 1.0f // yellow - }; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void setUniformLocation ( void ) -{ - projMatrLoc = glGetUniformLocation(program, "projMatr"); -} - -void startShaderProg ( void ) -{ - createBuffer(); - - GLuint shaders[] = { - createShader("vertex.glsl", GL_VERTEX_SHADER), - createShader("fragment.glsl", GL_FRAGMENT_SHADER) - }; - int len = sizeof(shaders) / sizeof(shaders[0]); - createProgram(shaders, len); - for (int i = 0; i < len; i++) { - glDeleteShader(shaders[i]); - } - - setUniformLocation(); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LEQUAL); - glDepthRange(0.0f, 1.0f); -} - -void _GLBuffer( void ) -{ - glClearColor(0.0f, 0.0f, 1.0f, 0.0f); - glClearDepth(1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glUseProgram(program); - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); - glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *) (4*4*sizeof(float))); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - - glUseProgram(0); -} int main( int argc, char* argv[] ) { + _glWindows_t glW; const int WIDTH = 640; const int HEIGHT = 480; int delayThreshold = 2; @@ -256,12 +72,12 @@ int main( int argc, char* argv[] ) SDL_SetHint(SDL_HINT_RENDER_VSYNC, 0); if (!SDL_Init(SDL_INIT_VIDEO)) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_Init failed: %s", SDL_GetError()); - panicError(); + exit(EXIT_FAILURE); } - if (!SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)) { + if (!SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY)) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Set atrribute SDL_GL_CONTEXT_PROFILE_MASK: %s", SDL_GetError()); - panicError(); + exit(EXIT_FAILURE); } SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); @@ -277,19 +93,19 @@ int main( int argc, char* argv[] ) PerformancePeriod = 1.0 / SDL_GetPerformanceFrequency(); timeCounter = GetTime(); - window = SDL_CreateWindow("Hello SDL", WIDTH, HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); - if (!window) { + glW.window = SDL_CreateWindow("Hello SDL", WIDTH, HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + if (!glW.window) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_CreateWindow: %s", SDL_GetError()); - panicError(); + exit(EXIT_FAILURE); } - glcontext = SDL_GL_CreateContext(window); - if (!glcontext) { + glW.glcontext = SDL_GL_CreateContext(glW.window); + if (!glW.glcontext) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_GL_CreateContext: %s", SDL_GetError()); - panicError(); + exit(EXIT_FAILURE); } - SetTitle(window); + SetTitle(glW.window); SDL_HideCursor(); @@ -297,7 +113,7 @@ int main( int argc, char* argv[] ) GLenum err = glewInit(); if (err != GLEW_OK) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "glewInit: %s", glewGetErrorString(err)); - panicError(); + exit(EXIT_FAILURE); } SDL_LogVerbose(SDL_LOG_CATEGORY_RENDER, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); @@ -337,11 +153,11 @@ int main( int argc, char* argv[] ) FPS = 1; } FrameTime = 1.0 / FPS; - SetTitle(window); + SetTitle(glW.window); } else if (e.key.key == SDLK_C) { FPS += 0.1; FrameTime = 1.0 / FPS; - SetTitle(window); + SetTitle(glW.window); } if (e.key.key == SDLK_ESCAPE) loopShouldStop = true; @@ -349,9 +165,9 @@ int main( int argc, char* argv[] ) } _GLBuffer(); - if (!SDL_GL_SwapWindow(window)) { + if (!SDL_GL_SwapWindow(glW.window)) { SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_GL_SwapWwindow: %s", SDL_GetError()); - panicError(); + exit(EXIT_FAILURE); } sleepTime = timeCounter - GetTime(); @@ -370,8 +186,8 @@ int main( int argc, char* argv[] ) timeCounter += FrameTime; } - SDL_DestroyWindow(window); - SDL_GL_DestroyContext(glcontext); + SDL_DestroyWindow(glW.window); + SDL_GL_DestroyContext(glW.glcontext); SDL_Quit(); exit(EXIT_SUCCESS); } diff --git a/opengl.c b/opengl.c new file mode 100644 index 0000000..d49deb5 --- /dev/null +++ b/opengl.c @@ -0,0 +1,143 @@ +#include + +#include +#include +#include + +#include "opengl.h" +#include "readfile.h" + +shaderProgram_t sp; + +GLuint createShader ( const char *shaderFile, GLenum shaderType ) +{ + const char *strShaderType; + if (shaderType == GL_VERTEX_SHADER) { + strShaderType = "vertex"; + } else if (shaderType == GL_GEOMETRY_SHADER) { + strShaderType = "geometry"; + } else if (shaderType == GL_FRAGMENT_SHADER) { + strShaderType = "fragment"; + } else { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Unrecognized shader type."); + exit(EXIT_FAILURE); + } + GLuint shader = glCreateShader(shaderType); + if (!shader) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Error create shader type %s.", strShaderType); + exit(EXIT_FAILURE); + } + GLchar *content = readFile(shaderFile); + glShaderSource(shader, 1, (const GLchar **)&content, NULL); + SDL_free(content); + glCompileShader(shader); + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLint infoLen; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + GLchar *info = SDL_malloc(sizeof(GLchar) * (infoLen + 1)); + glGetShaderInfoLog(shader, infoLen, NULL, info); + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Filed to compile %s shader:\n%s.", strShaderType, info); + exit(EXIT_FAILURE); + } + return shader; +} + +void createProgram ( GLuint *shaders, int len ) +{ + sp.program = glCreateProgram(); + if (!sp.program) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Can't to create shader program."); + exit(EXIT_FAILURE); + } + for (int i = 0; i < len; i++) { + glAttachShader(sp.program, shaders[i]); + } + glLinkProgram(sp.program); + GLint status; + glGetProgramiv(sp.program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLint infoLen; + glGetProgramiv(sp.program, GL_INFO_LOG_LENGTH, &infoLen); + GLchar *info = SDL_malloc(sizeof(GLchar) * (infoLen + 1)); + glGetProgramInfoLog(sp.program, infoLen, NULL, info); + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Link failed: %s", info); + exit(EXIT_FAILURE); + } +} + +void createBuffer ( void ) +{ + GLushort indices[] = { + 0, 1, 2, + 0, 2, 3 + }; + float vertices[] = { + -1.0f, -1.0f, -2.0f, 1.0f, // left-bottom + -1.0f, 1.0f, -2.0f, 1.0f, // left-top + 1.0f, 1.0f, -2.0f, 1.0f, // right-top + 1.0f, -1.0f, -2.0f, 1.0f, // right-bottom + + // colours + 1.0f, 0.0f, 0.0f, 1.0f, // red + 0.0f, 1.0f, 0.0f, 1.0f, // green + 1.0f, 0.0f, 1.0f, 1.0f, // purple + 1.0f, 1.0f, 0.0f, 1.0f // yellow + }; + glGenBuffers(1, &sp.vbo); + glBindBuffer(GL_ARRAY_BUFFER, sp.vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenBuffers(1, &sp.ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sp.ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void setUniformLocation ( void ) +{ + sp.projMatrLoc = glGetUniformLocation(sp.program, "projMatr"); +} + +void startShaderProg ( void ) +{ + createBuffer(); + + GLuint shaders[] = { + createShader("vertex.glsl", GL_VERTEX_SHADER), + createShader("fragment.glsl", GL_FRAGMENT_SHADER) + }; + int len = sizeof(shaders) / sizeof(shaders[0]); + createProgram(shaders, len); + for (int i = 0; i < len; i++) { + glDeleteShader(shaders[i]); + } + + setUniformLocation(); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + glDepthRange(0.0f, 1.0f); +} + +void _GLBuffer( void ) +{ + glClearColor(0.0f, 0.0f, 1.0f, 0.0f); + glClearDepth(1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glUseProgram(sp.program); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, sp.vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sp.ibo); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void *) (4*4*sizeof(float))); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + + glUseProgram(0); +} diff --git a/opengl.h b/opengl.h new file mode 100644 index 0000000..b4ead28 --- /dev/null +++ b/opengl.h @@ -0,0 +1,22 @@ +#ifndef OPENGL_H +#define OPENGL_H + +typedef struct { + SDL_Window* window; + SDL_GLContext glcontext; +} _glWindows_t; + +typedef struct { + GLuint program; + GLuint vbo; + GLuint ibo; + GLuint projMatrLoc; +} shaderProgram_t; + +GLuint createShader ( const char *shaderFile, GLenum shaderType ); +void createProgram ( GLuint *shaders, int len ); +void createBuffer ( void ); +void startShaderProg ( void ); +void _GLBuffer( void ); + +#endif diff --git a/readfile.c b/readfile.c new file mode 100644 index 0000000..7252adf --- /dev/null +++ b/readfile.c @@ -0,0 +1,40 @@ +#include +#include +#include "readfile.h" + +char *readFile ( const char *fileName ) +{ + SDL_IOStream *ioStream = SDL_IOFromFile(fileName, "rb"); + if (!ioStream) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "ioStream: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + if (SDL_SeekIO(ioStream, 0, SDL_IO_SEEK_END) == -1) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_SeekIO_END: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + long len = SDL_TellIO(ioStream); + if (len == -1) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_TellIO: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + if (SDL_SeekIO(ioStream, 0, SDL_IO_SEEK_SET) == -1) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_IO_SEEK_SET: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + char *res = SDL_malloc(len + 1); + if (!res) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_malloc: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + if (SDL_ReadIO(ioStream, res, len) != (size_t)len) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_ReadIO: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + if (!SDL_CloseIO(ioStream)) { + SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_CloseIO: %s.", SDL_GetError()); + exit(EXIT_FAILURE); + } + res[len] = 0; + return res; +} diff --git a/readfile.h b/readfile.h new file mode 100644 index 0000000..fbe6c6a --- /dev/null +++ b/readfile.h @@ -0,0 +1,6 @@ +#ifndef READFILE_H +#define READFILE_H + +char *readFile ( const char *fileName ); + +#endif