#include "3dmodelio/TextureAtlasData.h" #include "audioplayer/AudioPlayer.h" #include "gamemath/MouseCoordinateTransforms.h" #include "font/BitmapFont.h" #include "gamemath/TextureAtlas.h" #include "jsonserialization/JSONDeserializationContext.h" #include "nativeaudio/AudioOut.h" #include "pngimageio/PNGImageIO.h" #include "renderer/Renderable.h" #include "renderer/Renderer.h" #include "resourcemanager/ResourceManager.h" #include "shadercollection/ShaderCollection.h" #include "shadercollection/ShaderConfiguration2DTexture.h" #include "shell/Shell.h" #include "shell/ShellCallbacks.h" #include "shell/ShellKeyCodes.h" #include "uitoolkit/UIAppearance.h" #include "uitoolkit/UIButton.h" #include "uitoolkit/UIContainer.h" #include "uitoolkit/UIDrawingInterface2DTexture.h" #include "uitoolkit/UIToolkitAppearance.h" #include "uitoolkit/UIToolkitContext.h" #include "uitoolkit/UITypeface_BitmapFont.h" #include "utilities/IOUtilities.h" #include "vorbisaudioio/VorbisAudioIO.h" #if defined(STEM_PLATFORM_macosx) #include "nsopenglshell/NSOpenGLShell.h" #include "nsopenglshell/NSOpenGLTarget.h" #elif defined(STEM_PLATFORM_iphonesimulator) || defined(STEM_PLATFORM_iphoneos) #include "eaglshell/EAGLShell.h" #include "eaglshell/EAGLTarget.h" #elif defined(STEM_PLATFORM_windows) #include "wglshell/WGLShell.h" #include "wglshell/WGLTarget.h" #elif defined(STEM_PLATFORM_linux) #include "glxshell/GLXShell.h" #include "glxshell/GLXTarget.h" #elif defined(STEM_PLATFORM_android) #include "eglshell/EGLShell.h" #include "eglshell/EGLTarget.h" #else #error Unsupported platform #endif #include #include #include #include #ifdef WIN32 #include #define sleep(seconds) Sleep((seconds) * 1000) #endif Atom ATOM_vorbis = "vorbis"; static ResourceManager * resourceManager; static Renderer * renderer; static RenderLayer * renderLayer; static ShaderConfiguration2DTexture * shaderConfiguration; static unsigned int viewWidth = 800, viewHeight = 480; static float viewRatio = 4.0f / 3.0f; static float scaleFactor = 1.0f; static UIElement * rootElement; static UIToolkitContext uiContext; static UIDrawingInterface2DTexture * drawingInterface; static UIAppearance appearance; static Texture * texture; static TextureAtlas * atlas; static BitmapFont * font; static UIButton * stream1Button, * stream2Button, * pauseButton; static unsigned int effect1InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE, effect2InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE, stream1InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE, stream2InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE; static PCMAudioStream lowLatencyStream, highLatencyStream; static float category0Volume = 1.0f, category1Volume = 1.0f; static bool Target_draw(double referenceTime, double activeDrawDelta) { Renderer_clear(renderer, COLOR4f(1.0f, 1.0f, 1.0f, 0.0f)); Renderer_drawLayer(renderer, renderLayer, referenceTime, activeDrawDelta); AudioPlayer_run(); if (stream1InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE && !AudioPlayer_isAudioStreamPlaying(stream1InstanceID)) { stream1InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE; UIButton_setText(stream1Button, STRL("Start stream 1")); } if (stream2InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE && !AudioPlayer_isAudioStreamPlaying(stream2InstanceID)) { stream2InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE; UIButton_setText(stream2Button, STRL("Start stream 2")); } if (call_virtual(needsRedraw, rootElement) || AudioPlayer_isAnyAudioPlaying()) { Shell_redisplay(); } return true; } static void Target_keyDown(unsigned int charCode, unsigned int keyCode, unsigned int modifiers, bool isRepeat, double referenceTime) { if (keyCode == KEY_CODE_Q && (modifiers & MODIFIER_PLATFORM_MENU_COMMAND_BIT)) { exit(EXIT_SUCCESS); } } static Vector2f transformMousePosition(float x, float y) { return VECTOR2f(x / scaleFactor, (viewHeight - y) / scaleFactor); } static void Target_mouseDown(unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifierFlags, double referenceTime) { Vector2f position = transformMousePosition(x, y); if (call_virtual(mouseDown, rootElement, buttonNumber, buttonMask, position.x, position.y, modifierFlags, false, referenceTime)) { Shell_redisplay(); } } static void Target_mouseUp(unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifierFlags, double referenceTime) { Vector2f position = transformMousePosition(x, y); if (call_virtual(mouseUp, rootElement, buttonNumber, buttonMask, position.x, position.y, modifierFlags, referenceTime)) { Shell_redisplay(); } } static void Target_mouseMoved(float x, float y, float deltaX, float deltaY, unsigned int modifierFlags, double referenceTime) { Vector2f position = transformMousePosition(x, y); if (call_virtual(mouseMoved, rootElement, position.x, position.y, deltaX, deltaY, modifierFlags, referenceTime)) { Shell_redisplay(); } } static void Target_mouseDragged(unsigned int buttonMask, float x, float y, float deltaX, float deltaY, unsigned int modifierFlags, double referenceTime) { Vector2f position = transformMousePosition(x, y); if (call_virtual(mouseDragged, rootElement, buttonMask, position.x, position.y, deltaX, deltaY, modifierFlags, referenceTime)) { Shell_redisplay(); } } static void Target_resized(unsigned int newWidth, unsigned int newHeight, double referenceTime) { viewWidth = newWidth; viewHeight = newHeight; viewRatio = (float) newWidth / newHeight; scaleFactor = Shell_getDisplayScaleFactor(Shell_getDisplayIndexFromWindow()); if (renderer != NULL) { Renderer_setViewport(renderer, 0, 0, viewWidth, viewHeight, NULL); call_virtual(setProjectionMatrix, shaderConfiguration, Matrix4x4f_ortho(MATRIX4x4f_IDENTITY, 0.0f, viewWidth / scaleFactor, 0.0f, viewHeight / scaleFactor, -1.0f, 1.0f)); drawingInterface->scaleFactor = scaleFactor; } } static void Target_backgrounded(double referenceTime) { //AudioPlayer_pause(); } static void Target_foregrounded(double referenceTime) { //AudioPlayer_unpause(); } static void effect1ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { effect1InstanceID = AudioPlayer_playSoundEffect(ATOM("effect1.ogg"), 0); } static void effect2ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { effect2InstanceID = AudioPlayer_playSoundEffect(ATOM("effect2.ogg"), 1); } static void stopEffect1ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { if (effect1InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE) { AudioPlayer_cancelSoundEffect(effect1InstanceID); effect1InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE; } } static void stopEffect2ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { if (effect2InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE) { AudioPlayer_cancelSoundEffect(effect2InstanceID); effect2InstanceID = AUDIO_PLAYER_INSTANCE_ID_NONE; } } static void stopAllEffectsButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { AudioPlayer_cancelAllSoundEffects(); } static void playGroupButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { AudioPlayer_beginPlayGroup(); effect1InstanceID = AudioPlayer_playSoundEffect(ATOM("effect1.ogg"), 0); sleep(1); effect2InstanceID = AudioPlayer_playSoundEffect(ATOM("effect2.ogg"), 0); AudioPlayer_endPlayGroup(); } static void stream1ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { if (stream1InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE && AudioPlayer_isAudioStreamPlaying(stream1InstanceID)) { AudioPlayer_stopAudioStream(stream1InstanceID); UIButton_setText(stream1Button, STRL("Start stream 1")); } else { stream1InstanceID = AudioPlayer_startAudioStream(&lowLatencyStream, true, true, 0, NULL, NULL); UIButton_setText(stream1Button, STRL("Stop stream 1")); } } static void stream2ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { if (stream2InstanceID != AUDIO_PLAYER_INSTANCE_ID_NONE && AudioPlayer_isAudioStreamPlaying(stream2InstanceID)) { AudioPlayer_stopAudioStream(stream2InstanceID); UIButton_setText(stream2Button, STRL("Start stream 2")); } else { stream2InstanceID = AudioPlayer_startAudioStream(&highLatencyStream, true, false, 1, NULL, NULL); UIButton_setText(stream2Button, STRL("Stop stream 2")); } } static void stopAllStreamsButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { AudioPlayer_stopAllAudioStreams(); } static void pauseButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { if (AudioPlayer_isPaused()) { AudioPlayer_unpause(); UIButton_setText(pauseButton, STRL("Pause")); } else { AudioPlayer_pause(); UIButton_setText(pauseButton, STRL("Unpause")); } } static void category0ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { char buttonLabel[32]; if (category0Volume == 1.0f) { category0Volume = 0.5f; } else if (category0Volume == 0.5f) { category0Volume = 0.0f; } else { category0Volume = 1.0f; } AudioPlayer_setCategoryVolume(0, category0Volume); snprintf_safe(buttonLabel, sizeof(buttonLabel), "Category 0 volume: %.1f", category0Volume); UIButton_setText(button, STR(buttonLabel)); } static void category1ButtonCallback(UIButton * button, unsigned int modifiers, double referenceTime, void * context) { char buttonLabel[32]; if (category1Volume == 1.0f) { category1Volume = 0.5f; } else if (category1Volume == 0.5f) { category1Volume = 0.0f; } else { category1Volume = 1.0f; } AudioPlayer_setCategoryVolume(1, category1Volume); snprintf_safe(buttonLabel, sizeof(buttonLabel), "Category 1 volume: %.1f", category1Volume); UIButton_setText(button, STR(buttonLabel)); } static void registerShellCallbacks() { Shell_drawFunc(Target_draw); Shell_resizeFunc(Target_resized); Shell_keyDownFunc(Target_keyDown); Shell_mouseDownFunc(Target_mouseDown); Shell_mouseUpFunc(Target_mouseUp); Shell_mouseMovedFunc(Target_mouseMoved); Shell_mouseDraggedFunc(Target_mouseDragged); Shell_backgroundedFunc(Target_backgrounded); Shell_foregroundedFunc(Target_foregrounded); } static void * loadOggVorbis(const char * resourceName, void * context) { return VorbisAudioIO_loadOggVorbisFile(resourceName); } static void unloadOggVorbis(void * resource, void * context) { PCMAudio_dispose(resource); } static AudioFrameIndex lowLatencyReadCallback(PCMAudioStream * self, AudioFrameIndex frameCount, void * outBuffer, bool loop) { static AudioFrameIndex framesWrittenTotal; unsigned int frameIndex; int16_t * samples = outBuffer; float frameToSinAngle = M_PI * 2.0f / (self->sampleRate / 440.0f); float rangeMultiplier = 1 << (self->bytesPerSample * 8 - 1); AudioFrameIndex accumulatedFrameCount = framesWrittenTotal; for (frameIndex = 0; frameIndex < frameCount; frameIndex++) { samples[frameIndex] = sinf((accumulatedFrameCount + frameIndex) * frameToSinAngle) * 0.5f * rangeMultiplier; } framesWrittenTotal += frameCount; return frameCount; } static AudioFrameIndex highLatencyReadCallback(PCMAudioStream * self, AudioFrameIndex frameCount, void * outBuffer, bool loop) { static AudioFrameIndex framesWrittenTotal; unsigned int frameIndex; int16_t * samples = outBuffer; float frameToSinAngle = M_PI * 2.0f / (self->sampleRate / 880.0f); float rangeMultiplier = 1 << (self->bytesPerSample * 8 - 1); AudioFrameIndex accumulatedFrameCount = framesWrittenTotal; for (frameIndex = 0; frameIndex < frameCount; frameIndex++) { samples[frameIndex] = sinf((accumulatedFrameCount + frameIndex) * frameToSinAngle) * 0.5f * rangeMultiplier; } framesWrittenTotal += frameCount; return frameCount; } static void seekCallback(PCMAudioStream * self, AudioFrameIndex offset, int whence) { } #if defined(STEM_PLATFORM_macosx) void NSOpenGLTarget_configure(int argc, const char ** argv, struct NSOpenGLShellConfiguration * configuration) { configuration->windowTitle = "AudioPlayer Test Harness"; configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0); configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0); configuration->useGLCoreProfile = true; #elif defined(STEM_PLATFORM_iphonesimulator) || defined(STEM_PLATFORM_iphoneos) void EAGLTarget_configure(int argc, char ** argv, struct EAGLShellConfiguration * configuration) { #elif defined(STEM_PLATFORM_windows) void WGLTarget_configure(void * instance, void * prevInstance, char * commandLine, int command, int argc, const char ** argv, struct WGLShellConfiguration * configuration) { configuration->windowTitle = "AudioPlayer Test Harness"; configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0); configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0); configuration->useGLCoreProfile = true; #elif defined(STEM_PLATFORM_linux) void GLXTarget_configure(int argc, const char ** argv, struct GLXShellConfiguration * configuration) { configuration->windowTitle = "AudioPlayer Test Harness"; configuration->windowWidth = viewWidth * Shell_getDisplayScaleFactor(0); configuration->windowHeight = viewHeight * Shell_getDisplayScaleFactor(0); #elif defined(STEM_PLATFORM_android) void EGLTarget_configure(struct EGLShellConfiguration * configuration) { readResourceFile = EGLShell_readResourceFile; #else #error Unsupported platform #endif registerShellCallbacks(); } static PCMAudio * referenceAudioData(Atom identifier, void * context) { return ResourceManager_referenceResource(resourceManager, ATOM_vorbis, identifier); } static void releaseAudioData(Atom identifier, PCMAudio * data, void * context) { ResourceManager_releaseResource(resourceManager, data); } static void listRenderablesCallback(RenderableIO * renderableIO, void * context) { call_virtual(listRenderables, rootElement, renderableIO, 0, RECT4i_EMPTY); } void Target_init() { static struct PCMAudioStream_vtableStruct lowLatencyVtable, highLatencyVtable; chdir(Shell_getResourcePath()); Atom_registerStaticAddress(ATOM_vorbis); resourceManager = ResourceManager_create(Shell_getCurrentTime); ResourceManager_addTypeHandler(resourceManager, ATOM_vorbis, loadOggVorbis, unloadOggVorbis, PURGE_DEFERRED, resourceManager); AudioOut_sampleFormat sampleFormat = {2, 44100, 2}; AudioPlayer_init("audioplayer test harness", 8, 2, 2, sampleFormat, referenceAudioData, releaseAudioData, NULL); PCMAudioStream_init(&lowLatencyStream, 2, 1, 44100); lowLatencyVtable = PCMAudioStream_class; lowLatencyVtable.read = lowLatencyReadCallback; lowLatencyVtable.seek = seekCallback; lowLatencyStream.vtable = &lowLatencyVtable; PCMAudioStream_init(&highLatencyStream, 2, 1, 44100); highLatencyVtable = PCMAudioStream_class; highLatencyVtable.read = highLatencyReadCallback; highLatencyVtable.seek = seekCallback; highLatencyStream.vtable = &highLatencyVtable; renderer = Renderer_create(); renderLayer = RenderLayer_create(RENDER_LAYER_SORT_DRAW_ORDER_ONLY, listRenderablesCallback, NULL); shaderConfiguration = ShaderConfiguration2DTexture_create(ShaderCollection_get2DTextureShader()); call_virtual(setProjectionMatrix, shaderConfiguration, Matrix4x4f_ortho(MATRIX4x4f_IDENTITY, 0.0f, viewWidth / scaleFactor, 0.0f, viewHeight / scaleFactor, -1.0f, 1.0f)); JSONDeserializationContext * context; TextureAtlasData * atlasData; BitmapImage * image; UIContainer * container; UIButton * effect1Button, * effect2Button, * stopEffect1Button, * stopEffect2Button, * stopAllEffectsButton, * playGroupButton, * stopAllStreamsButton, * category0Button, * category1Button; context = JSONDeserializationContext_createWithResourceFile("interface.atlas"); if (context->status != SERIALIZATION_ERROR_OK) { fprintf(stderr, "Fatal error: Couldn't load interface.atlas (status %d)\n", context->status); exit(EXIT_FAILURE); } atlasData = TextureAtlasData_deserialize(context); call_virtual(dispose, context); if (atlasData == NULL) { fprintf(stderr, "Fatal error: Couldn't deserialize interface.atlas (status %d)\n", context->status); exit(EXIT_FAILURE); } image = PNGImageIO_loadPNGResourceFile("interface_atlas.png", BITMAP_PIXEL_FORMAT_RGBA_8888, true); if (image == NULL) { fprintf(stderr, "Fatal error: Couldn't load interface_atlas.png\n"); exit(EXIT_FAILURE); } texture = Texture_createWithTexels2D(image->pixels, image->width, image->height, 4, TEXEL_COMPONENT_UINT8_NORM, TEXEL_SWIZZLE_DEFAULT, TEXTURE_OPTION_MAGNIFY_NEAREST | TEXTURE_OPTION_MINIFY_NEAREST); atlas = TextureAtlasData_createTextureAtlas(atlasData, image->width, image->height); BitmapImage_dispose(image); TextureAtlasData_dispose(atlasData); context = JSONDeserializationContext_createWithResourceFile("15pt.bitmapfont"); if (context->status != SERIALIZATION_ERROR_OK) { fprintf(stderr, "Fatal error: Couldn't load 15pt.bitmapfont (status %d)\n", context->status); exit(EXIT_FAILURE); } font = BitmapFont_deserialize(context); call_virtual(dispose, context); if (font == NULL) { fprintf(stderr, "Fatal error: Couldn't deserialize 15pt.bitmapfont (status %d)\n", context->status); exit(EXIT_FAILURE); } BitmapFont_readAtlasEntries(font, atlas); font->pointSize *= 2; call_virtual(setTexture, shaderConfiguration, 0, texture, false); drawingInterface = UIDrawingInterface2DTexture_create(); uiContext = UIToolkitContext_init(default2DRenderPipelineConfiguration(RENDER_BLEND_ALPHA), shaderConfiguration, drawingInterface); UIToolkit_setContext(&uiContext); appearance = UIAppearance_init(NULL); UIToolkit_registerAppearanceParameters(&appearance, atlas, UITypeface_BitmapFont_create(font, TEXT_OPTION_PIXEL_SNAPPING), NULL); effect1Button = UIButton_create(STRL("Play effect 1"), VECTOR2f(20.0f, 20.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, effect1ButtonCallback, NULL, appearance); effect2Button = UIButton_create(STRL("Play effect 2"), VECTOR2f(20.0f, 60.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, effect2ButtonCallback, NULL, appearance); stopEffect1Button = UIButton_create(STRL("Stop effect 1"), VECTOR2f(20.0f, 100.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stopEffect1ButtonCallback, NULL, appearance); stopEffect2Button = UIButton_create(STRL("Stop effect 2"), VECTOR2f(20.0f, 140.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stopEffect2ButtonCallback, NULL, appearance); stopAllEffectsButton = UIButton_create(STRL("Stop all effects"), VECTOR2f(20.0f, 180.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stopAllEffectsButtonCallback, NULL, appearance); playGroupButton = UIButton_create(STRL("Play group"), VECTOR2f(20.0f, 220.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, playGroupButtonCallback, NULL, appearance); stream1Button = UIButton_create(STRL("Start stream 1"), VECTOR2f(221.0f, 20.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stream1ButtonCallback, NULL, appearance); stream2Button = UIButton_create(STRL("Start stream 2"), VECTOR2f(221.0f, 60.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stream2ButtonCallback, NULL, appearance); stopAllStreamsButton = UIButton_create(STRL("Stop all streams"), VECTOR2f(221.0f, 100.0f), VECTOR2f(0.0f, 0.0f), 200.0f, OVERFLOW_TRUNCATE, stopAllStreamsButtonCallback, NULL, appearance); pauseButton = UIButton_create(STRL("Pause"), VECTOR2f(422.0f, 20.0f), VECTOR2f(0.0f, 0.0f), 100.0f, OVERFLOW_TRUNCATE, pauseButtonCallback, NULL, appearance); category0Button = UIButton_create(STRL("Category 0 volume: 1.0"), VECTOR2f(523.0f, 20.0f), VECTOR2f(0.0f, 0.0f), 255.0f, OVERFLOW_TRUNCATE, category0ButtonCallback, NULL, appearance); category1Button = UIButton_create(STRL("Category 1 volume: 1.0"), VECTOR2f(523.0f, 60.0f), VECTOR2f(0.0f, 0.0f), 255.0f, OVERFLOW_TRUNCATE, category1ButtonCallback, NULL, appearance); container = UIContainer_create(VECTOR2f(0.0f, 0.0f), UICONTAINER_NO_CENTER, UICONTAINER_SIZE_AUTO, false, appearance); UIContainer_addElement(container, effect1Button, true); UIContainer_addElement(container, effect2Button, true); UIContainer_addElement(container, stopEffect1Button, true); UIContainer_addElement(container, stopEffect2Button, true); UIContainer_addElement(container, stopAllEffectsButton, true); UIContainer_addElement(container, playGroupButton, true); UIContainer_addElement(container, stream1Button, true); UIContainer_addElement(container, stream2Button, true); UIContainer_addElement(container, stopAllStreamsButton, true); UIContainer_addElement(container, pauseButton, true); UIContainer_addElement(container, category0Button, true); UIContainer_addElement(container, category1Button, true); rootElement = (UIElement *) container; Shell_mainLoop(); }