main: Added _optional_ callback entry points.
This lets apps optionally have a handful of callbacks for their entry points instead of a single main function. If used, the actual main/SDL_main/whatever entry point will be implemented in the single-header library SDL_main.h and the app will implement four separate functions:
First:
int SDL_AppInit(int argc, char **argv);
This will be called once before anything else. argc/argv work like they always do. If this returns 0, the app runs. If it returns < 0, the app calls SDL_AppQuit and terminates with an exit code that reports an error to the platform. If it returns > 0, the app calls SDL_AppQuit and terminates with an exit code that reports success to the platform. This function should not go into an infinite mainloop; it should do any one-time startup it requires and then return.
Then:
int SDL_AppIterate(void);
This is called over and over, possibly at the refresh rate of the display or some other metric that the platform dictates. This is where the heart of your app runs. It should return as quickly as reasonably possible, but it's not a "run one memcpy and that's all the time you have" sort of thing. The app should do any game updates, and render a frame of video. If it returns < 0, SDL will call SDL_AppQuit and terminate the process with an exit code that reports an error to the platform. If it returns > 0, the app calls SDL_AppQuit and terminates with an exit code that reports success to the platform. If it returns 0, then SDL_AppIterate will be called again at some regular frequency. The platform may choose to run this more or less (perhaps less in the background, etc), or it might just call this function in a loop as fast as possible. You do not check the event queue in this function (SDL_AppEvent exists for that).
Next:
int SDL_AppEvent(const SDL_Event *event);
This will be called once for each event pushed into the SDL queue. This may be called from any thread, and possibly in parallel to SDL_AppIterate. The fields in event do not need to be free'd (as you would normally need to do for SDL_EVENT_DROP_FILE, etc), and your app should not call SDL_PollEvent, SDL_PumpEvent, etc, as SDL will manage this for you. Return values are the same as from SDL_AppIterate(), so you can terminate in response to SDL_EVENT_QUIT, etc.
Finally:
void SDL_AppQuit(void);
This is called once before terminating the app--assuming the app isn't being forcibly killed or crashed--as a last chance to clean up. After this returns, SDL will call SDL_Quit so the app doesn't have to (but it's safe for the app to call it, too). Process termination proceeds as if the app returned normally from main(), so atexit handles will run, if your platform supports that.
The app does not implement SDL_main if using this. To turn this on, define SDL_MAIN_USE_CALLBACKS before including SDL_main.h. Defines like SDL_MAIN_HANDLED and SDL_MAIN_NOIMPL are also respected for callbacks, if the app wants to do some sort of magic main implementation thing.
In theory, on most platforms these can be implemented in the app itself, but this saves some #ifdefs in the app and lets everyone struggle less against some platforms, and might be more efficient in the long run, too.
On some platforms, it's possible this is the only reasonable way to go, but we haven't actually hit one that 100% requires it yet (but we will, if we want to write a RetroArch backend, for example).
Using the callback entry points works on every platform, because on platforms that don't require them, we can fake them with a simple loop in an internal implementation of the usual SDL_main.
The primary way we expect people to write SDL apps is with SDL_main, and this is not intended to replace it. If the app chooses to use this, it just removes some platform-specific details they might have to otherwise manage, and maybe removes a barrier to entry on some future platform.
Fixes #6785.
Reference PR #8247.
This commit is contained in:
@@ -47,11 +47,16 @@ if(WINDOWS_STORE)
|
||||
target_link_libraries(sdl_test_main_uwp PRIVATE SDL3::Headers)
|
||||
target_compile_options(sdl_test_main_uwp PRIVATE "/ZW")
|
||||
|
||||
add_library(sdl_test_main_callbacks_uwp OBJECT main.cpp)
|
||||
target_link_libraries(sdl_test_main_callbacks_uwp PRIVATE SDL3::Headers)
|
||||
target_compile_options(sdl_test_main_callbacks_uwp PRIVATE "/ZW")
|
||||
target_compile_definitions(sdl_test_main_callbacks_uwp PRIVATE "SDL_MAIN_USE_CALLBACKS")
|
||||
|
||||
set_source_files_properties(${RESOURCE_FILES} PROPERTIES VS_DEPLOYENT_LOCATION "Assets")
|
||||
endif()
|
||||
|
||||
macro(add_sdl_test_executable TARGET)
|
||||
cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;NO_C90" "" "NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;SOURCES" ${ARGN})
|
||||
cmake_parse_arguments(AST "BUILD_DEPENDENT;NONINTERACTIVE;NEEDS_RESOURCES;TESTUTILS;NO_C90;MAIN_CALLBACKS" "" "NONINTERACTIVE_TIMEOUT;NONINTERACTIVE_ARGS;SOURCES" ${ARGN})
|
||||
if(AST_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown argument(s): ${AST_UNPARSED_ARGUMENTS}")
|
||||
endif()
|
||||
@@ -73,8 +78,14 @@ macro(add_sdl_test_executable TARGET)
|
||||
TARGET "${TARGET}"
|
||||
)
|
||||
set_property(SOURCE "${uwp_bindir}/${TARGET}.appxmanifest" PROPERTY VS_DEPLOYMENT_CONTENT 1)
|
||||
|
||||
if(AST_MAIN_CALLBACKS)
|
||||
list(APPEND EXTRA_SOURCES "$<TARGET_OBJECTS:sdl_test_main_callbacks_uwp>")
|
||||
else()
|
||||
list(APPEND EXTRA_SOURCES "$<TARGET_OBJECTS:sdl_test_main_uwp>")
|
||||
endif()
|
||||
|
||||
list(APPEND EXTRA_SOURCES
|
||||
"$<TARGET_OBJECTS:sdl_test_main_uwp>"
|
||||
"${uwp_bindir}/${TARGET}.appxmanifest"
|
||||
"uwp/logo-50x50.png"
|
||||
"uwp/square-44x44.png"
|
||||
@@ -213,7 +224,7 @@ endif()
|
||||
|
||||
add_sdl_test_executable(checkkeys SOURCES checkkeys.c)
|
||||
add_sdl_test_executable(checkkeysthreads SOURCES checkkeysthreads.c)
|
||||
add_sdl_test_executable(loopwave NEEDS_RESOURCES TESTUTILS SOURCES loopwave.c)
|
||||
add_sdl_test_executable(loopwave NEEDS_RESOURCES TESTUTILS MAIN_CALLBACKS SOURCES loopwave.c)
|
||||
add_sdl_test_executable(testsurround SOURCES testsurround.c)
|
||||
add_sdl_test_executable(testresample NEEDS_RESOURCES SOURCES testresample.c)
|
||||
add_sdl_test_executable(testaudioinfo SOURCES testaudioinfo.c)
|
||||
@@ -223,7 +234,7 @@ file(GLOB TESTAUTOMATION_SOURCE_FILES testautomation*.c)
|
||||
add_sdl_test_executable(testautomation NONINTERACTIVE NONINTERACTIVE_TIMEOUT 120 NEEDS_RESOURCES NO_C90 SOURCES ${TESTAUTOMATION_SOURCE_FILES})
|
||||
add_sdl_test_executable(testmultiaudio NEEDS_RESOURCES TESTUTILS SOURCES testmultiaudio.c)
|
||||
add_sdl_test_executable(testaudiohotplug NEEDS_RESOURCES TESTUTILS SOURCES testaudiohotplug.c)
|
||||
add_sdl_test_executable(testaudiocapture SOURCES testaudiocapture.c)
|
||||
add_sdl_test_executable(testaudiocapture MAIN_CALLBACKS SOURCES testaudiocapture.c)
|
||||
add_sdl_test_executable(testatomic NONINTERACTIVE SOURCES testatomic.c)
|
||||
add_sdl_test_executable(testintersections SOURCES testintersections.c)
|
||||
add_sdl_test_executable(testrelative SOURCES testrelative.c)
|
||||
@@ -304,7 +315,7 @@ files2headers(gamepad_image_headers
|
||||
)
|
||||
files2headers(icon_bmp_header icon.bmp)
|
||||
|
||||
add_sdl_test_executable(testaudio NEEDS_RESOURCES TESTUTILS SOURCES testaudio.c)
|
||||
add_sdl_test_executable(testaudio MAIN_CALLBACKS NEEDS_RESOURCES TESTUTILS SOURCES testaudio.c)
|
||||
add_sdl_test_executable(testfile NONINTERACTIVE SOURCES testfile.c)
|
||||
add_sdl_test_executable(testcontroller TESTUTILS SOURCES testcontroller.c gamepadutils.c ${gamepad_image_headers})
|
||||
add_sdl_test_executable(testgeometry TESTUTILS SOURCES testgeometry.c)
|
||||
@@ -341,7 +352,7 @@ add_sdl_test_executable(testsem NONINTERACTIVE NONINTERACTIVE_ARGS 10 NONINTERAC
|
||||
add_sdl_test_executable(testsensor SOURCES testsensor.c)
|
||||
add_sdl_test_executable(testshader NEEDS_RESOURCES TESTUTILS SOURCES testshader.c)
|
||||
add_sdl_test_executable(testshape NEEDS_RESOURCES SOURCES testshape.c)
|
||||
add_sdl_test_executable(testsprite NEEDS_RESOURCES TESTUTILS SOURCES testsprite.c)
|
||||
add_sdl_test_executable(testsprite MAIN_CALLBACKS NEEDS_RESOURCES TESTUTILS SOURCES testsprite.c)
|
||||
add_sdl_test_executable(testspriteminimal SOURCES testspriteminimal.c ${icon_bmp_header})
|
||||
add_sdl_test_executable(teststreaming NEEDS_RESOURCES TESTUTILS SOURCES teststreaming.c)
|
||||
add_sdl_test_executable(testtimer NONINTERACTIVE NONINTERACTIVE_ARGS --no-interactive NONINTERACTIVE_TIMEOUT 60 SOURCES testtimer.c)
|
||||
|
||||
118
test/loopwave.c
118
test/loopwave.c
@@ -17,10 +17,7 @@
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3/SDL_test.h>
|
||||
@@ -34,68 +31,24 @@ static struct
|
||||
} wave;
|
||||
|
||||
static SDL_AudioStream *stream;
|
||||
static SDLTest_CommonState *state;
|
||||
|
||||
static void fillerup(void)
|
||||
static int fillerup(void)
|
||||
{
|
||||
const int minimum = (wave.soundlen / SDL_AUDIO_FRAMESIZE(wave.spec)) / 2;
|
||||
if (SDL_GetAudioStreamQueued(stream) < minimum) {
|
||||
SDL_PutAudioStreamData(stream, wave.sound, wave.soundlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
|
||||
static void
|
||||
quit(int rc)
|
||||
{
|
||||
SDL_Quit();
|
||||
/* Let 'main()' return normally */
|
||||
if (rc != 0) {
|
||||
exit(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
close_audio(void)
|
||||
{
|
||||
if (stream) {
|
||||
SDL_DestroyAudioStream(stream);
|
||||
stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_audio(void)
|
||||
{
|
||||
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &wave.spec, NULL, NULL);
|
||||
if (!stream) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s\n", SDL_GetError());
|
||||
SDL_free(wave.sound);
|
||||
quit(2);
|
||||
}
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));
|
||||
}
|
||||
|
||||
|
||||
static int done = 0;
|
||||
|
||||
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
static void loop(void)
|
||||
{
|
||||
if (done) {
|
||||
emscripten_cancel_main_loop();
|
||||
} else {
|
||||
fillerup();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int SDL_AppInit(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
char *filename = NULL;
|
||||
SDLTest_CommonState *state;
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "5");
|
||||
|
||||
/* Initialize test framework */
|
||||
state = SDLTest_CommonCreateState(argv, 0);
|
||||
@@ -129,22 +82,25 @@ int main(int argc, char *argv[])
|
||||
/* Load the SDL library */
|
||||
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
filename = GetResourceFilename(filename, "sample.wav");
|
||||
|
||||
if (filename == NULL) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
|
||||
quit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load the wave file into memory */
|
||||
if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == -1) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
|
||||
quit(1);
|
||||
SDL_free(filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_free(filename);
|
||||
|
||||
/* Show the list of available drivers */
|
||||
SDL_Log("Available audio drivers:");
|
||||
for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
|
||||
@@ -153,30 +109,30 @@ int main(int argc, char *argv[])
|
||||
|
||||
SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
|
||||
|
||||
open_audio();
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop(loop, 0, 1);
|
||||
#else
|
||||
while (!done) {
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL_PollEvent(&event) > 0) {
|
||||
if (event.type == SDL_EVENT_QUIT) {
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
fillerup();
|
||||
SDL_Delay(100);
|
||||
stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &wave.spec, NULL, NULL);
|
||||
if (!stream) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create audio stream: %s\n", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream));
|
||||
|
||||
/* Clean up on signal */
|
||||
close_audio();
|
||||
SDL_free(wave.sound);
|
||||
SDL_free(filename);
|
||||
SDL_Quit();
|
||||
SDLTest_CommonDestroyState(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDL_AppEvent(const SDL_Event *event)
|
||||
{
|
||||
return (event->type == SDL_EVENT_QUIT) ? 1 : 0;
|
||||
}
|
||||
|
||||
int SDL_AppIterate(void)
|
||||
{
|
||||
return fillerup();
|
||||
}
|
||||
|
||||
void SDL_AppQuit(void)
|
||||
{
|
||||
SDL_DestroyAudioStream(stream);
|
||||
SDL_free(wave.sound);
|
||||
SDLTest_CommonDestroyState(state);
|
||||
}
|
||||
|
||||
|
||||
539
test/testaudio.c
539
test/testaudio.c
@@ -1,9 +1,4 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
#include <SDL3/SDL_test.h>
|
||||
#include <SDL3/SDL_test_common.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
@@ -103,7 +98,6 @@ struct Thing
|
||||
|
||||
|
||||
static Uint64 app_ready_ticks = 0;
|
||||
static int done = 0;
|
||||
static SDLTest_CommonState *state = NULL;
|
||||
|
||||
static Thing *things = NULL;
|
||||
@@ -124,51 +118,6 @@ static Texture *trashcan_texture = NULL;
|
||||
static Texture *soundboard_texture = NULL;
|
||||
static Texture *soundboard_levels_texture = NULL;
|
||||
|
||||
static void DestroyTexture(Texture *tex);
|
||||
static void DestroyThing(Thing *thing);
|
||||
|
||||
|
||||
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
|
||||
static void Quit(int rc)
|
||||
{
|
||||
while (things != NULL) {
|
||||
DestroyThing(things); /* make sure all the audio devices are closed, etc. */
|
||||
}
|
||||
|
||||
DestroyTexture(physdev_texture);
|
||||
DestroyTexture(logdev_texture);
|
||||
DestroyTexture(audio_texture);
|
||||
DestroyTexture(trashcan_texture);
|
||||
DestroyTexture(soundboard_texture);
|
||||
DestroyTexture(soundboard_levels_texture);
|
||||
SDLTest_CommonQuit(state);
|
||||
|
||||
/* Let 'main()' return normally */
|
||||
if (rc != 0) {
|
||||
exit(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static char *xstrdup(const char *str)
|
||||
{
|
||||
char *ptr = SDL_strdup(str);
|
||||
if (!ptr) {
|
||||
SDL_Log("Out of memory!");
|
||||
Quit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *xalloc(const size_t len)
|
||||
{
|
||||
void *ptr = SDL_calloc(1, len);
|
||||
if (!ptr) {
|
||||
SDL_Log("Out of memory!");
|
||||
Quit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
static void SetTitleBar(const char *fmt, ...)
|
||||
{
|
||||
@@ -232,7 +181,12 @@ static Thing *CreateThing(ThingType what, float x, float y, float z, float w, fl
|
||||
Thing *i;
|
||||
Thing *thing;
|
||||
|
||||
thing = (Thing *) xalloc(sizeof (Thing));
|
||||
thing = (Thing *) SDL_calloc(1, sizeof (Thing));
|
||||
if (!thing) {
|
||||
SDL_Log("Out of memory!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((w < 0) || (h < 0)) {
|
||||
SDL_assert(texture != NULL);
|
||||
if (w < 0) {
|
||||
@@ -256,7 +210,7 @@ static Thing *CreateThing(ThingType what, float x, float y, float z, float w, fl
|
||||
thing->scale = 1.0f;
|
||||
thing->createticks = SDL_GetTicks();
|
||||
thing->texture = texture;
|
||||
thing->titlebar = titlebar ? xstrdup(titlebar) : NULL;
|
||||
thing->titlebar = titlebar ? SDL_strdup(titlebar) : NULL; /* if allocation fails, oh well. */
|
||||
|
||||
/* insert in list by Z order (furthest from the "camera" first, so they get drawn over; negative Z is not drawn at all). */
|
||||
if (things == NULL) {
|
||||
@@ -515,12 +469,14 @@ static Thing *CreatePoofThing(Thing *poofing_thing)
|
||||
const float centery = poofing_thing->rect.y + (poofing_thing->rect.h / 2);
|
||||
const float z = poofing_thing->z;
|
||||
Thing *thing = CreateThing(THING_POOF, poofing_thing->rect.x, poofing_thing->rect.y, z, poofing_thing->rect.w, poofing_thing->rect.h, poofing_thing->texture, NULL);
|
||||
thing->data.poof.startw = poofing_thing->rect.w;
|
||||
thing->data.poof.starth = poofing_thing->rect.h;
|
||||
thing->data.poof.centerx = centerx;
|
||||
thing->data.poof.centery = centery;
|
||||
thing->ontick = PoofThing_ontick;
|
||||
thing->ondrag = PoofThing_ondrag;
|
||||
if (thing) {
|
||||
thing->data.poof.startw = poofing_thing->rect.w;
|
||||
thing->data.poof.starth = poofing_thing->rect.h;
|
||||
thing->data.poof.centerx = centerx;
|
||||
thing->data.poof.centery = centery;
|
||||
thing->ontick = PoofThing_ontick;
|
||||
thing->ondrag = PoofThing_ondrag;
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
@@ -638,18 +594,20 @@ static Thing *CreateStreamThing(const SDL_AudioSpec *spec, const Uint8 *buf, con
|
||||
{
|
||||
static const ThingType can_be_dropped_onto[] = { THING_TRASHCAN, THING_LOGDEV, THING_LOGDEV_CAPTURE, THING_NULL };
|
||||
Thing *thing = CreateThing(THING_STREAM, x, y, 0, -1, -1, soundboard_texture, fname);
|
||||
SDL_Log("Adding audio stream for %s", fname ? fname : "(null)");
|
||||
thing->data.stream.stream = SDL_CreateAudioStream(spec, spec);
|
||||
if (buf && buflen) {
|
||||
SDL_PutAudioStreamData(thing->data.stream.stream, buf, (int) buflen);
|
||||
SDL_FlushAudioStream(thing->data.stream.stream);
|
||||
thing->data.stream.total_bytes = SDL_GetAudioStreamAvailable(thing->data.stream.stream);
|
||||
if (thing) {
|
||||
SDL_Log("Adding audio stream for %s", fname ? fname : "(null)");
|
||||
thing->data.stream.stream = SDL_CreateAudioStream(spec, spec);
|
||||
if (buf && buflen) {
|
||||
SDL_PutAudioStreamData(thing->data.stream.stream, buf, (int) buflen);
|
||||
SDL_FlushAudioStream(thing->data.stream.stream);
|
||||
thing->data.stream.total_bytes = SDL_GetAudioStreamAvailable(thing->data.stream.stream);
|
||||
}
|
||||
thing->ontick = StreamThing_ontick;
|
||||
thing->ondrag = StreamThing_ondrag;
|
||||
thing->ondrop = StreamThing_ondrop;
|
||||
thing->ondraw = StreamThing_ondraw;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
}
|
||||
thing->ontick = StreamThing_ontick;
|
||||
thing->ondrag = StreamThing_ondrag;
|
||||
thing->ondrop = StreamThing_ondrop;
|
||||
thing->ondraw = StreamThing_ondraw;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
return thing;
|
||||
}
|
||||
|
||||
@@ -703,13 +661,15 @@ static Thing *LoadWavThing(const char *fname, float x, float y)
|
||||
|
||||
SDL_asprintf(&titlebar, "WAV file (\"%s\", %s, %s, %uHz)", nodirs, AudioFmtToString(spec.format), AudioChansToStr(spec.channels), (unsigned int) spec.freq);
|
||||
thing = CreateThing(THING_WAV, x - (audio_texture->w / 2), y - (audio_texture->h / 2), 5, -1, -1, audio_texture, titlebar);
|
||||
SDL_free(titlebar);
|
||||
SDL_memcpy(&thing->data.wav.spec, &spec, sizeof (SDL_AudioSpec));
|
||||
thing->data.wav.buf = buf;
|
||||
thing->data.wav.buflen = buflen;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
thing->ondrag = WavThing_ondrag;
|
||||
thing->ondrop = WavThing_ondrop;
|
||||
if (thing) {
|
||||
SDL_free(titlebar);
|
||||
SDL_memcpy(&thing->data.wav.spec, &spec, sizeof (SDL_AudioSpec));
|
||||
thing->data.wav.buf = buf;
|
||||
thing->data.wav.buflen = buflen;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
thing->ondrag = WavThing_ondrag;
|
||||
thing->ondrop = WavThing_ondrop;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(path);
|
||||
@@ -743,17 +703,21 @@ static void DestroyTexture(Texture *tex)
|
||||
|
||||
static Texture *CreateTexture(const char *fname)
|
||||
{
|
||||
Texture *tex = (Texture *) xalloc(sizeof (Texture));
|
||||
int texw, texh;
|
||||
tex->texture = LoadTexture(state->renderers[0], fname, SDL_TRUE, &texw, &texh);
|
||||
if (!tex->texture) {
|
||||
SDL_Log("Failed to load '%s': %s", fname, SDL_GetError());
|
||||
SDL_free(tex);
|
||||
Quit(1);
|
||||
Texture *tex = (Texture *) SDL_calloc(1, sizeof (Texture));
|
||||
if (!tex) {
|
||||
SDL_Log("Out of memory!");
|
||||
} else {
|
||||
int texw, texh;
|
||||
tex->texture = LoadTexture(state->renderers[0], fname, SDL_TRUE, &texw, &texh);
|
||||
if (!tex->texture) {
|
||||
SDL_Log("Failed to load '%s': %s", fname, SDL_GetError());
|
||||
SDL_free(tex);
|
||||
return NULL;
|
||||
}
|
||||
SDL_SetTextureBlendMode(tex->texture, SDL_BLENDMODE_BLEND);
|
||||
tex->w = (float) texw;
|
||||
tex->h = (float) texh;
|
||||
}
|
||||
SDL_SetTextureBlendMode(tex->texture, SDL_BLENDMODE_BLEND);
|
||||
tex->w = (float) texw;
|
||||
tex->h = (float) texh;
|
||||
return tex;
|
||||
}
|
||||
|
||||
@@ -763,9 +727,11 @@ static void DeviceThing_ondrag(Thing *thing, int button, float x, float y)
|
||||
{
|
||||
if ((button == SDL_BUTTON_MIDDLE) && (thing->what == THING_LOGDEV_CAPTURE)) { /* drag out a new stream. This is a UX mess. :/ */
|
||||
dragging_thing = CreateStreamThing(&thing->data.logdev.spec, NULL, 0, NULL, x, y);
|
||||
dragging_thing->data.stream.next_level_update = SDL_GetTicks() + 100;
|
||||
SDL_BindAudioStream(thing->data.logdev.devid, dragging_thing->data.stream.stream); /* bind to new device! */
|
||||
dragging_thing->line_connected_to = thing;
|
||||
if (dragging_thing) {
|
||||
dragging_thing->data.stream.next_level_update = SDL_GetTicks() + 100;
|
||||
SDL_BindAudioStream(thing->data.logdev.devid, dragging_thing->data.stream.stream); /* bind to new device! */
|
||||
dragging_thing->line_connected_to = thing;
|
||||
}
|
||||
} else if (button == SDL_BUTTON_RIGHT) { /* drag out a new logical device. */
|
||||
const SDL_AudioDeviceID which = ((thing->what == THING_LOGDEV) || (thing->what == THING_LOGDEV_CAPTURE)) ? thing->data.logdev.devid : thing->data.physdev.devid;
|
||||
const SDL_AudioDeviceID devid = SDL_OpenAudioDevice(which, NULL);
|
||||
@@ -929,22 +895,24 @@ static Thing *CreateLogicalDeviceThing(Thing *parent, const SDL_AudioDeviceID wh
|
||||
|
||||
SDL_Log("Adding logical audio device %u", (unsigned int) which);
|
||||
thing = CreateThing(iscapture ? THING_LOGDEV_CAPTURE : THING_LOGDEV, x, y, 5, -1, -1, logdev_texture, NULL);
|
||||
thing->data.logdev.devid = which;
|
||||
thing->data.logdev.iscapture = iscapture;
|
||||
thing->data.logdev.physdev = physthing;
|
||||
thing->data.logdev.visualizer = SDL_CreateTexture(state->renderers[0], SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, VISUALIZER_WIDTH, VISUALIZER_HEIGHT);
|
||||
thing->data.logdev.postmix_lock = SDL_CreateMutex();
|
||||
if (thing->data.logdev.visualizer) {
|
||||
SDL_SetTextureBlendMode(thing->data.logdev.visualizer, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
thing->line_connected_to = physthing;
|
||||
thing->ontick = LogicalDeviceThing_ontick;
|
||||
thing->ondrag = DeviceThing_ondrag;
|
||||
thing->ondrop = LogicalDeviceThing_ondrop;
|
||||
thing->ondraw = LogicalDeviceThing_ondraw;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
if (thing) {
|
||||
thing->data.logdev.devid = which;
|
||||
thing->data.logdev.iscapture = iscapture;
|
||||
thing->data.logdev.physdev = physthing;
|
||||
thing->data.logdev.visualizer = SDL_CreateTexture(state->renderers[0], SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, VISUALIZER_WIDTH, VISUALIZER_HEIGHT);
|
||||
thing->data.logdev.postmix_lock = SDL_CreateMutex();
|
||||
if (thing->data.logdev.visualizer) {
|
||||
SDL_SetTextureBlendMode(thing->data.logdev.visualizer, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
thing->line_connected_to = physthing;
|
||||
thing->ontick = LogicalDeviceThing_ontick;
|
||||
thing->ondrag = DeviceThing_ondrag;
|
||||
thing->ondrop = LogicalDeviceThing_ondrop;
|
||||
thing->ondraw = LogicalDeviceThing_ondraw;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
|
||||
SetLogicalDeviceTitlebar(thing);
|
||||
SetLogicalDeviceTitlebar(thing);
|
||||
}
|
||||
return thing;
|
||||
}
|
||||
|
||||
@@ -1002,21 +970,23 @@ static Thing *CreatePhysicalDeviceThing(const SDL_AudioDeviceID which, const SDL
|
||||
|
||||
SDL_Log("Adding physical audio device %u", (unsigned int) which);
|
||||
thing = CreateThing(iscapture ? THING_PHYSDEV_CAPTURE : THING_PHYSDEV, next_physdev_x, 170, 5, -1, -1, physdev_texture, NULL);
|
||||
thing->data.physdev.devid = which;
|
||||
thing->data.physdev.iscapture = iscapture;
|
||||
thing->data.physdev.name = SDL_GetAudioDeviceName(which);
|
||||
thing->ondrag = DeviceThing_ondrag;
|
||||
thing->ondrop = PhysicalDeviceThing_ondrop;
|
||||
thing->ontick = PhysicalDeviceThing_ontick;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
if (thing) {
|
||||
thing->data.physdev.devid = which;
|
||||
thing->data.physdev.iscapture = iscapture;
|
||||
thing->data.physdev.name = SDL_GetAudioDeviceName(which);
|
||||
thing->ondrag = DeviceThing_ondrag;
|
||||
thing->ondrop = PhysicalDeviceThing_ondrop;
|
||||
thing->ontick = PhysicalDeviceThing_ontick;
|
||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||
|
||||
SetPhysicalDeviceTitlebar(thing);
|
||||
if (SDL_GetTicks() <= (app_ready_ticks + 2000)) { /* assume this is the initial batch if it happens in the first two seconds. */
|
||||
RepositionRowOfThings(THING_PHYSDEV, 10.0f); /* don't rearrange them after the initial add. */
|
||||
RepositionRowOfThings(THING_PHYSDEV_CAPTURE, 170.0f); /* don't rearrange them after the initial add. */
|
||||
next_physdev_x = 0.0f;
|
||||
} else {
|
||||
next_physdev_x += physdev_texture->w * 1.5f;
|
||||
SetPhysicalDeviceTitlebar(thing);
|
||||
if (SDL_GetTicks() <= (app_ready_ticks + 2000)) { /* assume this is the initial batch if it happens in the first two seconds. */
|
||||
RepositionRowOfThings(THING_PHYSDEV, 10.0f); /* don't rearrange them after the initial add. */
|
||||
RepositionRowOfThings(THING_PHYSDEV_CAPTURE, 170.0f); /* don't rearrange them after the initial add. */
|
||||
next_physdev_x = 0.0f;
|
||||
} else {
|
||||
next_physdev_x += physdev_texture->w * 1.5f;
|
||||
}
|
||||
}
|
||||
|
||||
return thing;
|
||||
@@ -1066,157 +1036,13 @@ static void WindowResized(const int newwinw, const int newwinh)
|
||||
state->window_h = newwinh;
|
||||
}
|
||||
|
||||
|
||||
static void Loop(void)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_bool saw_event = SDL_FALSE;
|
||||
|
||||
if (app_ready_ticks == 0) {
|
||||
app_ready_ticks = SDL_GetTicks();
|
||||
}
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
Thing *thing = NULL;
|
||||
|
||||
saw_event = SDL_TRUE;
|
||||
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
thing = UpdateMouseOver(event.motion.x, event.motion.y);
|
||||
if ((dragging_button == -1) && event.motion.state) {
|
||||
if (event.motion.state & SDL_BUTTON_LMASK) {
|
||||
/* for people that don't have all three buttons... */
|
||||
if (ctrl_held) {
|
||||
dragging_button = SDL_BUTTON_RIGHT;
|
||||
} else if (alt_held) {
|
||||
dragging_button = SDL_BUTTON_MIDDLE;
|
||||
} else {
|
||||
dragging_button = SDL_BUTTON_LEFT;
|
||||
}
|
||||
dragging_button_real = SDL_BUTTON_LEFT;
|
||||
} else if (event.motion.state & SDL_BUTTON_RMASK) {
|
||||
dragging_button = SDL_BUTTON_RIGHT;
|
||||
dragging_button_real = SDL_BUTTON_RIGHT;
|
||||
} else if (event.motion.state & SDL_BUTTON_MMASK) {
|
||||
dragging_button = SDL_BUTTON_MIDDLE;
|
||||
dragging_button_real = SDL_BUTTON_MIDDLE;
|
||||
}
|
||||
|
||||
|
||||
if (dragging_button != -1) {
|
||||
dragging_thing = thing;
|
||||
if (thing && thing->ondrag) {
|
||||
thing->ondrag(thing, dragging_button, event.motion.x, event.motion.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
droppable_highlighted_thing = NULL;
|
||||
if (dragging_thing) {
|
||||
dragging_thing->rect.x = event.motion.x - (dragging_thing->rect.w / 2);
|
||||
dragging_thing->rect.y = event.motion.y - (dragging_thing->rect.h / 2);
|
||||
if (dragging_thing->can_be_dropped_onto) {
|
||||
thing = FindThingAtPoint(event.motion.x, event.motion.y);
|
||||
if (thing) {
|
||||
int i;
|
||||
for (i = 0; dragging_thing->can_be_dropped_onto[i]; i++) {
|
||||
if (dragging_thing->can_be_dropped_onto[i] == thing->what) {
|
||||
droppable_highlighted_thing = thing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
thing = UpdateMouseOver(event.button.x, event.button.y);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
if (dragging_button_real == event.button.button) {
|
||||
Thing *dropped_thing = dragging_thing;
|
||||
dragging_thing = NULL;
|
||||
dragging_button = -1;
|
||||
dragging_button_real = -1;
|
||||
if (dropped_thing && dropped_thing->ondrop) {
|
||||
dropped_thing->ondrop(dropped_thing, event.button.button, event.button.x, event.button.y);
|
||||
}
|
||||
droppable_highlighted_thing = NULL;
|
||||
}
|
||||
thing = UpdateMouseOver(event.button.x, event.button.y);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
UpdateMouseOver(event.wheel.mouseX, event.wheel.mouseY);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
ctrl_held = ((event.key.keysym.mod & SDL_KMOD_CTRL) != 0) ? SDL_TRUE : SDL_FALSE;
|
||||
alt_held = ((event.key.keysym.mod & SDL_KMOD_ALT) != 0) ? SDL_TRUE : SDL_FALSE;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_DROP_FILE:
|
||||
SDL_Log("Drop file! '%s'", event.drop.file);
|
||||
LoadWavThing(event.drop.file, event.drop.x, event.drop.y);
|
||||
/* SDLTest_CommonEvent will free the string, below. */
|
||||
break;
|
||||
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
WindowResized(event.window.data1, event.window.data2);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_AUDIO_DEVICE_ADDED:
|
||||
CreatePhysicalDeviceThing(event.adevice.which, event.adevice.iscapture);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_AUDIO_DEVICE_REMOVED: {
|
||||
const SDL_AudioDeviceID which = event.adevice.which;
|
||||
Thing *i, *next;
|
||||
SDL_Log("Removing audio device %u", (unsigned int) which);
|
||||
for (i = things; i != NULL; i = next) {
|
||||
next = i->next;
|
||||
if (((i->what == THING_PHYSDEV) || (i->what == THING_PHYSDEV_CAPTURE)) && (i->data.physdev.devid == which)) {
|
||||
TrashThing(i);
|
||||
next = things; /* in case we mangled the list. */
|
||||
} else if (((i->what == THING_LOGDEV) || (i->what == THING_LOGDEV_CAPTURE)) && (i->data.logdev.devid == which)) {
|
||||
TrashThing(i);
|
||||
next = things; /* in case we mangled the list. */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
SDLTest_CommonEvent(state, &event, &done);
|
||||
}
|
||||
|
||||
TickThings();
|
||||
Draw();
|
||||
|
||||
if (!saw_event) {
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (done) {
|
||||
emscripten_cancel_main_loop();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int SDL_AppInit(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO | SDL_INIT_AUDIO);
|
||||
if (state == NULL) {
|
||||
Quit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->window_flags |= SDL_WINDOW_RESIZABLE;
|
||||
@@ -1234,13 +1060,13 @@ int main(int argc, char *argv[])
|
||||
NULL
|
||||
};
|
||||
SDLTest_CommonLogUsage(state, argv[0], options);
|
||||
Quit(1);
|
||||
return -1;
|
||||
}
|
||||
i += consumed;
|
||||
}
|
||||
|
||||
if (!SDLTest_CommonInit(state)) {
|
||||
Quit(2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (state->audio_id) {
|
||||
@@ -1250,27 +1076,174 @@ int main(int argc, char *argv[])
|
||||
|
||||
SetDefaultTitleBar();
|
||||
|
||||
physdev_texture = CreateTexture("physaudiodev.bmp");
|
||||
logdev_texture = CreateTexture("logaudiodev.bmp");
|
||||
audio_texture = CreateTexture("audiofile.bmp");
|
||||
trashcan_texture = CreateTexture("trashcan.bmp");
|
||||
soundboard_texture = CreateTexture("soundboard.bmp");
|
||||
soundboard_levels_texture = CreateTexture("soundboard_levels.bmp");
|
||||
if ((physdev_texture = CreateTexture("physaudiodev.bmp")) == NULL) { return -1; }
|
||||
if ((logdev_texture = CreateTexture("logaudiodev.bmp")) == NULL) { return -1; }
|
||||
if ((audio_texture = CreateTexture("audiofile.bmp")) == NULL) { return -1; }
|
||||
if ((trashcan_texture = CreateTexture("trashcan.bmp")) == NULL) { return -1; }
|
||||
if ((soundboard_texture = CreateTexture("soundboard.bmp")) == NULL) { return -1; }
|
||||
if ((soundboard_levels_texture = CreateTexture("soundboard_levels.bmp")) == NULL) { return -1; }
|
||||
|
||||
LoadStockWavThings();
|
||||
CreateTrashcanThing();
|
||||
CreateDefaultPhysicalDevice(SDL_FALSE);
|
||||
CreateDefaultPhysicalDevice(SDL_TRUE);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop(Loop, 0, 1);
|
||||
#else
|
||||
while (!done) {
|
||||
Loop();
|
||||
}
|
||||
#endif
|
||||
|
||||
Quit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static SDL_bool saw_event = SDL_FALSE;
|
||||
|
||||
int SDL_AppEvent(const SDL_Event *event)
|
||||
{
|
||||
Thing *thing = NULL;
|
||||
|
||||
saw_event = SDL_TRUE;
|
||||
|
||||
switch (event->type) {
|
||||
case SDL_EVENT_MOUSE_MOTION:
|
||||
thing = UpdateMouseOver(event->motion.x, event->motion.y);
|
||||
if ((dragging_button == -1) && event->motion.state) {
|
||||
if (event->motion.state & SDL_BUTTON_LMASK) {
|
||||
/* for people that don't have all three buttons... */
|
||||
if (ctrl_held) {
|
||||
dragging_button = SDL_BUTTON_RIGHT;
|
||||
} else if (alt_held) {
|
||||
dragging_button = SDL_BUTTON_MIDDLE;
|
||||
} else {
|
||||
dragging_button = SDL_BUTTON_LEFT;
|
||||
}
|
||||
dragging_button_real = SDL_BUTTON_LEFT;
|
||||
} else if (event->motion.state & SDL_BUTTON_RMASK) {
|
||||
dragging_button = SDL_BUTTON_RIGHT;
|
||||
dragging_button_real = SDL_BUTTON_RIGHT;
|
||||
} else if (event->motion.state & SDL_BUTTON_MMASK) {
|
||||
dragging_button = SDL_BUTTON_MIDDLE;
|
||||
dragging_button_real = SDL_BUTTON_MIDDLE;
|
||||
}
|
||||
|
||||
if (dragging_button != -1) {
|
||||
dragging_thing = thing;
|
||||
if (thing && thing->ondrag) {
|
||||
thing->ondrag(thing, dragging_button, event->motion.x, event->motion.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
droppable_highlighted_thing = NULL;
|
||||
if (dragging_thing) {
|
||||
dragging_thing->rect.x = event->motion.x - (dragging_thing->rect.w / 2);
|
||||
dragging_thing->rect.y = event->motion.y - (dragging_thing->rect.h / 2);
|
||||
if (dragging_thing->can_be_dropped_onto) {
|
||||
thing = FindThingAtPoint(event->motion.x, event->motion.y);
|
||||
if (thing) {
|
||||
int i;
|
||||
for (i = 0; dragging_thing->can_be_dropped_onto[i]; i++) {
|
||||
if (dragging_thing->can_be_dropped_onto[i] == thing->what) {
|
||||
droppable_highlighted_thing = thing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
thing = UpdateMouseOver(event->button.x, event->button.y);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
if (dragging_button_real == event->button.button) {
|
||||
Thing *dropped_thing = dragging_thing;
|
||||
dragging_thing = NULL;
|
||||
dragging_button = -1;
|
||||
dragging_button_real = -1;
|
||||
if (dropped_thing && dropped_thing->ondrop) {
|
||||
dropped_thing->ondrop(dropped_thing, event->button.button, event->button.x, event->button.y);
|
||||
}
|
||||
droppable_highlighted_thing = NULL;
|
||||
}
|
||||
thing = UpdateMouseOver(event->button.x, event->button.y);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
UpdateMouseOver(event->wheel.mouseX, event->wheel.mouseY);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
ctrl_held = ((event->key.keysym.mod & SDL_KMOD_CTRL) != 0) ? SDL_TRUE : SDL_FALSE;
|
||||
alt_held = ((event->key.keysym.mod & SDL_KMOD_ALT) != 0) ? SDL_TRUE : SDL_FALSE;
|
||||
break;
|
||||
|
||||
case SDL_EVENT_DROP_FILE:
|
||||
SDL_Log("Drop file! '%s'", event->drop.file);
|
||||
LoadWavThing(event->drop.file, event->drop.x, event->drop.y);
|
||||
/* SDL frees event->drop.file for you when you use SDL_AppEvent(). */
|
||||
break;
|
||||
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
WindowResized(event->window.data1, event->window.data2);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_AUDIO_DEVICE_ADDED:
|
||||
CreatePhysicalDeviceThing(event->adevice.which, event->adevice.iscapture);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_AUDIO_DEVICE_REMOVED: {
|
||||
const SDL_AudioDeviceID which = event->adevice.which;
|
||||
Thing *i, *next;
|
||||
SDL_Log("Removing audio device %u", (unsigned int) which);
|
||||
for (i = things; i != NULL; i = next) {
|
||||
next = i->next;
|
||||
if (((i->what == THING_PHYSDEV) || (i->what == THING_PHYSDEV_CAPTURE)) && (i->data.physdev.devid == which)) {
|
||||
TrashThing(i);
|
||||
next = things; /* in case we mangled the list. */
|
||||
} else if (((i->what == THING_LOGDEV) || (i->what == THING_LOGDEV_CAPTURE)) && (i->data.logdev.devid == which)) {
|
||||
TrashThing(i);
|
||||
next = things; /* in case we mangled the list. */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return SDLTest_CommonEventMainCallbacks(state, event);
|
||||
}
|
||||
|
||||
int SDL_AppIterate(void)
|
||||
{
|
||||
if (app_ready_ticks == 0) {
|
||||
app_ready_ticks = SDL_GetTicks();
|
||||
}
|
||||
|
||||
TickThings();
|
||||
Draw();
|
||||
|
||||
if (saw_event) {
|
||||
saw_event = SDL_FALSE; /* reset this so we know when SDL_AppEvent() runs again */
|
||||
} else {
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
return 0; /* keep going. */
|
||||
}
|
||||
|
||||
void SDL_AppQuit(void)
|
||||
{
|
||||
while (things != NULL) {
|
||||
DestroyThing(things); /* make sure all the audio devices are closed, etc. */
|
||||
}
|
||||
|
||||
DestroyTexture(physdev_texture);
|
||||
DestroyTexture(logdev_texture);
|
||||
DestroyTexture(audio_texture);
|
||||
DestroyTexture(trashcan_texture);
|
||||
DestroyTexture(soundboard_texture);
|
||||
DestroyTexture(soundboard_levels_texture);
|
||||
SDLTest_CommonQuit(state);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,94 +10,20 @@
|
||||
freely.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <SDL3/SDL_test.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
static SDL_Window *window = NULL;
|
||||
static SDL_Renderer *renderer = NULL;
|
||||
static SDL_AudioStream *stream_in = NULL;
|
||||
static SDL_AudioStream *stream_out = NULL;
|
||||
static int done = 0;
|
||||
static SDLTest_CommonState *state = NULL;
|
||||
|
||||
static void loop(void)
|
||||
{
|
||||
const SDL_AudioDeviceID devid_in = SDL_GetAudioStreamDevice(stream_in);
|
||||
const SDL_AudioDeviceID devid_out = SDL_GetAudioStreamDevice(stream_out);
|
||||
SDL_bool please_quit = SDL_FALSE;
|
||||
SDL_Event e;
|
||||
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (e.type == SDL_EVENT_QUIT) {
|
||||
please_quit = SDL_TRUE;
|
||||
} else if (e.type == SDL_EVENT_KEY_DOWN) {
|
||||
if (e.key.keysym.sym == SDLK_ESCAPE) {
|
||||
please_quit = SDL_TRUE;
|
||||
}
|
||||
} else if (e.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||
if (e.button.button == 1) {
|
||||
SDL_PauseAudioDevice(devid_out);
|
||||
SDL_ResumeAudioDevice(devid_in);
|
||||
}
|
||||
} else if (e.type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||
if (e.button.button == 1) {
|
||||
SDL_PauseAudioDevice(devid_in);
|
||||
SDL_FlushAudioStream(stream_in); /* so no samples are held back for resampling purposes. */
|
||||
SDL_ResumeAudioDevice(devid_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SDL_AudioDevicePaused(devid_in)) {
|
||||
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||
} else {
|
||||
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||
}
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* Feed any new data we captured to the output stream. It'll play when we unpause the device. */
|
||||
while (!please_quit && (SDL_GetAudioStreamAvailable(stream_in) > 0)) {
|
||||
Uint8 buf[1024];
|
||||
const int br = SDL_GetAudioStreamData(stream_in, buf, sizeof(buf));
|
||||
if (br < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read from input audio stream: %s\n", SDL_GetError());
|
||||
please_quit = 1;
|
||||
} else if (SDL_PutAudioStreamData(stream_out, buf, br) < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to write to output audio stream: %s\n", SDL_GetError());
|
||||
please_quit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (please_quit) {
|
||||
/* stop playing back, quit. */
|
||||
SDL_Log("Shutting down.\n");
|
||||
SDL_CloseAudioDevice(devid_in);
|
||||
SDL_CloseAudioDevice(devid_out);
|
||||
SDL_DestroyAudioStream(stream_in);
|
||||
SDL_DestroyAudioStream(stream_out);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_cancel_main_loop();
|
||||
#endif
|
||||
/* Let 'main()' return normally */
|
||||
done = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int SDL_AppInit(int argc, char **argv)
|
||||
{
|
||||
SDL_AudioDeviceID *devices;
|
||||
SDLTest_CommonState *state;
|
||||
SDL_AudioSpec outspec;
|
||||
SDL_AudioSpec inspec;
|
||||
SDL_AudioDeviceID device;
|
||||
@@ -105,6 +31,9 @@ int main(int argc, char **argv)
|
||||
const char *devname = NULL;
|
||||
int i;
|
||||
|
||||
/* this doesn't have to run very much, so give up tons of CPU time between iterations. */
|
||||
SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "15");
|
||||
|
||||
/* Initialize test framework */
|
||||
state = SDLTest_CommonCreateState(argv, 0);
|
||||
if (state == NULL) {
|
||||
@@ -128,7 +57,7 @@ int main(int argc, char **argv)
|
||||
if (consumed <= 0) {
|
||||
static const char *options[] = { "[device_name]", NULL };
|
||||
SDLTest_CommonLogUsage(state, argv[0], options);
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
i += consumed;
|
||||
@@ -175,20 +104,17 @@ int main(int argc, char **argv)
|
||||
device = SDL_OpenAudioDevice(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, NULL);
|
||||
if (!device) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
SDL_PauseAudioDevice(device);
|
||||
SDL_GetAudioDeviceFormat(device, &outspec, NULL);
|
||||
stream_out = SDL_CreateAudioStream(&outspec, &outspec);
|
||||
if (!stream_out) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for playback: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
} else if (SDL_BindAudioStream(device, stream_out) == -1) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for playback: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Log("Opening capture device %s%s%s...\n",
|
||||
@@ -199,38 +125,89 @@ int main(int argc, char **argv)
|
||||
device = SDL_OpenAudioDevice(want_device, NULL);
|
||||
if (!device) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
SDL_PauseAudioDevice(device);
|
||||
SDL_GetAudioDeviceFormat(device, &inspec, NULL);
|
||||
stream_in = SDL_CreateAudioStream(&inspec, &inspec);
|
||||
if (!stream_in) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for capture: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
} else if (SDL_BindAudioStream(device, stream_in) == -1) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't bind an audio stream for capture: %s!\n", SDL_GetError());
|
||||
SDL_Quit();
|
||||
exit(1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_SetAudioStreamFormat(stream_in, NULL, &outspec); /* make sure we output at the playback format. */
|
||||
|
||||
SDL_Log("Ready! Hold down mouse or finger to record!\n");
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop(loop, 0, 1);
|
||||
#else
|
||||
while (!done) {
|
||||
loop();
|
||||
if (!done) {
|
||||
SDL_Delay(16);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SDLTest_CommonDestroyState(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDL_AppEvent(const SDL_Event *event)
|
||||
{
|
||||
if (event->type == SDL_EVENT_QUIT) {
|
||||
return 1; /* terminate as success. */
|
||||
} else if (event->type == SDL_EVENT_KEY_DOWN) {
|
||||
if (event->key.keysym.sym == SDLK_ESCAPE) {
|
||||
return 1; /* terminate as success. */
|
||||
}
|
||||
} else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||
if (event->button.button == 1) {
|
||||
SDL_PauseAudioDevice(SDL_GetAudioStreamDevice(stream_out));
|
||||
SDL_FlushAudioStream(stream_out); /* so no samples are held back for resampling purposes. */
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream_in));
|
||||
}
|
||||
} else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
||||
if (event->button.button == 1) {
|
||||
SDL_PauseAudioDevice(SDL_GetAudioStreamDevice(stream_in));
|
||||
SDL_FlushAudioStream(stream_in); /* so no samples are held back for resampling purposes. */
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(stream_out));
|
||||
}
|
||||
}
|
||||
return 0; /* keep going. */
|
||||
}
|
||||
|
||||
int SDL_AppIterate(void)
|
||||
{
|
||||
if (!SDL_AudioDevicePaused(SDL_GetAudioStreamDevice(stream_in))) {
|
||||
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
|
||||
} else {
|
||||
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
|
||||
}
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
|
||||
/* Feed any new data we captured to the output stream. It'll play when we unpause the device. */
|
||||
while (SDL_GetAudioStreamAvailable(stream_in) > 0) {
|
||||
Uint8 buf[1024];
|
||||
const int br = SDL_GetAudioStreamData(stream_in, buf, sizeof(buf));
|
||||
if (br < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to read from input audio stream: %s\n", SDL_GetError());
|
||||
return -1; /* quit the app, report failure. */
|
||||
} else if (SDL_PutAudioStreamData(stream_out, buf, br) < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to write to output audio stream: %s\n", SDL_GetError());
|
||||
return -1; /* quit the app, report failure. */
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* keep app going. */
|
||||
}
|
||||
|
||||
void SDL_AppQuit(void)
|
||||
{
|
||||
SDL_Log("Shutting down.\n");
|
||||
const SDL_AudioDeviceID devid_in = SDL_GetAudioStreamDevice(stream_in);
|
||||
const SDL_AudioDeviceID devid_out = SDL_GetAudioStreamDevice(stream_out);
|
||||
SDL_CloseAudioDevice(devid_in); /* !!! FIXME: use SDL_OpenAudioDeviceStream instead so we can dump this. */
|
||||
SDL_CloseAudioDevice(devid_out);
|
||||
SDL_DestroyAudioStream(stream_in);
|
||||
SDL_DestroyAudioStream(stream_out);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDLTest_CommonDestroyState(state);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
#include <SDL3/SDL_test.h>
|
||||
#include <SDL3/SDL_test_common.h>
|
||||
#include <SDL3/SDL_main.h>
|
||||
@@ -48,20 +45,12 @@ static SDL_bool suspend_when_occluded;
|
||||
/* -1: infinite random moves (default); >=0: enables N deterministic moves */
|
||||
static int iterations = -1;
|
||||
|
||||
static int done;
|
||||
|
||||
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
|
||||
static void
|
||||
quit(int rc)
|
||||
void SDL_AppQuit(void)
|
||||
{
|
||||
SDL_free(sprites);
|
||||
SDL_free(positions);
|
||||
SDL_free(velocities);
|
||||
SDLTest_CommonQuit(state);
|
||||
/* Let 'main()' return normally */
|
||||
if (rc != 0) {
|
||||
exit(rc);
|
||||
}
|
||||
}
|
||||
|
||||
static int LoadSprite(const char *file)
|
||||
@@ -395,17 +384,17 @@ static void MoveSprites(SDL_Renderer *renderer, SDL_Texture *sprite)
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
static void loop(void)
|
||||
int SDL_AppEvent(const SDL_Event *event)
|
||||
{
|
||||
return SDLTest_CommonEventMainCallbacks(state, event);
|
||||
}
|
||||
|
||||
int SDL_AppIterate(void)
|
||||
{
|
||||
Uint64 now;
|
||||
int i;
|
||||
int active_windows = 0;
|
||||
SDL_Event event;
|
||||
|
||||
/* Check for events */
|
||||
while (SDL_PollEvent(&event)) {
|
||||
SDLTest_CommonEvent(state, &event, &done);
|
||||
}
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
if (state->windows[i] == NULL ||
|
||||
(suspend_when_occluded && (SDL_GetWindowFlags(state->windows[i]) & SDL_WINDOW_OCCLUDED))) {
|
||||
@@ -414,14 +403,9 @@ static void loop(void)
|
||||
++active_windows;
|
||||
MoveSprites(state->renderers[i], sprites[i]);
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (done) {
|
||||
emscripten_cancel_main_loop();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If all windows are occluded, throttle the event polling to 15hz. */
|
||||
if (!done && !active_windows) {
|
||||
if (!active_windows) {
|
||||
SDL_DelayNS(SDL_NS_PER_SECOND / 15);
|
||||
}
|
||||
|
||||
@@ -435,9 +419,11 @@ static void loop(void)
|
||||
next_fps_check = now + fps_check_delay;
|
||||
frames = 0;
|
||||
}
|
||||
|
||||
return 0; /* keep going */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int SDL_AppInit(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
Uint64 seed;
|
||||
@@ -449,7 +435,7 @@ int main(int argc, char *argv[])
|
||||
/* Initialize test framework */
|
||||
state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
|
||||
if (state == NULL) {
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
@@ -532,12 +518,12 @@ int main(int argc, char *argv[])
|
||||
NULL
|
||||
};
|
||||
SDLTest_CommonLogUsage(state, argv[0], options);
|
||||
quit(1);
|
||||
return -1;
|
||||
}
|
||||
i += consumed;
|
||||
}
|
||||
if (!SDLTest_CommonInit(state)) {
|
||||
quit(2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the windows, initialize the renderers, and load the textures */
|
||||
@@ -545,7 +531,7 @@ int main(int argc, char *argv[])
|
||||
(SDL_Texture **)SDL_malloc(state->num_windows * sizeof(*sprites));
|
||||
if (sprites == NULL) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
|
||||
quit(2);
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < state->num_windows; ++i) {
|
||||
SDL_Renderer *renderer = state->renderers[i];
|
||||
@@ -553,7 +539,7 @@ int main(int argc, char *argv[])
|
||||
SDL_RenderClear(renderer);
|
||||
}
|
||||
if (LoadSprite(icon) < 0) {
|
||||
quit(2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory for the sprite info */
|
||||
@@ -561,7 +547,7 @@ int main(int argc, char *argv[])
|
||||
velocities = (SDL_FRect *)SDL_malloc(num_sprites * sizeof(*velocities));
|
||||
if (positions == NULL || velocities == NULL) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
|
||||
quit(2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Position sprites and set their velocities using the fuzzer */
|
||||
@@ -586,19 +572,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Main render loop */
|
||||
/* Main render loop in SDL_AppIterate will begin when this function returns. */
|
||||
frames = 0;
|
||||
next_fps_check = SDL_GetTicks() + fps_check_delay;
|
||||
done = 0;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop(loop, 0, 1);
|
||||
#else
|
||||
while (!done) {
|
||||
loop();
|
||||
}
|
||||
#endif
|
||||
|
||||
quit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user