diff options
author | kdx <kikoodx@paranoici.org> | 2023-12-17 15:03:31 +0100 |
---|---|---|
committer | kdx <kikoodx@paranoici.org> | 2023-12-17 15:04:46 +0100 |
commit | 39ff0a1b8b1eb2fe2dc222c8ba6d76891d5b5b88 (patch) | |
tree | 06fb74d78b38414da69a5d77c4dac7da4c9e088d | |
download | sky-39ff0a1b8b1eb2fe2dc222c8ba6d76891d5b5b88.tar.gz |
initial commit
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | LICENSE | 19 | ||||
-rw-r--r-- | README | 14 | ||||
-rw-r--r-- | Sky.c | 270 | ||||
-rw-r--r-- | Sky.h | 84 | ||||
-rw-r--r-- | demo/main.c | 27 | ||||
-rw-r--r-- | demo/tileset.png | bin | 0 -> 1491 bytes |
7 files changed, 416 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae9f53d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/*.o +/a.out @@ -0,0 +1,19 @@ +Copyright (c) 2023 (: + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. @@ -0,0 +1,14 @@ +Sky +=== + +Framework minimal design pour l'animateur d'à côté. + +Utilisation +----------- + +Lire `Sky.h` et `demo/main.c`. + +Licence +------- + +Voir `LICENSE`. @@ -0,0 +1,270 @@ +/* Licensing informations can be found at the end of the file. */ + +#include "Sky.h" +#include <SDL2/SDL.h> +#include <SDL2/SDL_image.h> +#include <errno.h> +#include <unistd.h> + +static SDL_Window *_window = NULL; +static SDL_Renderer *_renderer = NULL; +static SDL_Texture *_target = NULL; +static SDL_Texture *_tileset = NULL; +static int _dwidth = 1; +static int _dheight = 1; +static int _tile_size = 16; +static int _tileset_width = 0; +static int _tileset_height = 0; +static Uint64 _min_dt = 0; +static Uint64 _next_time = 0; +static bool _should_quit = false; +static long _tick = 0; +static bool _input[KEY_X] = {0}; +static const SDL_Scancode _keymap[][8] = { + { SDL_SCANCODE_LEFT, SDL_SCANCODE_A, 0 }, + { SDL_SCANCODE_RIGHT, SDL_SCANCODE_D, 0 }, + { SDL_SCANCODE_UP, SDL_SCANCODE_W, 0 }, + { SDL_SCANCODE_DOWN, SDL_SCANCODE_S, 0 }, + { SDL_SCANCODE_Z, SDL_SCANCODE_J, 0 }, + { SDL_SCANCODE_X, SDL_SCANCODE_K, 0 } +}; + +static void _SkyDeinit(void) { + if (_tileset != NULL) + SDL_DestroyTexture(_tileset); + if (_target != NULL) + SDL_DestroyTexture(_target); + if (_renderer != NULL) + SDL_DestroyRenderer(_renderer); + if (_window != NULL) + SDL_DestroyWindow(_window); + IMG_Quit(); + SDL_Quit(); +} + +void Init(int fps, int width, int height, const char *tset_path, int tsize) { + if (atexit(_SkyDeinit)) + Panic("atexit failed: %s", strerror(errno)); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) + Panic("%s", SDL_GetError()); + + if (IMG_Init(IMG_INIT_PNG) == 0) + Panic("%s", IMG_GetError()); + + char *const basepath = SDL_GetBasePath(); + if (basepath == NULL) + Panic("%s", SDL_GetError()); + const int chdir_rv = chdir(basepath); + SDL_free(basepath); + if (chdir_rv < 0) + Panic("%s", strerror(errno)); + + _window = SDL_CreateWindow("", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + width, height, SDL_WINDOW_RESIZABLE); + if (_window == NULL) + Panic("%s", SDL_GetError()); + + _renderer = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED); + if (_renderer == NULL) + Panic("%s", SDL_GetError()); + + _target = SDL_CreateTexture(_renderer, SDL_PIXELFORMAT_RGB888, + SDL_TEXTUREACCESS_TARGET, width, height); + if (_target == NULL) + Panic("%s", SDL_GetError()); + + SetFPS(fps); + SetTileset(tset_path, tsize); + _dwidth = width; + _dheight = height; +} + +void SetFPS(int fps) { + if (fps <= 0) + _min_dt = 0; + else { + if (_min_dt == 0) + _next_time = SDL_GetTicks64(); + _min_dt = 1000 / fps; + } +} + +void SetTileset(const char *path, int tile_size) { + Assert(path != NULL); + Assert(tile_size > 0); + + if (_tileset != NULL) + SDL_DestroyTexture(_tileset); + + _tileset = IMG_LoadTexture(_renderer, path); + if (_tileset == NULL) + Panic("%s", IMG_GetError()); + + if (SDL_QueryTexture(_tileset, NULL, NULL, + &_tileset_width, &_tileset_height) < 0) + Panic("%s", SDL_GetError()); + + _tile_size = tile_size; + _tileset_width /= _tile_size; + _tileset_height /= _tile_size; + + if (SDL_SetRenderTarget(_renderer, _target) < 0) + Panic("%s", SDL_GetError()); +} + +void SetTitle(const char *title) { + SDL_SetWindowTitle(_window, title); +} + +bool ShouldQuit(void) { + return _should_quit; +} + +long Tick(void) { + return _tick; +} + +bool Keydown(unsigned key) { + Assert(key <= KEY_X); + return _input[key]; +} + +void DrawUpdate(void) { + if (SDL_SetRenderTarget(_renderer, NULL) < 0) + Panic("%s", SDL_GetError()); + + DrawColor(0, 0, 0); + DrawClear(); + + int win_w, win_h; + SDL_GetWindowSize(_window, &win_w, &win_h); + const float ratio_w = (float)win_w / _dwidth; + const float ratio_h = (float)win_h / _dheight; + float scale = (ratio_w < ratio_h) ? ratio_w : ratio_h; + if (scale > 1.0) + scale = (int)scale; + + const SDL_Rect dst = { + (win_w - _dwidth * scale) / 2, + (win_h - _dheight * scale) / 2, + _dwidth * scale, + _dheight * scale + }; + if (SDL_RenderCopy(_renderer, _target, NULL, &dst) < 0) + Panic("%s", SDL_GetError()); + + /* Limit frames per second. */ + if (_min_dt) { + const Uint64 cur_time = SDL_GetTicks64(); + if (_next_time + _min_dt <= cur_time) + _next_time = cur_time; + else + SDL_Delay(_next_time + _min_dt - cur_time); + } + + SDL_RenderPresent(_renderer); + + if (SDL_SetRenderTarget(_renderer, _target) < 0) + Panic("%s", SDL_GetError()); + + /* Cycle events. */ + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + _should_quit = true; + break; + case SDL_KEYDOWN: + if (e.key.repeat) + break; + /* fallthrough */ + case SDL_KEYUP: + for (int i = 0; i < KEY_X; i++) { + for (int k = 0; _keymap[i][k]; k++) { + const SDL_Scancode sc = _keymap[i][k]; + if (sc == e.key.keysym.scancode) { + _input[i] = + (e.type == SDL_KEYDOWN); + break; + } + } + } + break; + default: + break; + } + } + + _tick += 1; +} + +void DrawColor(float r, float g, float b) { + if (SDL_SetRenderDrawColor(_renderer, r*255, g*255, b*255, 255) < 0) + PWarn("%s", SDL_GetError()); +} + +void DrawClear(void) { + if (SDL_RenderClear(_renderer) < 0) + PWarn("%s", SDL_GetError()); +} + +void DrawPoint(int x, int y) { + if (SDL_RenderDrawPoint(_renderer, x, y) < 0) + PWarn("%s", SDL_GetError()); +} + +void DrawRect(int x, int y, int w, int h, bool fill) { + const SDL_Rect rect = { x, y, w + (w == 0), h + (h == 0) }; + if (fill) { + if (SDL_RenderFillRect(_renderer, &rect) < 0) + PWarn("%s", SDL_GetError()); + } else { + if (SDL_RenderDrawRect(_renderer, &rect) < 0) + PWarn("%s", SDL_GetError()); + } +} + +void DrawLine(int x1, int y1, int x2, int y2) { + if (SDL_RenderDrawLine(_renderer, x1, y1, x2, y2) < 0) + PWarn("%s", SDL_GetError()); +} + +void DrawTile(int id, int x, int y) { + Assert(id < _tileset_width * _tileset_height); + + const SDL_Rect src = { + id % _tileset_width * _tile_size, + id / _tileset_width * _tile_size, + _tile_size, + _tile_size + }; + const SDL_Rect dst = { x, y, _tile_size, _tile_size }; + + if (SDL_RenderCopy(_renderer, _tileset, &src, &dst) < 0) + PWarn("%s", SDL_GetError()); +} + +/* + * Copyright (c) 2023 (: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ @@ -0,0 +1,84 @@ +/* Licensing informations can be found at the end of the file. */ + +#pragma once +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +/* INITIALIZATION + * Call this function exactly once to initalize your project. + * Deinitialization is taken care of for you. + * You don't need to worry about failure either, Panic will be used. */ +void Init(int fps, int width, int height, const char *tset_path, int tsize); + +/* CONFIGURATION + * These functions can be called any number of time during runtime. */ +void SetFPS(int fps); +void SetTileset(const char *path, int tile_size); +void SetTitle(const char *title); + +/* SYSTEM */ +bool ShouldQuit(void); +long Tick(void); + +/* INPUT */ +enum { + KEY_LEFT, + KEY_RIGHT, + KEY_UP, + KEY_DOWN, + KEY_O, + KEY_X +}; +bool Keydown(unsigned key); + +/* DRAW + * Call DrawUpdate after all your draw calls to refresh the screen. */ +void DrawUpdate(void); +void DrawColor(float r, float g, float b); +void DrawClear(void); +void DrawPoint(int x, int y); +void DrawRect(int x, int y, int w, int h, bool fill); +void DrawLine(int x1, int y1, int x2, int y2); +void DrawTile(int id, int x, int y); + +/* MACRO SECTION + * Panic prints an error message and crashes the game. + * Assert calls panic if given expression is false. + * Alloc is a wrapper around calloc that calls Panic on allocation failure. */ +#define STR(X) #X +#define PGeneric(PREFIX, ...) fprintf(stderr, \ + "\x1b[" PREFIX " %s:%s:%d\x1b[0m \t", \ + __FILE_NAME__, __FUNCTION__, __LINE__), \ + fprintf(stderr, __VA_ARGS__), fputc('\n', stderr) +#define PLog(...) PGeneric("94mLOG", __VA_ARGS__) +#define PErr(...) PGeneric("91mERR", __VA_ARGS__) +#define PWarn(...) PGeneric("93mWRN", __VA_ARGS__) +#define Panic(...) PErr(__VA_ARGS__), exit(EXIT_FAILURE) +#define Assert(X) if (!(X)) Panic("assert failed: " STR(X)) +#define Alloc(X) ({ void *___ptr = calloc((X), 1); \ + if (___ptr == NULL) \ + perr("calloc failed: %s", strerror(errno)); \ + ___ptr; }) + +/* + * Copyright (c) 2023 (: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ diff --git a/demo/main.c b/demo/main.c new file mode 100644 index 0000000..cd73aa8 --- /dev/null +++ b/demo/main.c @@ -0,0 +1,27 @@ +/* build with + * $ gcc Sky.c demo/main.c -lSDL2 -lSDL2_image */ + +#include "../Sky.h" + +int main(int argc, char **argv) { + Init(60, 400, 224, "demo/tileset.png", 16); + SetTitle("Sky DEMO"); + + int x = 0, y = 0; + + while (!ShouldQuit()) { + x += Keydown(KEY_RIGHT); + x -= Keydown(KEY_LEFT); + y += Keydown(KEY_DOWN); + y -= Keydown(KEY_UP); + + DrawColor(0, 0, 1); + DrawClear(); + DrawTile(Tick() % 16, Tick() % 400, Tick() % 224); + DrawTile(2, (Tick() + 200) % 400, 223 - (Tick() + 112) % 224); + DrawTile(18, x, y); + DrawUpdate(); + } + + return 0; +} diff --git a/demo/tileset.png b/demo/tileset.png Binary files differnew file mode 100644 index 0000000..ea428d6 --- /dev/null +++ b/demo/tileset.png |