mobiground/main.c

296 lines
8.8 KiB
C
Raw Permalink Normal View History

2024-12-23 06:02:33 +05:00
#include <stdio.h>
#include <stdlib.h>
2024-11-12 17:08:03 +05:00
2024-12-23 06:02:33 +05:00
#include <GL/glew.h>
2024-11-12 17:08:03 +05:00
#include <SDL3/SDL.h>
2024-12-23 06:02:33 +05:00
#include <SDL3/SDL_opengl.h>
2024-11-12 17:08:03 +05:00
#include <SDL3/SDL_main.h> // only include this one in the source file with main()!
2024-11-25 06:37:08 +05:00
#define INITIAL_FPS 60
2024-11-12 17:08:03 +05:00
SDL_Window* window = NULL;
2024-12-23 06:02:33 +05:00
SDL_GLContext glcontext = NULL;
GLuint program;
GLuint vbo;
2024-11-12 17:08:03 +05:00
2024-11-25 06:37:08 +05:00
static double FPS = INITIAL_FPS;
static double FrameTime = 1.0 / INITIAL_FPS;
static double PerformancePeriod;
2024-12-23 17:02:28 +05:00
static void panicError ( void ) __attribute__((noreturn));
2024-11-12 17:08:03 +05:00
2024-12-23 06:02:33 +05:00
static double GetTime( void )
2024-11-25 06:37:08 +05:00
{
return PerformancePeriod * SDL_GetPerformanceCounter();
}
2024-12-23 06:02:33 +05:00
static void SetTitle ( SDL_Window *window )
2024-11-25 06:37:08 +05:00
{
char title[48] = {0};
2024-12-23 17:02:28 +05:00
SDL_snprintf(title, sizeof(title), "Hello Triangle! Framelimit: %6.3f Hz", FPS);
2024-11-25 06:37:08 +05:00
SDL_SetWindowTitle(window, title);
}
2024-12-23 17:02:28 +05:00
void panicError ( void )
2024-11-12 17:08:03 +05:00
{
2024-12-23 06:02:33 +05:00
SDL_GL_DestroyContext(glcontext);
2024-11-25 06:37:08 +05:00
SDL_DestroyWindow(window);
SDL_Quit();
2024-12-23 17:02:28 +05:00
exit(EXIT_FAILURE);
2024-11-12 17:08:03 +05:00
}
2024-12-23 06:02:33 +05:00
char *readFile ( const char *fileName )
{
SDL_IOStream *ioStream = SDL_IOFromFile(fileName, "rb");
2024-12-23 17:02:28 +05:00
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();
}
2024-12-23 06:02:33 +05:00
long len = SDL_TellIO(ioStream);
2024-12-23 17:02:28 +05:00
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();
}
2024-12-23 06:02:33 +05:00
char *res = SDL_malloc(len + 1);
2024-12-23 17:02:28 +05:00
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();
}
2024-12-23 06:02:33 +05:00
res[len] = 0;
return res;
}
2024-12-23 17:02:28 +05:00
GLuint createShader ( const char *shaderFile, GLenum shaderType )
2024-12-23 06:02:33 +05:00
{
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 {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Unrecognized shader type.");
panicError();
2024-12-23 06:02:33 +05:00
}
GLuint shader = glCreateShader(shaderType);
if (!shader) {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Error create shader type %s.", strShaderType);
panicError();
2024-12-23 06:02:33 +05:00
}
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);
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Filed to compile %s shader:\n%s.", strShaderType, info);
panicError();
2024-12-23 06:02:33 +05:00
}
return shader;
}
2024-12-23 17:02:28 +05:00
void createProgram ( GLuint *shaders, int len )
2024-12-23 06:02:33 +05:00
{
program = glCreateProgram();
if (!program) {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Can't to create shader program.");
panicError();
2024-12-23 06:02:33 +05:00
}
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);
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "Link failed: %s.", info);
panicError();
2024-12-23 06:02:33 +05:00
}
}
2024-12-23 17:02:28 +05:00
void createBuffer ( void )
2024-12-23 06:02:33 +05:00
{
float vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f
};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}
2024-12-23 17:02:28 +05:00
void startShaderProg ( void )
2024-12-23 06:02:33 +05:00
{
2024-12-23 17:02:28 +05:00
createBuffer();
2024-12-23 06:02:33 +05:00
GLuint shaders[] = {
2024-12-23 17:02:28 +05:00
createShader("vertex.glsl", GL_VERTEX_SHADER),
createShader("fragment.glsl", GL_FRAGMENT_SHADER)
2024-12-23 06:02:33 +05:00
};
int len = sizeof(shaders) / sizeof(shaders[0]);
2024-12-23 17:02:28 +05:00
createProgram(shaders, len);
2024-12-23 06:02:33 +05:00
for (int i = 0; i < len; i++) {
glDeleteShader(shaders[i]);
}
}
2024-12-23 17:02:28 +05:00
void _GLBuffer( void )
{
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glUseProgram(0);
}
2024-11-12 17:08:03 +05:00
int main( int argc, char* argv[] )
{
const int WIDTH = 640;
const int HEIGHT = 480;
2024-11-25 06:37:08 +05:00
int delay_threshold = 2;
2024-12-23 17:02:28 +05:00
int r, g, b, GLJ, GLN = 0;
double sleep_time = 0;
2024-11-25 06:37:08 +05:00
double time_counter = 0;
2024-11-12 17:08:03 +05:00
bool loopShouldStop = false;
2024-11-25 06:37:08 +05:00
SDL_SetHint(SDL_HINT_RENDER_VSYNC, 0);
2024-12-23 06:02:33 +05:00
if (!SDL_Init(SDL_INIT_VIDEO)) {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_Init failed: %s.", SDL_GetError());
2024-11-12 17:08:03 +05:00
}
2024-12-23 17:02:28 +05:00
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
2024-12-23 06:02:33 +05:00
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
2024-11-25 06:37:08 +05:00
PerformancePeriod = 1.0 / SDL_GetPerformanceFrequency();
time_counter = GetTime();
2024-12-23 06:02:33 +05:00
window = SDL_CreateWindow("Hello SDL", WIDTH, HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
if (!window) {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_CreateWindow: %s.", SDL_GetError());
panicError();
2024-11-12 17:08:03 +05:00
}
2024-12-23 06:02:33 +05:00
glcontext = SDL_GL_CreateContext(window);
if (!glcontext) {
2024-12-23 17:02:28 +05:00
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_GL_CreateContext: %s.", SDL_GetError());
panicError();
2024-11-12 17:08:03 +05:00
}
2024-11-25 06:37:08 +05:00
SetTitle(window);
SDL_HideCursor();
2024-12-23 17:02:28 +05:00
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK) {
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "glewInit: %s.", glewGetErrorString(err));
panicError();
}
SDL_LogVerbose(SDL_LOG_CATEGORY_RENDER, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
err = SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &GLJ);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &GLN);
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
SDL_Log("%s", SDL_GetError());
SDL_LogVerbose(SDL_LOG_CATEGORY_RENDER, "Red size: %d, Green size: %d, Blue size: %d, OpenGL: %d.%d.", r, g, b, GLJ, GLN);
SDL_GL_SetSwapInterval(0);
startShaderProg();
2024-12-23 06:02:33 +05:00
while (!loopShouldStop) {
2024-11-12 17:08:03 +05:00
SDL_Event e;
SDL_zero(e);
2024-12-23 06:02:33 +05:00
while (SDL_PollEvent(&e)) {
2024-11-25 06:37:08 +05:00
if (e.type == SDL_EVENT_QUIT)
loopShouldStop = true;
2024-12-23 06:02:33 +05:00
else if (e.type == SDL_EVENT_KEY_DOWN) {
if (e.key.key == SDLK_X) {
2024-11-25 06:37:08 +05:00
FPS -= 0.1;
2024-12-23 06:02:33 +05:00
if (FPS < 1) {
2024-11-25 06:37:08 +05:00
FPS = 1;
}
FrameTime = 1.0 / FPS;
SetTitle(window);
}
2024-12-23 06:02:33 +05:00
else if (e.key.key == SDLK_C) {
2024-11-25 06:37:08 +05:00
FPS += 0.1;
FrameTime = 1.0 / FPS;
SetTitle(window);
}
2024-12-23 06:02:33 +05:00
if (e.key.key == SDLK_ESCAPE)
loopShouldStop = true;
2024-11-25 06:37:08 +05:00
}
2024-11-12 17:08:03 +05:00
}
2024-12-23 17:02:28 +05:00
_GLBuffer();
if (!SDL_GL_SwapWindow(window)) {
SDL_LogCritical(SDL_LOG_CATEGORY_ASSERT, "SDL_GL_SwapWwindow: %s.", SDL_GetError());
panicError();
}
2024-11-25 06:37:08 +05:00
sleep_time = time_counter - GetTime();
2024-12-23 06:02:33 +05:00
if (sleep_time * 1000 > delay_threshold) {
2024-11-25 06:37:08 +05:00
Uint32 ms = (Uint32)(sleep_time * 1000) - delay_threshold;
SDL_Delay(ms);
2024-12-23 06:02:33 +05:00
if (time_counter < GetTime()) {
2024-11-25 06:37:08 +05:00
delay_threshold++;
SDL_Log("Slept too long. Increased threshold to %u ms.", delay_threshold);
}
}
while (time_counter > GetTime()) {
2024-12-23 06:02:33 +05:00
/* Waiting for the right moment. */
2024-11-25 06:37:08 +05:00
}
time_counter += FrameTime;
2024-11-12 17:08:03 +05:00
}
2024-12-23 06:02:33 +05:00
2024-11-12 17:08:03 +05:00
SDL_DestroyWindow(window);
2024-12-23 06:02:33 +05:00
SDL_GL_DestroyContext(glcontext);
2024-11-12 17:08:03 +05:00
SDL_Quit();
2024-12-23 17:02:28 +05:00
exit(EXIT_SUCCESS);
2024-11-12 17:08:03 +05:00
}