From 659df362a4297bdf570486a1fb6ce8fe475b5447 Mon Sep 17 00:00:00 2001 From: Quinn <99677023+thepigeongenerator@users.noreply.github.com> Date: Thu, 12 Sep 2024 00:20:27 +0200 Subject: [PATCH] added some files --- .gitignore | 2 + assets/uwu | 1 + build.sh | 65 ++++++++++++++++++++++++ src/errors.c | 32 ++++++++++++ src/errors.h | 25 ++++++++++ src/game/game.c | 11 +++++ src/game/game.h | 9 ++++ src/main.c | 78 +++++++++++++++++++++++++++++ src/main.h | 4 ++ src/window/audio.c | 112 ++++++++++++++++++++++++++++++++++++++++++ src/window/audio.h | 21 ++++++++ src/window/renderer.c | 44 +++++++++++++++++ src/window/renderer.h | 10 ++++ 13 files changed, 414 insertions(+) create mode 100644 .gitignore create mode 100644 assets/uwu create mode 100755 build.sh create mode 100644 src/errors.c create mode 100644 src/errors.h create mode 100644 src/game/game.c create mode 100644 src/game/game.h create mode 100644 src/main.c create mode 100644 src/main.h create mode 100644 src/window/audio.c create mode 100644 src/window/audio.h create mode 100644 src/window/renderer.c create mode 100644 src/window/renderer.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a8bc10 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +build \ No newline at end of file diff --git a/assets/uwu b/assets/uwu new file mode 100644 index 0000000..e108e50 --- /dev/null +++ b/assets/uwu @@ -0,0 +1 @@ +uwu diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..a53c019 --- /dev/null +++ b/build.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# define variables +PROJECT_NAME=${PWD##*/} +BUILD_DIR="./build" +INCLUDE_IN_BUILD="./assets" + +# compilation targets +args_linux86_64() +{ + ARCHITECTURE="linux-86_64" + COMPILER="/bin/gcc" + ARGS="-lSDL2" + FILE_EXSTENSION="" +} + +args_win86-64() +{ + ARCHITECTURE="win-86_64" + COMPILER="/usr/bin/x86_64-w64-mingw32-gcc" + ARGS="-lmingw32 -lSDL2main -lSDL2 -mwindows" + INCLUDE_IN_BUILD="$INCLUDE_IN_BUILD /usr/x86_64-w64-mingw32/bin/SDL2.dll" + FILE_EXSTENSION=".exe" +} + +args_emscripten() +{ + ARCHITECTURE="web" + COMPILER="/home/user/.local/bin/emcc" + ARGS="-s USE_SDL=2" + FILE_EXSTENSION=".html" +} + +# handle arguments +if [ "$1" = "linux86_64" ]; then args_linux86_64 +elif [ "$1" = "win86_64" ]; then args_win86-64 +elif [ "$1" = "web" ]; then args_emscripten +else echo -e "\033[91mdidn't include any arguments! D:\033[0m" && exit -1 +fi + +# check whether $BUILD_DIR or $ARCHITECTURE isn't set +if [[ -z $BUILD_DIR ]] || [[ -z "$ARCHITECTURE" ]]; then + echo -e "\033[91mBUILD_DIR or ARCHITECTURE not set D:\033[0m" + exit -1 +fi + + +# make (and clear) the build directory +mkdir $BUILD_DIR $BUILD_DIR/$ARCHITECTURE +rm -rf $BUILD_DIR/$ARCHITECTURE/* + +# copy included files or directories to the build directory +if [[ ! -z $INCLUDE_IN_BUILD ]]; then + cp -r $INCLUDE_IN_BUILD $BUILD_DIR/$ARCHITECTURE +fi + +# get the executable path +EXE_PATH=$BUILD_DIR/$ARCHITECTURE/$PROJECT_NAME$FILE_EXSTENSION +echo "building at: $EXE_PATH" + +# compile the code +COMMAND="$COMPILER `find ./src -name *.c` -o $EXE_PATH -Wall -g -lm $ARGS" +echo "using command: $COMMAND" +$COMMAND +exit $? diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 0000000..fa7d860 --- /dev/null +++ b/src/errors.c @@ -0,0 +1,32 @@ +#include "errors.h" + +#include +#include +#include + +#define MAX_STR_LEN 128 + +void error(const ErrorCode error_code, const char* format, ...) { + char buffer[MAX_STR_LEN] = {0}; // contains the buffer of the final string + + va_list args = {0}; + va_start(args, format); + vsnprintf(buffer, MAX_STR_LEN, format, args); + va_end(args); + + printf("\033[91mE\033[0m: %s\n", buffer); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "something went wrong! :O", buffer, NULL); + + exit(error_code); +} + +void warn(const char* format, ...) { + char buffer[MAX_STR_LEN] = {0}; // contains the buffer of the final string + + va_list args = {0}; + va_start(args, format); + vsnprintf(buffer, MAX_STR_LEN, format, args); + va_end(args); + + printf("\033[93mW\033[0m: %s\n", buffer); +} diff --git a/src/errors.h b/src/errors.h new file mode 100644 index 0000000..07f1613 --- /dev/null +++ b/src/errors.h @@ -0,0 +1,25 @@ +#pragma once + +typedef unsigned char ErrorCode; +enum { + ERROR_MISC = -1, + + SUCCESS = 0, + ERROR_INIT = 1, + + // SDL errors + ERROR_SDL = 2, + ERROR_SDL_INIT = ERROR_SDL | ERROR_INIT, + + // renderer errors + ERROR_SDL_RENDERER = ERROR_SDL | 4, + ERROR_SDL_RENDERER_INIT = ERROR_SDL_RENDERER | ERROR_INIT, + + // audio errors + ERROR_SDL_AUDIO = ERROR_SDL | 8, + ERROR_SDL_AUDIO_INIT = ERROR_SDL_AUDIO | ERROR_INIT, +}; + +// call when a fatal error has occurred, the program will immediately terminate when called +void error(const ErrorCode error_code, const char* format, ...); +void warn(const char* format, ...); diff --git a/src/game/game.c b/src/game/game.c new file mode 100644 index 0000000..7770ffd --- /dev/null +++ b/src/game/game.c @@ -0,0 +1,11 @@ +#include "game.h" + +#include "../main.h" + + +// called every time the game's state is updated +void game_update(GameData game_data, const Uint8* keys) { + if (keys[SDL_SCANCODE_ESCAPE]) { + stop(); + } +} diff --git a/src/game/game.h b/src/game/game.h new file mode 100644 index 0000000..0689c8b --- /dev/null +++ b/src/game/game.h @@ -0,0 +1,9 @@ +#pragma once +#include + +// stores the data used in the game +typedef struct { +} GameData; + +// updates the game's state +void game_update(GameData game_data, const Uint8* keys); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..6262a5e --- /dev/null +++ b/src/main.c @@ -0,0 +1,78 @@ +#include "main.h" + +#include +#include +#include +#include + +#include "errors.h" +#include "game/game.h" +#include "window/audio.h" +#include "window/renderer.h" + +#ifdef __EMSCRIPTEN__ // for web builds +#include +#endif + + +bool playing = true; + +SDL_Window* window = NULL; +SDL_Renderer* renderer = NULL; + +// handles game application initialisation +static void init(void) { + // initialize SDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { + error(ERROR_SDL_INIT, "SDL could not initialize! SDL Error: %s", SDL_GetError()); + return; + } + + // initialize the renderer + if (renderer_init(&window, &renderer) < 0) { + error(ERROR_SDL_RENDERER_INIT, SDL_GetError()); + return; + } + + // initialize audio + AudioDevice* audio_device = audio_device_init(32000, AUDIO_S16, 1, 4096); + //AudioData audio1 = audio_load_wav(audio_device, "FILE MANE"); +} + +// handles game application updating +static void update(void) { + // update the input + { + SDL_Event e; + while (SDL_PollEvent(&e)) { + switch (e.type) { + case SDL_QUIT: + exit(SUCCESS); + break; + } + } + } + + // preform updates + game_update((GameData){}, SDL_GetKeyboardState(NULL)); + renderer_update(&(RenderData){ + window, renderer}); +} + +// handles game application quitting +void stop(void) { + playing = false; +} + +// entry point of the application +int main(int argc, char** argv) { + init(); + + while (playing) + update(); + + // cleanup of resources + SDL_Quit(); + + return 0; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..1369892 --- /dev/null +++ b/src/main.h @@ -0,0 +1,4 @@ +#pragma once + +// stops execution of the game +void stop(void); diff --git a/src/window/audio.c b/src/window/audio.c new file mode 100644 index 0000000..9791118 --- /dev/null +++ b/src/window/audio.c @@ -0,0 +1,112 @@ +#include "audio.h" + +#include + +#include "../errors.h" + +// the maximum amount of sounds that can play at once +#define MAX_SOUNDS 64 + +typedef struct { + AudioData* playing_audio; + AudioDevice audio_device; +} AudioCallbackData; + +// audio callback from SDL_AudioSpec; called when the audio device needs more data +static void audio_mixer(void* userdata, Uint8* stream, int len) { + memset(stream, 0, len); // clear the playing audio + AudioDevice* device = userdata; // get the callback data + AudioData* audio = device->playing_audio; + + for (int i = 0; i < MAX_SOUNDS; i++) { + // skip if the audio doesn't conain any further data + if (audio[i].length <= 0) { + continue; + } + + // get the length of which we shall be mixing + Uint32 mix_length = SDL_min(audio[i].length, len); + + // mix the audio with the stream + SDL_MixAudioFormat(stream, audio[i].buffer, device->format, mix_length, SDL_MIX_MAXVOLUME); + audio[i].buffer += mix_length; // move the pointer up a a bit + audio[i].length -= mix_length; // move up the mixed amount + } +} + +// converts the audio to the format of the audio device +static void convert_audio(const AudioDevice* audio_device, const SDL_AudioSpec wav_spec, Uint8** wav_buffer, Uint32* wav_length) { + // build the audio converter with the audio given + SDL_AudioCVT cvt = {0}; + SDL_BuildAudioCVT(&cvt, wav_spec.format, wav_spec.channels, wav_spec.freq, audio_device->format, audio_device->channels, audio_device->freq); + + cvt.len = (*wav_length) * wav_spec.channels; // the buffer length + cvt.buf = (Uint8*)SDL_malloc(cvt.len * cvt.len_mult); // allocate size for the new buffer + memcpy(cvt.buf, *wav_buffer, *wav_length); // copy wav data to cvt buffer; + + // convert + SDL_ConvertAudio(&cvt); + + // output + *wav_length = cvt.len_cvt; // set the length to the new length + memcpy(*wav_buffer, cvt.buf, cvt.len_cvt); // copy converted cvt buffer back to wav buffer + + free(cvt.buf); // free the memory allocated to the cvt buffer +} + +// loads a WAV file and returns the relevant information +AudioData audio_load_wav(const AudioDevice* audio_device, const char* file_path) { + SDL_AudioSpec wav_spec = {0}; + AudioData audio = {0}; + + SDL_LoadWAV(file_path, &wav_spec, &audio.buffer, &audio.length); + convert_audio(audio_device, wav_spec, &audio.buffer, &audio.length); + audio.mixed_amount = audio.length; + + return audio; +} + +// initializes the audio device +AudioDevice* audio_device_init(const int freq, const SDL_AudioFormat format, const Uint8 channels, const Uint16 samples) { + // allocate memory for the audio device + AudioDevice* audio_device = malloc(sizeof(AudioDevice)); + + // define the audio specification + SDL_AudioSpec spec = {freq, format, channels, samples}; + spec.callback = audio_mixer; + spec.userdata = audio_device; + + // create the audio device + *audio_device = (AudioDevice){ + SDL_OpenAudioDevice(NULL, 0, &spec, NULL, 0), + freq, + format, + channels, + calloc(MAX_SOUNDS, sizeof(AudioData)), // allocate memory on the heap for the playing audio array + }; + + // if the audio device isn't set, cause an error + if (audio_device->id < 1) { + error(ERROR_SDL_AUDIO_INIT, "AudioDivice failed to open! SDL Error: %s", SDL_GetError()); + return NULL; + } + + // default state of the device is paused, so we unpause it here + SDL_PauseAudioDevice(audio_device->id, 0); + return audio_device; +} + +// plays the audio +void audio_play(const AudioDevice* audio_device, const AudioData audio) { + AudioData* playing_audio = audio_device->playing_audio; + + for (int i = 0; i < MAX_SOUNDS; i++) { + // overrite audio that has been deallocated + if (playing_audio[i].length <= 0) { + + // override the audio + playing_audio[i] = audio; + break; // don't continue. :3 + } + } +} diff --git a/src/window/audio.h b/src/window/audio.h new file mode 100644 index 0000000..bd54743 --- /dev/null +++ b/src/window/audio.h @@ -0,0 +1,21 @@ +#pragma once +#include + +typedef struct { + Uint32 length; + Uint32 mixed_amount; + Uint8* buffer; +} AudioData; + +typedef struct { + SDL_AudioDeviceID id; + int freq; + SDL_AudioFormat format; + Uint8 channels; + AudioData* playing_audio; +} AudioDevice; + + +AudioData audio_load_wav(const AudioDevice* audio_device, const char* file_path); +AudioDevice* audio_device_init(const int freq, const SDL_AudioFormat format, const Uint8 channels, const Uint16 samples); +void audio_play(const AudioDevice* audio_device, const AudioData audio); diff --git a/src/window/renderer.c b/src/window/renderer.c new file mode 100644 index 0000000..8ba1333 --- /dev/null +++ b/src/window/renderer.c @@ -0,0 +1,44 @@ +// initializes the window and renderer +#include "renderer.h" + +#include +#include + +#include "../errors.h" +#include "../main.h" + + +int renderer_init(SDL_Window** window, SDL_Renderer** renderer) { + // create a new window + *window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, SDL_WINDOW_SHOWN); + if (*window == NULL) { + error(ERROR_SDL_RENDERER_INIT, "Window failed to be created! SDL Error: %s", SDL_GetError()); + return -1; + } + + // create a renderer + *renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_PRESENTVSYNC); + if (*renderer == NULL) { + error(ERROR_SDL_RENDERER_INIT, "Renderer failed to be created! SDL Error: %s", SDL_GetError()); + return -1; + } + + return 0; +} + +void renderer_update(const RenderData* render_data) { + SDL_Renderer* renderer = render_data->renderer; + + int success = 0; // if an error occurs, this value is <0 + + // clear render + success |= SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x50); + success |= SDL_RenderClear(renderer); + + if (success < 0) { + warn("\033[93mW\033[0m: something went wrong whilst renderering! SDL Error: %s\n", SDL_GetError()); + return; + } + + SDL_RenderPresent(renderer); +} diff --git a/src/window/renderer.h b/src/window/renderer.h new file mode 100644 index 0000000..60a636b --- /dev/null +++ b/src/window/renderer.h @@ -0,0 +1,10 @@ +#pragma once +#include + +typedef struct { + SDL_Window* window; + SDL_Renderer* renderer; +} RenderData; + +int renderer_init(SDL_Window** window, SDL_Renderer** renderer); +void renderer_update(const RenderData* render_data);