Last active
October 15, 2023 07:11
-
-
Save t-mat/2d77ee3813945ffd59ea95c56ead98cc to your computer and use it in GitHub Desktop.
My SDL2 template
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
// My template code for SDL2. Press ESC to exit. | |
// Copyright (C) 2021, Takayuki Matsuoka. | |
// SPDX-License-Identifier: CC0-1.0 | |
#include <vector> | |
#define SDL_MAIN_HANDLED | |
#include <SDL.h> | |
#if defined(_MSC_VER) | |
//#pragma comment(lib, "SDL2.lib") | |
#pragma comment(lib, "SDL2-static.lib") | |
#pragma comment(lib, "winmm.lib") | |
#pragma comment(lib, "Version.lib") | |
#pragma comment(lib, "imm32.lib") | |
#pragma comment(lib, "Setupapi.lib") | |
#endif | |
std::vector<uint8_t> loadFile(const char* filename) { | |
std::vector<uint8_t> file; | |
if(SDL_RWops* rw = SDL_RWFromFile(filename, "rb")) { | |
file.resize(SDL_RWsize(rw)); | |
SDL_RWread(rw, file.data(), 1, file.size()); | |
SDL_RWclose(rw); | |
} | |
return file; | |
} | |
struct GameControllers : std::vector<SDL_GameController*> { | |
GameControllers() { | |
for(int i = 0, n = SDL_NumJoysticks(); i < n; ++i) { | |
auto* g = SDL_GameControllerOpen(i); | |
if(g) { push_back(g); } | |
} | |
} | |
}; | |
struct Screen : std::vector<uint32_t> { | |
Screen(int w, int h) : width{w}, height{h} { resize(w * h); } | |
void setPixel(int x, int y, int r, int g, int b) { | |
if(x < 0 || x >= width || y < 0 || y >= height) { return; } | |
const uint32_t c = ((r & 0xff) << 24) | ((g & 0xff) << 16) | ((b & 0xff) << 8); | |
(*this)[y * width + x] = c; | |
} | |
int width = 0; | |
int height = 0; | |
}; | |
// | |
bool update(uint64_t microsecondsSinceStartup, Screen& screen, const uint8_t* sdlKeyboardState, GameControllers& gameControllers) { | |
double secondsSinceStartup = microsecondsSinceStartup * (1.0 / 1000 / 1000); | |
const int t = (int) secondsSinceStartup; | |
for(int y = 0; y < screen.height; y++) { | |
for(int x = 0; x < screen.width; x++) { | |
const int c = (1 + t + y / 32 + x / 32) % 8; | |
int r = ((c>>0) & 1) * 0xff; | |
int g = ((c>>1) & 1) * 0xff; | |
int b = ((c>>2) & 1) * 0xff; | |
screen.setPixel(x, y, r, g, b); | |
} | |
} | |
if(sdlKeyboardState[SDL_SCANCODE_ESCAPE] != 0) { | |
return false; | |
} | |
return true; | |
} | |
int main(int argc, const char* argv[]) { | |
uint32_t sdlInitFlag = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK; | |
const int width = 320; // in pixels | |
const int height = 240; // in pixels | |
const int scale = 4; // magnifier | |
const int FrameRate = 60; // frames / sec | |
if(SDL_Init(sdlInitFlag) < 0) { | |
return SDL_Log("FAIL: SDL_Init() - %s\n", SDL_GetError()), EXIT_FAILURE; | |
} | |
SDL_Window* window = SDL_CreateWindow("My app", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | |
width*scale, height*scale, SDL_WINDOW_SHOWN); | |
if(! window) { | |
return SDL_Log("FAIL: SDL_CreateWindow() - %s\n", SDL_GetError()), EXIT_FAILURE; | |
} | |
SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBX8888); | |
GameControllers gameControllers; | |
Screen screen(width, height); | |
const uint64_t pcOrig = SDL_GetPerformanceCounter(); | |
const uint64_t pcFreq = SDL_GetPerformanceFrequency(); | |
uint64_t pcPrev = SDL_GetPerformanceCounter(); | |
for(bool running = true; running; ) { | |
for(SDL_Event e; SDL_PollEvent(&e); ) { | |
running &= (e.type != SDL_QUIT); | |
} | |
{ // Update app logic | |
const uint64_t microsecondsSinceStartup = (SDL_GetPerformanceCounter() - pcOrig) * 1000000 / pcFreq; | |
const uint8_t* keyboardState = SDL_GetKeyboardState(nullptr); | |
running &= update(microsecondsSinceStartup, screen, keyboardState, gameControllers); | |
} | |
{ // Copy screen to the surface | |
SDL_LockSurface(surface); | |
for(int y = 0; y < height; ++y) { | |
auto* dst = reinterpret_cast<uint32_t*>(surface->pixels) + y * width; | |
for(int x = 0; x < width; ++x) { | |
dst[x] = screen[y * width + x]; | |
} | |
} | |
SDL_UnlockSurface(surface); | |
SDL_BlitScaled(surface, nullptr, SDL_GetWindowSurface(window), nullptr); | |
} | |
{ // Delay for constant frame rate | |
const uint64_t pcNext = pcPrev + pcFreq / FrameRate; | |
const int64_t pcDiff = pcNext - SDL_GetPerformanceCounter(); | |
if(pcDiff > 0) { | |
SDL_Delay(static_cast<uint32_t>((pcDiff * 1000) / pcFreq)); | |
} | |
pcPrev = SDL_GetPerformanceCounter(); | |
} | |
SDL_UpdateWindowSurface(window); | |
} | |
SDL_FreeSurface(surface); | |
SDL_DestroyWindow(window); | |
SDL_Quit(); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment