From 7c2282fb9e9b93b2f6514d71f1144a53d6e413b4 Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Tue, 9 Mar 2021 14:41:16 +0200 Subject: [PATCH] implement keyboard functionality and sound, write readme --- .gitignore | 11 + .vscode/launch.json | 2 +- CMakeLists.txt | 9 +- README.md | 12 + beep.mp3 | Bin 0 -> 9244 bytes chip8.h | 5 + main.cpp | 188 +++++++++++-- sdl2_cmake_files/FindSDL2.cmake | 388 ++++++++++++++++++++++++++ sdl2_cmake_files/FindSDL2_mixer.cmake | 220 +++++++++++++++ 9 files changed, 804 insertions(+), 31 deletions(-) create mode 100644 README.md create mode 100644 beep.mp3 create mode 100644 sdl2_cmake_files/FindSDL2.cmake create mode 100644 sdl2_cmake_files/FindSDL2_mixer.cmake diff --git a/.gitignore b/.gitignore index e44be4d..23c9639 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,13 @@ roms/ + +# makefile Makefile + +# cmake files +CMakeFiles +cmake_install.cmake +CMakeCache.txt + +# binary and debug binary +chip8 +chip8debug \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 695452c..f4d7b61 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/chip8debug", - "args": ["IBM Logo.ch8"], + "args": ["./roms/Pong.ch8"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], diff --git a/CMakeLists.txt b/CMakeLists.txt index 1568d5c..bbe8964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.16) project(chip8 VERSION 0.1) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/sdl2_cmake_files) + set(CMAKE_CXX_STANDARD 11) set(CMAKE_CSS_STANDARD_REQUIRED True) set(CMAKE_DEBUG_POSTFIX debug) @@ -9,8 +11,11 @@ set(CMAKE_DEBUG_POSTFIX debug) add_executable(chip8 main.cpp) set_target_properties(chip8 PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) -find_package(sdl2 REQUIRED) -target_link_libraries(chip8 SDL2) +find_package(SDL2 REQUIRED) +target_link_libraries(chip8 SDL2::Core) + +find_package(SDL2_mixer REQUIRED) +target_link_libraries(chip8 SDL2::Mixer) configure_file(version.h.in version.h) diff --git a/README.md b/README.md new file mode 100644 index 0000000..ad15778 --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# chip-m8 +Basic Chip-8 emulator written in C++ using SDL2 as the graphics and sound library. + +# Building +You will need both the SDL2 development and SDL2 Mixer libraries installed on your machine (consult your OS). + + +Run cmake in the repository directory and then run `make` if you're on linux or build with Visual Studio if you're on Windows. +I only tested with linux, so no guarantees a visual studio project will be built with cmake + +# License +Licensed under the MIT license. \ No newline at end of file diff --git a/beep.mp3 b/beep.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a6853a7d99d049ce172e500abcc4203c05c8a713 GIT binary patch literal 9244 zcmeI0XHXPfx3(JwktiTY4uj+lQ zB65aad{(@KENlrW3}lZNbB@1`{n2YfEpf9q1ct|QSG@=OO^BQphyVpy!?>w#;Mm)^ z;a6d?7r^tin0!D1xPe2U_zI_poE|6n`5N{&cJW;hj>6%R3eFplJ*fAbn1NW2T~kpS z@F9tPiv8cnB`HEPON*?*6DcFs6!ghSr15b8@H0FT`rBxw`tUDG0n2SxB$B71B_=v6TLyN$HReLJCR?G2`?1D<#H*v5M&{cSKU#0DbS&?QwC+ zccs@+s=IcDMm%=3+O^k&9ASJrEVelx$#HjT4%(ZFaPI}jW{X9VcdcL^;zyW9AZmPU zcxg>J^8(W(S}h9vgCC6TOgc@vtBd%SPc@$q;nIg13E~uGcC;D))Tfv=R(S@{)0l04 zS$|P7Ds~XDo7witjlKBFKJkW9bQ0fxniljQf3ev0=Ar2jLn{Up zM^(@N%dJV#AUPUT1!4?U{J}a2nOdnHtivvkQWSei3yg__c5;QRQaJDPPL;Q)+@5&K zHA*wV+ZI= zjkq&M4vw>Wn19!xli1-VcBJWU=VjXbNfdI% zkzx3v0TuXu>NgZ0NOl&E&?d}epT z%Q}ko)1!W+E0z{XxDLD2#67}CDuaFB@#w@VtI={N1g{!6-6YH#HFzWsE~!!U15G8u zA&#W}59jJm-KkUdlXSQ!N`+`!<^nKAMg9KOYKWt`?c{Tw_C84wyN*oz!FMr%6s=>#59Hu+9wr_uGHR|=k5t=eZdT2Mr zyqxw#_@mwkH$KF-8nT=GreAhxPhTx!nq5nUbRbtV=hhL7wgrtq$!HvnVYa}?0SfKFyr(8U`Vo1YGjU7?yG)(^I zjmdx-&uc;u7*(uUaGeu8)mKum6)xVD@k_1{b?zRx&<1`zo2n6~AzVh9MT4mCtzY_d z0KjkJn{a2eN9s1L9P>ZY@Ab*cBwEE2UL$a^73mf6jx)&&b%Mfm`3Gsly_SV@+0&WY@32N>4@ z(|J2(jO5fmwaLJ<#Y?SiH(diEYT>`DakQUF>9o`!BOqCl`FWG-5fC;_@JzWb{a#Yb-+)WSs}M)(~^(Y z0Q)*=*+n-OyNyT3L8k8$Q13DZ=dXm{*XX}Msf8_mzXNo zzNGJ56Y_&mN6mZhIo9{3%XlIa#5>9!zjl*apbPXNTW%G+QSsfRo#4y;kaecX?kTD4 zkp?-KZrm*lpQo}p?|bNuq3zVfOx-DzsZ@H0dm*O&e!+v1i!V-sRjAUV#BCz40_U=` z{Lh8x95saJx^xRyXn~=HyY^n?D?fDZ_X%^~ua@SUWI!wcYQCZE$ezig0gJF;dZZoQ z+Ru^=2gQ-64vUl-*(F=OfBQ7-7YgIx|KhkupUjC>I^a~%?BTd1d=9lcA4&1U6Q#DS zuI#i<)+KSyR_ByfD^awoXtSal;w_C5wneEMj_Wcvzgv24M4f3Evxcb&;F6NOr(aOF zu&2wg=_Zhfh^0^yLAzwCI}FSaIztkqax~NrPH-MrIBp&;uNF%Poy3 zzIx%&H6b`a&9UgZw^HBts@qdGzqO+j!zS!lDYD?D!o)NFx;fBEpnxc8M01n~Z42Gz zlHQ6sOk8g|4*F3WJXX36Q408a*IT#rN1D|vCL}UHWY&4Nsxb$^g@L&9f!lQ7j@s*P z(>v7qNHUFw`iZ&UVpT=nv5NDbdxG~PNuJa71#S>14r>;IIAa+z3xc^9mLnhCn5sg+^TX@)YJ88 zuDT2fx7#$*V*|1P93K$p8i0!rWJZWQBPtb&npkK$Pk$u>p8Sp4sS-GS9ZuSl&XAtE zwT1uT9tOde9R3;G>Da;ewl}r} zfM*obuFhLktB5?}7b#BaQ0!$mr(!4M63_3Zs4NN*t*mf^N^;y;V^G-D_eD-&c>S=_@t%%tVb;#|+mMNl zI|FT}<7U2LQ_fU<`|n-@+!U5DylLq84F&!f6@sxZrvb(wSf(uM19=gBq_Gj)S+3u2 z(2$IT+Mnv8-*oBu?{0V6U@jeva*^5}R^xI@n3G#zYtxaPLCJkxqc})*(kIFdJ+ou& zsNHrVjd11u1m2hX!zFQ*;_mepeSbB7_t6Ix6fiBQv z7QH6a0MJD(TEo}(``*fUAg_9;bK6pnQLwTw0~0Qjqo-!l;-+*`$vn*&;wTxO5Z4<5 z05%}bG60t$&Pha#Ro{sAV*A3UQ{s#(vUy)|TA6T^tnW_R@!?Ks5d*l#u&u(un*F?> zkn>VcTT1b- zxKcDY_Lny8R@KFVaY+7~VA12|(&HmvMeUrHBrVk?K$74o3{MekJ>XV$Czp%f+K*_4 z*QNM`M(kmX%liALgfw6*s$Z0hasn?j^U22ob)HPkBdF>d+ji5YO%RuB zLhS%e@%(iU^<8#*2-k^s=y0eaG;`?Gw>qcO2Sq!g0RV=__YF_e;Yqea=d&f&Pt|)X z<{5&@6jC9tTC}VSk@L|LS~F70`aXs+8i6Ko(xebMlCBzjW#L$(t_BIO39sQ&MfNF2 z)vwO1=kM81br2uc(CZ$Zy{yU7(|ar1r7yTW{Ep8&rj%R+QpB=#8OHmywzaaiTRHE> zRM$Iyar3a_7V)c`ljYD=p*+3QnG0PMmGj}Pb3k#U^yDeK3e@7cnin|Ja^@*++%1+< zbl$*dbCu)HZ@*sgl$>){dSqNZJRY_M;Peu>!EnV?AR@^r3fe6~ry(B#1K5>u6@$hS z2_fx8lAz`ok4;i;5(R@OtTJ;J{{?SJt<&TSYuqP zL)nD~ldGe6)_0Qhs&21S9UWLe6oCwS-IDo8vGk30$8;`JONNSB7HD{YL+^@HL9m=} z8dU+|Tw3j83a^0l&bu>*-1z~e>{cNh$4L@p!E9Tx-2xj3T$CFPRhiQ(pSDO#-D^TU z0PXyu?bsEea~Th*s~&QPB&KsY7))XSZaf7TDAFvNvBl;t$t1-)wKqi{!L9+zi)kE? zgtttKehtQ@dh69y!^1-a?lowVWp9;I>MG~F*bY46V~hxqdGJD35iEe>>L0es@;=xt z%Z<=lRLSptIc&Y;JRxh6{pxhT&+r08C-Xn+5l`N;3 zzKu~;u=E|dp;i5f;e!QxXp2~mt&peI(J=gN{#$u)??UD`-Jgw&RAm(VOC}bffvR4) zlSAhrx$)gkrCDl-(OpF=;jHC!|S@JhmX(iHVAg zao_x2)Il9m;srxCY~L!h4dwS-Vs1QeKQM030`iw^n_J?$clt2*7u;eLFchroZ#)Ek zd)rHY_0DcLfz}d4TCIQE*!y+J#rl!tNvHpw20hGagZfaXX)KF~zUi2GZ&{o9`#Pzu zb$`i9|GSc6?=Fnj+7#CP)dmix^n$g`2R(>RL-U++D=L>;ZJP?P-AI8YLlL7-_HQg7V6L%bN4_n&=; zk#5oQn$V1l8*80xM;V9nul2ou=hLp{{LwH68i66{h2R+3H=%0|9#cJg#Nu(e@6M2(4X=B-&g%h=-+$wXOw>l i{Tbi?ebv8&{=HY%O7Q>r_5UUGf4_{s75|$9!2bXyJFr{; literal 0 HcmV?d00001 diff --git a/chip8.h b/chip8.h index 6bbec85..a3f818a 100644 --- a/chip8.h +++ b/chip8.h @@ -10,6 +10,11 @@ struct Chip8 { uint32_t pixels[64 * 32]; bool draw; + + bool keys[16]; + + uint8_t delay_timer; + uint8_t sound_timer; }; static const uint8_t font[80] = { diff --git a/main.cpp b/main.cpp index ca4967d..08744f8 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,15 @@ #include +#include #include "chip8.h" #include "version.h" #include -#include -void poll_events(SDL_Window *window, bool *running) { +constexpr uint32_t ON_COLOR = 0xFFFFFFFF; +constexpr uint32_t OFF_COLOR = 0x000000FF; + +void poll_events(SDL_Window *window, bool *running, Chip8 &chip8) { SDL_Event ev; while (SDL_PollEvent(&ev)) { @@ -19,25 +22,128 @@ void poll_events(SDL_Window *window, bool *running) { case SDLK_ESCAPE: *running = false; break; - } - break; - case SDL_WINDOWEVENT: - switch (ev.window.event) { - case SDL_WINDOWEVENT_RESIZED: + case SDLK_1: + chip8.keys[0] = true; + break; + case SDLK_2: + chip8.keys[1] = true; + break; + case SDLK_3: + chip8.keys[2] = true; + break; + case SDLK_4: + chip8.keys[3] = true; + break; + case SDLK_q: + chip8.keys[4] = true; + break; + case SDLK_w: + chip8.keys[5] = true; + break; + case SDLK_e: + chip8.keys[6] = true; + break; + case SDLK_r: + chip8.keys[7] = true; + break; + case SDLK_a: + chip8.keys[8] = true; + break; + case SDLK_s: + chip8.keys[9] = true; + break; + case SDLK_d: + chip8.keys[0xA] = true; + break; + case SDLK_f: + chip8.keys[0xB] = true; + break; + case SDLK_z: + chip8.keys[0xC] = true; + break; + case SDLK_x: + chip8.keys[0xD] = true; + break; + case SDLK_c: + chip8.keys[0xE] = true; + break; + case SDLK_v: + chip8.keys[0xF] = true; break; } + break; + case SDL_KEYUP: + switch (ev.key.keysym.sym) { + case SDLK_1: + chip8.keys[0] = false; + break; + case SDLK_2: + chip8.keys[1] = false; + break; + case SDLK_3: + chip8.keys[2] = false; + break; + case SDLK_4: + chip8.keys[3] = false; + break; + case SDLK_q: + chip8.keys[4] = false; + break; + case SDLK_w: + chip8.keys[5] = false; + break; + case SDLK_e: + chip8.keys[6] = false; + break; + case SDLK_r: + chip8.keys[7] = false; + break; + case SDLK_a: + chip8.keys[8] = false; + break; + case SDLK_s: + chip8.keys[9] = false; + break; + case SDLK_d: + chip8.keys[0xA] = false; + break; + case SDLK_f: + chip8.keys[0xB] = false; + break; + case SDLK_z: + chip8.keys[0xC] = false; + break; + case SDLK_x: + chip8.keys[0xD] = false; + break; + case SDLK_c: + chip8.keys[0xE] = false; + break; + case SDLK_v: + chip8.keys[0xF] = false; + break; + } + break; } } } -void emulate(Chip8 &chip8, SDL_Window *window) { - constexpr uint32_t ON_COLOR = 0xFFFFFFFF; - constexpr uint32_t OFF_COLOR = 0x000000FF; +void emulate(Chip8 &chip8, SDL_Window *window, Mix_Music *beep) { const uint8_t first_byte = chip8.memory[chip8.PC]; const uint8_t second_byte = chip8.memory[chip8.PC + 1]; const uint16_t opcode = first_byte << 8 | second_byte; - printf("Executing %02X%02X \n", first_byte, second_byte); + if (chip8.delay_timer > 0) { + // decrement at 60hz + chip8.delay_timer--; + } + + if (chip8.sound_timer > 0) { + // decrement at 60hz + // play sound + Mix_PlayMusic(beep, 1); + chip8.sound_timer--; + } switch (first_byte >> 4) { case 0x0: @@ -179,12 +285,13 @@ void emulate(Chip8 &chip8, SDL_Window *window) { for (int x = 0; x < 8; x++) { if (pixel & (0x80 >> x)) { // check if we're turning off the pixel and set VF. - int index = (chip8.V[first_byte & 0x0F] + x) % 64 + ((chip8.V[((second_byte & 0xF0) >> 4)] + y) % 32) * 64; + int index = ((chip8.V[first_byte & 0x0F] + x) % 64) + ((chip8.V[((second_byte & 0xF0) >> 4)] + y) % 32) * 64; if (chip8.pixels[index] == ON_COLOR) { chip8.V[0xF] = 1; chip8.pixels[index] = OFF_COLOR; + } else { + chip8.pixels[index] = ON_COLOR; } - chip8.pixels[index] = ON_COLOR; } } } @@ -193,23 +300,34 @@ void emulate(Chip8 &chip8, SDL_Window *window) { break; } case 0xE: - // TODO: + switch (second_byte) { + case 0x9E: + if (chip8.keys[chip8.V[first_byte & 0x0F]]) { + chip8.PC += 2; + } + break; + case 0xA1: + if (!chip8.keys[chip8.V[first_byte & 0x0F]]) { + chip8.PC += 2; + } + break; + } chip8.PC += 2; break; case 0xF: auto X = (opcode & 0x0F00) >> 8; switch (second_byte) { case 0x07: - // TODO: + chip8.V[X] = chip8.delay_timer; break; case 0x0A: - // TODO: + // TODO: wait for keypress and then store it somewhere break; case 0x15: - // TODO: + chip8.delay_timer = chip8.V[X]; break; case 0x18: - // TODO: + chip8.sound_timer = chip8.V[X]; break; case 0x1E: chip8.I = chip8.I + chip8.V[X]; @@ -242,14 +360,14 @@ void emulate(Chip8 &chip8, SDL_Window *window) { int main(int argc, char **argv) { if (argc < 2) { - std::cout << "No file was provided as input, quitting program" << std::endl; + printf("No file was provided as input, quitting program\n"); return 0; } std::ifstream file(argv[1], std::ios::binary | std::ios::ate); if (!file) { - std::cout << "Invalid file was provided, quitting program" << std::endl; + printf("Invalid file was provided, quitting program\n"); return 0; } @@ -263,15 +381,28 @@ int main(int argc, char **argv) { Chip8 chip8; memcpy(chip8.memory, font, sizeof(font)); - memset(chip8.pixels, 0xFF000000, sizeof(chip8.pixels)); + memset(chip8.pixels, 0, sizeof(chip8.pixels)); memset(chip8.stack, 0, sizeof(chip8.stack)); memset(chip8.V, 0, sizeof(chip8.V)); if (SDL_Init(SDL_INIT_VIDEO) < 0) { - std::cout << "Video init failed"; + printf("Video init failed\n"); return -1; } - + + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + printf("Audio init failed\n"); + return -1; + } + + if (MIX_INIT_MP3 != Mix_Init(MIX_INIT_MP3)) { + printf("Could not init audio mixer\n"); + return -1; + } + + Mix_OpenAudio(22050, AUDIO_S16SYS, 2, 640); + Mix_Music *beep = Mix_LoadMUS("./beep.mp3"); + srand(time(0)); std::streamsize size = file.tellg(); @@ -281,26 +412,27 @@ int main(int argc, char **argv) { window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 320, SDL_WINDOW_SHOWN); renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_BGRA8888, SDL_TEXTUREACCESS_STATIC, 64, 32); + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 64, 32); bool running = true; while (running) { - emulate(chip8, window); + emulate(chip8, window, beep); if (chip8.draw) { - SDL_UpdateTexture(texture, 0, chip8.pixels, 64 * sizeof(uint32_t)); - SDL_RenderCopy(renderer, texture, 0, 0); + SDL_UpdateTexture(texture, nullptr, chip8.pixels, 64 * sizeof(uint32_t)); + SDL_RenderCopy(renderer, texture, nullptr, nullptr); SDL_RenderPresent(renderer); chip8.draw = false; } - poll_events(window, &running); + poll_events(window, &running, chip8); } SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); + Mix_FreeMusic(beep); SDL_Quit(); return 0; diff --git a/sdl2_cmake_files/FindSDL2.cmake b/sdl2_cmake_files/FindSDL2.cmake new file mode 100644 index 0000000..0f6fcfc --- /dev/null +++ b/sdl2_cmake_files/FindSDL2.cmake @@ -0,0 +1,388 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# Copyright 2019 Amine Ben Hassouna +# Copyright 2000-2019 Kitware, Inc. and Contributors +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. + +# * Neither the name of Kitware, Inc. nor the names of Contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#[=======================================================================[.rst: +FindSDL2 +-------- + +Locate SDL2 library + +This module defines the following 'IMPORTED' targets: + +:: + + SDL2::Core + The SDL2 library, if found. + Libraries should link to SDL2::Core + + SDL2::Main + The SDL2main library, if found. + Applications should link to SDL2::Main instead of SDL2::Core + + + +This module will set the following variables in your project: + +:: + + SDL2_LIBRARIES, the name of the library to link against + SDL2_INCLUDE_DIRS, where to find SDL.h + SDL2_FOUND, if false, do not try to link to SDL2 + SDL2MAIN_FOUND, if false, do not try to link to SDL2main + SDL2_VERSION_STRING, human-readable string containing the version of SDL2 + + + +This module responds to the following cache variables: + +:: + + SDL2_PATH + Set a custom SDL2 Library path (default: empty) + + SDL2_NO_DEFAULT_PATH + Disable search SDL2 Library in default path. + If SDL2_PATH (default: ON) + Else (default: OFF) + + SDL2_INCLUDE_DIR + SDL2 headers path. + + SDL2_LIBRARY + SDL2 Library (.dll, .so, .a, etc) path. + + SDL2MAIN_LIBRAY + SDL2main Library (.a) path. + + SDL2_BUILDING_LIBRARY + This flag is useful only when linking to SDL2_LIBRARIES insead of + SDL2::Main. It is required only when building a library that links to + SDL2_LIBRARIES, because only applications need main() (No need to also + link to SDL2main). + If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES + and no SDL2::Main target will be created. + + +Don't forget to include SDLmain.h and SDLmain.m in your project for the +OS X framework based version. (Other versions link to -lSDL2main which +this module will try to find on your behalf.) Also for OS X, this +module will automatically add the -framework Cocoa on your behalf. + + +Additional Note: If you see an empty SDL2_LIBRARY in your project +configuration, it means CMake did not find your SDL2 library +(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point +to your SDL2 library, and configure again. Similarly, if you see an +empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These +values are used to generate the final SDL2_LIBRARIES variable and the +SDL2::Core and SDL2::Main targets, but when these values are unset, +SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created. + + +$SDL2DIR is an environment variable that would correspond to the +./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 + + + +Created by Amine Ben Hassouna: + Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake). + Add cache variables for more flexibility: + SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above). + Mark 'Threads' as a required dependency for non-OSX systems. + Modernize the FindSDL2.cmake module by creating specific targets: + SDL2::Core and SDL2::Main (for details, see doc above). + + +Original FindSDL.cmake module: + Modified by Eric Wing. Added code to assist with automated building + by using environmental variables and providing a more + controlled/consistent search behavior. Added new modifications to + recognize OS X frameworks and additional Unix paths (FreeBSD, etc). + Also corrected the header search path to follow "proper" SDL + guidelines. Added a search for SDLmain which is needed by some + platforms. Added a search for threads which is needed by some + platforms. Added needed compile switches for MinGW. + +On OSX, this will prefer the Framework version (if found) over others. +People will have to manually change the cache value of SDL2_LIBRARY to +override this selection or set the SDL2_PATH variable or the CMake +environment CMAKE_INCLUDE_PATH to modify the search paths. + +Note that the header path has changed from SDL/SDL.h to just SDL.h +This needed to change because "proper" SDL convention is #include +"SDL.h", not . This is done for portability reasons +because not all systems place things in SDL/ (see FreeBSD). +#]=======================================================================] + +# Define options for searching SDL2 Library in a custom path + +set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path") + +set(_SDL2_NO_DEFAULT_PATH OFF) +if(SDL2_PATH) + set(_SDL2_NO_DEFAULT_PATH ON) +endif() + +set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH} + CACHE BOOL "Disable search SDL2 Library in default path") +unset(_SDL2_NO_DEFAULT_PATH) + +set(SDL2_NO_DEFAULT_PATH_CMD) +if(SDL2_NO_DEFAULT_PATH) + set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH) +endif() + +# Search for the SDL2 include directory +find_path(SDL2_INCLUDE_DIR SDL.h + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES SDL2 + # path suffixes to search inside ENV{SDL2DIR} + include/SDL2 include + PATHS ${SDL2_PATH} + DOC "Where the SDL2 headers can be found" +) + +set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}") + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VC_LIB_PATH_SUFFIX lib/x64) +else() + set(VC_LIB_PATH_SUFFIX lib/x86) +endif() + +# SDL-2.0 is the name used by FreeBSD ports... +# don't confuse it for the version number. +find_library(SDL2_LIBRARY + NAMES SDL2 SDL-2.0 + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2_PATH} + DOC "Where the SDL2 Library can be found" +) + +set(SDL2_LIBRARIES "${SDL2_LIBRARY}") + +if(NOT SDL2_BUILDING_LIBRARY) + if(NOT SDL2_INCLUDE_DIR MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + + if(SDL2_PATH) + set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}") + endif() + + if(NOT SDL2_NO_DEFAULT_PATH) + set(SDL2MAIN_LIBRARY_PATHS + /sw + /opt/local + /opt/csw + /opt + "${SDL2MAIN_LIBRARY_PATHS}" + ) + endif() + + find_library(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2MAIN_LIBRARY_PATHS} + DOC "Where the SDL2main library can be found" + ) + unset(SDL2MAIN_LIBRARY_PATHS) + endif() +endif() + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +if(NOT APPLE) + find_package(Threads QUIET) + if(NOT Threads_FOUND) + set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).") + if(SDL2_FIND_REQUIRED) + message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND}) + else() + if(NOT SDL2_FIND_QUIETLY) + message(STATUS ${SDL2_THREADS_NOT_FOUND}) + endif() + return() + endif() + unset(SDL2_THREADS_NOT_FOUND) + endif() +endif() + +# MinGW needs an additional link flag, -mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows +if(MINGW) + set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW") +endif() + +if(SDL2_LIBRARY) + # For SDL2main + if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY) + list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX) + if(_SDL2_MAIN_INDEX EQUAL -1) + set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES}) + endif() + unset(_SDL2_MAIN_INDEX) + endif() + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + if(APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa) + endif() + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + if(NOT APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + # For MinGW library + if(MINGW) + set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES}) + endif() + +endif() + +# Read SDL2 version +if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}") + set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}) + unset(SDL2_VERSION_MAJOR_LINE) + unset(SDL2_VERSION_MINOR_LINE) + unset(SDL2_VERSION_PATCH_LINE) + unset(SDL2_VERSION_MAJOR) + unset(SDL2_VERSION_MINOR) + unset(SDL2_VERSION_PATCH) +endif() + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) + +if(SDL2MAIN_LIBRARY) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main + REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) +endif() + + +mark_as_advanced(SDL2_PATH + SDL2_NO_DEFAULT_PATH + SDL2_LIBRARY + SDL2MAIN_LIBRARY + SDL2_INCLUDE_DIR + SDL2_BUILDING_LIBRARY) + + +# SDL2:: targets (SDL2::Core and SDL2::Main) +if(SDL2_FOUND) + + # SDL2::Core target + if(SDL2_LIBRARY AND NOT TARGET SDL2::Core) + add_library(SDL2::Core UNKNOWN IMPORTED) + set_target_properties(SDL2::Core PROPERTIES + IMPORTED_LOCATION "${SDL2_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}") + + if(APPLE) + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_OPTIONS -framework Cocoa) + else() + # For threads, as mentioned Apple doesn't need this. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + endif() + + # SDL2::Main target + # Applications should link to SDL2::Main instead of SDL2::Core + # For more details, please see above. + if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main) + + if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY) + add_library(SDL2::Main INTERFACE IMPORTED) + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + elseif(SDL2MAIN_LIBRARY) + # MinGW requires that the mingw32 library is specified before the + # libSDL2main.a static library when linking. + # The SDL2::MainInternal target is used internally to make sure that + # CMake respects this condition. + add_library(SDL2::MainInternal UNKNOWN IMPORTED) + set_property(TARGET SDL2::MainInternal PROPERTY + IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}") + set_property(TARGET SDL2::MainInternal PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + + add_library(SDL2::Main INTERFACE IMPORTED) + + if(MINGW) + # MinGW needs an additional link flag '-mwindows' and link to mingw32 + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows") + endif() + + set_property(TARGET SDL2::Main APPEND PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::MainInternal) + endif() + + endif() +endif() \ No newline at end of file diff --git a/sdl2_cmake_files/FindSDL2_mixer.cmake b/sdl2_cmake_files/FindSDL2_mixer.cmake new file mode 100644 index 0000000..ae6051a --- /dev/null +++ b/sdl2_cmake_files/FindSDL2_mixer.cmake @@ -0,0 +1,220 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# Copyright 2019 Amine Ben Hassouna +# Copyright 2000-2019 Kitware, Inc. and Contributors +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. + +# * Neither the name of Kitware, Inc. nor the names of Contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#[=======================================================================[.rst: +FindSDL2_mixer +-------------- + +Locate SDL2_mixer library + +This module defines the following 'IMPORTED' target: + +:: + + SDL2::Mixer + The SDL2_mixer library, if found. + Have SDL2::Core as a link dependency. + + + +This module will set the following variables in your project: + +:: + + SDL2_MIXER_LIBRARIES, the name of the library to link against + SDL2_MIXER_INCLUDE_DIRS, where to find the headers + SDL2_MIXER_FOUND, if false, do not try to link against + SDL2_MIXER_VERSION_STRING - human-readable string containing the + version of SDL2_mixer + +This module responds to the following cache variables: + +:: + + SDL2_MIXER_PATH + Set a custom SDL2_mixer Library path (default: empty) + + SDL2_MIXER_NO_DEFAULT_PATH + Disable search SDL2_mixer Library in default path. + If SDL2_MIXER_PATH (default: ON) + Else (default: OFF) + + SDL2_MIXER_INCLUDE_DIR + SDL2_mixer headers path. + + SDL2_MIXER_LIBRARY + SDL2_mixer Library (.dll, .so, .a, etc) path. + + +Additional Note: If you see an empty SDL2_MIXER_LIBRARY in your project +configuration, it means CMake did not find your SDL2_mixer library +(SDL2_mixer.dll, libsdl2_mixer.so, etc). Set SDL2_MIXER_LIBRARY to point +to your SDL2_mixer library, and configure again. This value is used to +generate the final SDL2_MIXER_LIBRARIES variable and the SDL2::Mixer target, +but when this value is unset, SDL2_MIXER_LIBRARIES and SDL2::Mixer does not +get created. + + +$SDL2MIXERDIR is an environment variable that would correspond to the +./configure --prefix=$SDL2MIXERDIR used in building SDL2_mixer. + +$SDL2DIR is an environment variable that would correspond to the +./configure --prefix=$SDL2DIR used in building SDL2. + + + +Created by Amine Ben Hassouna: + Adapt FindSDL_mixer.cmake to SDL2_mixer (FindSDL2_mixer.cmake). + Add cache variables for more flexibility: + SDL2_MIXER_PATH, SDL2_MIXER_NO_DEFAULT_PATH (for details, see doc above). + Add SDL2 as a required dependency. + Modernize the FindSDL2_mixer.cmake module by creating a specific target: + SDL2::Mixer (for details, see doc above). + +Original FindSDL_mixer.cmake module: + Created by Eric Wing. This was influenced by the FindSDL.cmake + module, but with modifications to recognize OS X frameworks and + additional Unix paths (FreeBSD, etc). +#]=======================================================================] + +# SDL2 Library required +find_package(SDL2 QUIET) +if(NOT SDL2_FOUND) + set(SDL2_MIXER_SDL2_NOT_FOUND "Could NOT find SDL2 (SDL2 is required by SDL2_mixer).") + if(SDL2_mixer_FIND_REQUIRED) + message(FATAL_ERROR ${SDL2_MIXER_SDL2_NOT_FOUND}) + else() + if(NOT SDL2_mixer_FIND_QUIETLY) + message(STATUS ${SDL2_MIXER_SDL2_NOT_FOUND}) + endif() + return() + endif() + unset(SDL2_MIXER_SDL2_NOT_FOUND) +endif() + + +# Define options for searching SDL2_mixer Library in a custom path + +set(SDL2_MIXER_PATH "" CACHE STRING "Custom SDL2_mixer Library path") + +set(_SDL2_MIXER_NO_DEFAULT_PATH OFF) +if(SDL2_MIXER_PATH) + set(_SDL2_MIXER_NO_DEFAULT_PATH ON) +endif() + +set(SDL2_MIXER_NO_DEFAULT_PATH ${_SDL2_MIXER_NO_DEFAULT_PATH} + CACHE BOOL "Disable search SDL2_mixer Library in default path") +unset(_SDL2_MIXER_NO_DEFAULT_PATH) + +set(SDL2_MIXER_NO_DEFAULT_PATH_CMD) +if(SDL2_MIXER_NO_DEFAULT_PATH) + set(SDL2_MIXER_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH) +endif() + +# Search for the SDL2_mixer include directory +find_path(SDL2_MIXER_INCLUDE_DIR SDL_mixer.h + HINTS + ENV SDL2MIXERDIR + ENV SDL2DIR + ${SDL2_MIXER_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES SDL2 + # path suffixes to search inside ENV{SDL2DIR} + # and ENV{SDL2MIXERDIR} + include/SDL2 include + PATHS ${SDL2_MIXER_PATH} + DOC "Where the SDL2_mixer headers can be found" +) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VC_LIB_PATH_SUFFIX lib/x64) +else() + set(VC_LIB_PATH_SUFFIX lib/x86) +endif() + +# Search for the SDL2_mixer library +find_library(SDL2_MIXER_LIBRARY + NAMES SDL2_mixer + HINTS + ENV SDL2MIXERDIR + ENV SDL2DIR + ${SDL2_MIXER_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2_MIXER_PATH} + DOC "Where the SDL2_mixer Library can be found" +) + +# Read SDL2_mixer version +if(SDL2_MIXER_INCLUDE_DIR AND EXISTS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h") + file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_MIXER_INCLUDE_DIR}/SDL_mixer.h" SDL2_MIXER_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MAJOR "${SDL2_MIXER_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_MINOR "${SDL2_MIXER_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MIXER_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_MIXER_VERSION_PATCH "${SDL2_MIXER_VERSION_PATCH_LINE}") + set(SDL2_MIXER_VERSION_STRING ${SDL2_MIXER_VERSION_MAJOR}.${SDL2_MIXER_VERSION_MINOR}.${SDL2_MIXER_VERSION_PATCH}) + unset(SDL2_MIXER_VERSION_MAJOR_LINE) + unset(SDL2_MIXER_VERSION_MINOR_LINE) + unset(SDL2_MIXER_VERSION_PATCH_LINE) + unset(SDL2_MIXER_VERSION_MAJOR) + unset(SDL2_MIXER_VERSION_MINOR) + unset(SDL2_MIXER_VERSION_PATCH) +endif() + +set(SDL2_MIXER_LIBRARIES ${SDL2_MIXER_LIBRARY}) +set(SDL2_MIXER_INCLUDE_DIRS ${SDL2_MIXER_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_mixer + REQUIRED_VARS SDL2_MIXER_LIBRARIES SDL2_MIXER_INCLUDE_DIRS + VERSION_VAR SDL2_MIXER_VERSION_STRING) + + +mark_as_advanced(SDL2_MIXER_PATH + SDL2_MIXER_NO_DEFAULT_PATH + SDL2_MIXER_LIBRARY + SDL2_MIXER_INCLUDE_DIR) + + +if(SDL2_MIXER_FOUND) + + # SDL2::Mixer target + if(SDL2_MIXER_LIBRARY AND NOT TARGET SDL2::Mixer) + add_library(SDL2::Mixer UNKNOWN IMPORTED) + set_target_properties(SDL2::Mixer PROPERTIES + IMPORTED_LOCATION "${SDL2_MIXER_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_MIXER_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES SDL2::Core) + endif() +endif() \ No newline at end of file