microwerx icon

Engine Template #1

microwerx | PRO | 04/29/23 05:38:54 PM UTC | 0 ⭐ | 1109 👁️ | Never ⏰ | []
C |

4.71 KB

|

Source Code

|

0 👍

/

0 👎

/**
 * Copyright (c) 2023 Jonathan Metzgar
 *
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
 
#include "object.h"
 
#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
 
void LogSDLError()
{
    fprintf(stderr, "Error: %s\n", SDL_GetError());
}
 
/////// Game Engine //////
 
typedef struct GameEngine
{
    Object_t self;
    SDL_Window *window;
    int frameCount;
    double previousTime;
    double currentTime;
    double deltaTime;
    int width;
    int height;
    bool finished;
} GameEngine;
 
typedef GameEngine *GameEnginePtr;
 
GameEnginePtr CreateGameEngine()
{
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
    {
        LogSDLError();
        return NULL;
    }
 
    const int windowWidth = 1280;
    const int windowHeight = 720;
 
    // Tell SDL2 to make a window with an OpenGL context.
    SDL_WindowFlags windowFlags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
    SDL_Window *window = SDL_CreateWindow("Game Engine",
                                          SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                          windowWidth, windowHeight, windowFlags);
    if (window == NULL)
    {
        LogSDLError();
        return NULL;
    }
 
    // Tell SDL2 what to have in the OpenGL context.
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
    // SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
 
    SDL_GLContext glContext = SDL_GL_CreateContext(window);
    if (glContext == NULL)
    {
        LogSDLError();
        return NULL;
    }
 
    // Enable vsync on the display.
    SDL_GL_SetSwapInterval(1);
    SDL_GL_MakeCurrent(window, glContext);
 
    GameEnginePtr engine = (GameEnginePtr)allocObject(sizeof(GameEngine));
 
    engine->window = window;
    engine->width = windowWidth;
    engine->height = windowHeight;
    engine->currentTime = SDL_GetTicks64() / 1000.0;
 
    return engine;
}
 
void EngineStartFrame(GameEnginePtr engine)
{
    engine->previousTime = engine->currentTime;
    engine->currentTime = SDL_GetTicks64() / 1000.0;
    engine->deltaTime = engine->currentTime - engine->previousTime;
    engine->frameCount++;
}
 
void EnginePollEvents(GameEnginePtr engine)
{
    // Process all events for the current frame.
    SDL_Event e;
    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_KEYDOWN)
        {
            if (e.key.keysym.sym == SDLK_ESCAPE)
                engine->finished = true;
        }
 
        else if (e.type == SDL_WINDOWEVENT)
        {
            if (e.window.event == SDL_WINDOWEVENT_RESIZED)
            {
                engine->width = e.window.data1;
                engine->height = e.window.data2;
            }
        }
 
        else if (e.type == SDL_QUIT)
        {
            engine->finished = true;
        }
 
        else
        {
            // This is an unhandled event.
        }
    }
}
 
void EngineTick(GameEnginePtr engine)
{
}
 
void EngineDraw(GameEnginePtr engine)
{
    // Set up OpenGL drawing commands.
    glViewport(0, 0, engine->width, engine->height);
 
    double s = sin(engine->currentTime) * 0.5 + 0.5;
    glClearColor(0.1, s, 0.3, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
 
    glBegin(GL_TRIANGLES);
    glVertex2f(-0.5f, -0.5f);
    glVertex2f(0.5f, -0.5f);
    glVertex2f(0.0f, 0.5f);
    glEnd();
}
 
void EngineEndFrame(GameEnginePtr engine)
{
    SDL_GL_SwapWindow(engine->window);
}
 
int main(int argc, char **argv)
{
    GameEnginePtr engine = CreateGameEngine();
    if (engine == NULL)
    {
        return -1;
    }
 
    // Start the game loop.
    while (!engine->finished)
    {
        EngineStartFrame(engine);
        EnginePollEvents(engine);
 
        // Leave the loop if we're done.
        if (engine->finished)
            break;
 
        EngineTick(engine);
        EngineDraw(engine);
        EngineEndFrame(engine);
    }
 
    releaseObject((ObjectPtr)engine);
    return 0;
}
 

Comments