// // main.cpp // projectM-sdl // // Created by Mischa Spiegelmock on 6/3/15. // // This is an implementation of projectM using libSDL2 #include "pmSDL.hpp" #define OGL_DEBUG 0 #define UNLOCK_FPS 0 #define FAKE_AUDIO 0 #if OGL_DEBUG void DebugLog(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { /*if (type != GL_DEBUG_TYPE_OTHER)*/ { std::cerr << " -- \n" << "Type: " << type << "; Source: " << source <<"; ID: " << id << "; Severity: " << severity << "\n" << message << "\n"; } } #endif // return path to config file to use std::string getConfigFilePath() { const char *path = DATADIR_PATH; struct stat sb; // check if datadir exists. // it should exist if this application was installed. if not, assume we're developing it and use currect directory if (stat(path, &sb) != 0) { SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "Could not open datadir path %s.\n", DATADIR_PATH); } std::string configFilePath = path; configFilePath += "/config.inp"; // check if config file exists if (stat(configFilePath.c_str(), &sb) != 0) { SDL_LogWarn(SDL_LOG_CATEGORY_ERROR, "No config file %s found. Using development settings.\n", configFilePath.c_str()); return ""; } return configFilePath; } int main(int argc, char *argv[]) { #if UNLOCK_FPS setenv("vblank_mode", "0", 1); #endif SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); if (! SDL_VERSION_ATLEAST(2, 0, 5)) { SDL_Log("SDL version 2.0.5 or greater is required. You have %i.%i.%i", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); return 1; } // default window size to usable bounds (e.g. minus menubar and dock) SDL_Rect initialWindowBounds; #if SDL_VERSION_ATLEAST(2, 0, 5) // new and better SDL_GetDisplayUsableBounds(0, &initialWindowBounds); #else SDL_GetDisplayBounds(0, &initialWindowBounds); #endif int width = initialWindowBounds.w; int height = initialWindowBounds.h; int renderIndex = 0; #ifdef USE_GLES for(int i = 0; i < SDL_GetNumRenderDrivers(); i++) { SDL_RendererInfo info; if (SDL_GetRenderDriverInfo(i, &info) == 0) { if (std::string(info.name) == "opengles2") { renderIndex = i; break; } } } // use GLES 2.0 (this may need adjusting) SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); #else // Disabling compatibility profile SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif SDL_Window *win = SDL_CreateWindow("projectM", 0, 0, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); SDL_GLContext glCtx = SDL_GL_CreateContext(win); SDL_Log("GL_VERSION: %s", glGetString(GL_VERSION)); SDL_Log("GL_SHADING_LANGUAGE_VERSION: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); SDL_Log("GL_VENDOR: %s", glGetString(GL_VENDOR)); SDL_SetWindowTitle(win, "projectM Visualizer"); projectMSDL *app; // load configuration file std::string configFilePath = getConfigFilePath(); if (! configFilePath.empty()) { // found config file, use it app = new projectMSDL(configFilePath, 0); SDL_Log("Using config from %s", configFilePath.c_str()); } else { SDL_Log("Config file not found, using development settings"); float heightWidthRatio = (float)height / (float)width; projectM::Settings settings; settings.windowWidth = width; settings.windowHeight = height; settings.meshX = 300; settings.meshY = settings.meshX * heightWidthRatio; settings.fps = 60; settings.smoothPresetDuration = 3; // seconds settings.presetDuration = 7; // seconds settings.beatSensitivity = 0.8; settings.aspectCorrection = 1; settings.shuffleEnabled = 1; settings.softCutRatingsEnabled = 1; // ??? // get path to our app, use CWD for presets/fonts/etc std::string base_path = SDL_GetBasePath(); settings.presetURL = base_path + "presets"; // settings.presetURL = base_path + "presets/presets_shader_test"; settings.menuFontURL = base_path + "fonts/Vera.ttf"; settings.titleFontURL = base_path + "fonts/Vera.ttf"; // init with settings app = new projectMSDL(settings, 0); } app->init(win, &glCtx); #if OGL_DEBUG glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(DebugLog, NULL); #endif #if !FAKE_AUDIO // get an audio input device if (app->openAudioInput()) app->beginAudioCapture(); #endif #if UNLOCK_FPS int32_t frame_count = 0; struct timespec now; clock_gettime(CLOCK_MONOTONIC_RAW, &now); int64_t start = ( ((int64_t)now.tv_sec * 1000L) + (now.tv_nsec / 1000000L) ); #endif // standard main loop int fps = app->settings().fps; printf("fps: %d\n", fps); if (fps <= 0) fps = 60; const Uint32 frame_delay = 1000/fps; Uint32 last_time = SDL_GetTicks(); while (! app->done) { app->renderFrame(); #if FAKE_AUDIO app->addFakePCM(); #endif #if UNLOCK_FPS frame_count++; clock_gettime(CLOCK_MONOTONIC_RAW, &now); if (( ((int64_t)now.tv_sec * 1000L) + (now.tv_nsec / 1000000L) ) - start > 5000) { SDL_GL_DeleteContext(glCtx); delete(app); fprintf(stdout, "Frames[%d]\n", frame_count); exit(0); } #else app->pollEvent(); Uint32 elapsed = SDL_GetTicks() - last_time; if (elapsed < frame_delay) SDL_Delay(frame_delay - elapsed); last_time = SDL_GetTicks(); #endif } SDL_GL_DeleteContext(glCtx); #if !FAKE_AUDIO app->endAudioCapture(); #endif delete app; return PROJECTM_SUCCESS; }