From fc886b23e66e4e96535183506714da47411e6247 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 10 Apr 2012 11:59:57 +0200 Subject: [PATCH] Move the SDL C++ wrapper code into the native project as well. --- android/README.md | 8 + android/app-android.cpp | 8 +- android/res/layout/main.xml | 12 -- android/res/values/strings.xml | 7 - {android => base}/NativeApp.h | 23 ++- base/PCMain.cpp | 270 +++++++++++++++++++++++++++++++++ base/display.cpp | 4 + base/display.h | 7 + native.vcxproj | 5 +- native.vcxproj.filters | 9 ++ 10 files changed, 324 insertions(+), 29 deletions(-) create mode 100644 android/README.md delete mode 100644 android/res/layout/main.xml delete mode 100644 android/res/values/strings.xml rename {android => base}/NativeApp.h (64%) create mode 100644 base/PCMain.cpp create mode 100644 base/display.cpp create mode 100644 base/display.h diff --git a/android/README.md b/android/README.md new file mode 100644 index 0000000000..61612db953 --- /dev/null +++ b/android/README.md @@ -0,0 +1,8 @@ +Here's an Android library project. Add this to your eclipse workspace +and add a dependency to it, then just inherit from NativeActivity, +write your C++ code, and Bob's your uncle. + + +Contact: hrydgard@gmail.com + + diff --git a/android/app-android.cpp b/android/app-android.cpp index c5354f9589..ba33634a5e 100644 --- a/android/app-android.cpp +++ b/android/app-android.cpp @@ -13,13 +13,13 @@ #include #include "base/basictypes.h" +#include "base/display.h" +#include "base/NativeApp.h" #include "base/logging.h" #include "base/timeutil.h" #include "file/zip_read.h" #include "input/input_state.h" #include "audio/mixer.h" -#include "android/NativeApp.h" -#include "Globals.h" #define coord_xres 800 #define coord_yres 480 @@ -100,9 +100,7 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_init ILOG("External storage path: %s", str); str = env->GetStringUTFChars(dataDir, &isCopy); - user_data_path = std::string(str) + "/"; - settings_file = user_data_path + "settings.json"; - ILOG("Settings file: %s", settings_file.c_str()); + std::string user_data_path = std::string(str) + "/"; str = env->GetStringUTFChars(jinstallID, &isCopy); std::string installID = std::string(str); diff --git a/android/res/layout/main.xml b/android/res/layout/main.xml deleted file mode 100644 index bc12cd8231..0000000000 --- a/android/res/layout/main.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml deleted file mode 100644 index 6a272c9cf2..0000000000 --- a/android/res/values/strings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - Hello World! - libnative - - \ No newline at end of file diff --git a/android/NativeApp.h b/base/NativeApp.h similarity index 64% rename from android/NativeApp.h rename to base/NativeApp.h index 4ca2409ac3..72ffc952c0 100644 --- a/android/NativeApp.h +++ b/base/NativeApp.h @@ -1,5 +1,7 @@ #pragma once +#include + // The Native App API. // // Implement these functions and you've got a native app. These are called @@ -9,12 +11,15 @@ // This is defined in input/input_state.h. struct InputState; -// The very first function to be called. Even NativeMix is not called -// before this, although it may be called at any point in time afterwards. -// Must not call OpenGL. Main thread. +// You must implement this. The first function to get called, just write strings to the two pointers. +void NativeGetAppInfo(std::string *app_dir_name, std::string *app_nice_name); + +// The very first function to be called after NativeGetAppInfo. Even NativeMix is not called +// before this, although it may be called at any point in time afterwards (on any thread!) +// This functions must NOT call OpenGL. Main thread. void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *installID); -// Runs after NativeInit() at some point. Can call OpenGL. +// Runs after NativeInit() at some point. May (and probably should) call OpenGL. void NativeInitGraphics(); // Signals that you need to recreate all buffered OpenGL resources, @@ -44,3 +49,13 @@ void NativeMix(short *audio, int num_samples); // Main thread. void NativeShutdownGraphics(); void NativeShutdown(); + +// Calls back into Java / SDL +// These APIs must be implemented by every port (for example app-android.cpp, PCMain.cpp). +// You are free to call these. +void SystemToast(const char *text); +void ShowAd(int x, int y, bool center_x); +void Vibrate(int length_ms); +void LaunchBrowser(const char *url); +void LaunchMarket(const char *url); +void LaunchEmail(const char *email_address); diff --git a/base/PCMain.cpp b/base/PCMain.cpp new file mode 100644 index 0000000000..f6fbd87fd3 --- /dev/null +++ b/base/PCMain.cpp @@ -0,0 +1,270 @@ +// Bare bones SDL main. + +// Marble Madness +// Marble Mania +// Marbeliciuos +// Ballsy +// Rollerball +// Crash +// Cowball (with cowbell noises at the menu!) +// Rollfish + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#endif + +#include + +#include "SDL/SDL.h" +#include "SDL/SDL_timer.h" +#include "SDL/SDL_audio.h" + +#include "base/display.h" +#include "base/logging.h" +#include "base/timeutil.h" +#include "gfx_es2/glsl_program.h" +#include "file/zip_read.h" +#include "input/input_state.h" +#include "base/NativeApp.h" + + +// Simple implementations of System functions + +void SystemToast(const char *text) { + MessageBox(0, text, "Toast!", MB_ICONINFORMATION); +} + + +void ShowAd(int x, int y, bool center_x) { + // Ignore ads on PC +} + +void Vibrate(int length_ms) { + // Ignore on PC +} + +void LaunchBrowser(const char *url) +{ +#ifdef _WIN32 + ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); +#else +#endif +} + +void LaunchMarket(const char *url) +{ +#ifdef _WIN32 + ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); +#else +#endif +} + +void LaunchEmail(const char *email_address) +{ +#ifdef _WIN32 + ShellExecute(NULL, "open", (std::string("mailto:") + email_address).c_str(), NULL, NULL, SW_SHOWNORMAL); +#else +#endif +} + + + +const int buttonMappings[12] = { + SDLK_x, //A + SDLK_s, //B + SDLK_z, //X + SDLK_a, //Y + SDLK_w, //LBUMPER + SDLK_q, //RBUMPER + SDLK_1, //START + SDLK_2, //BACK + SDLK_UP, //UP + SDLK_DOWN, //DOWN + SDLK_LEFT, //LEFT + SDLK_RIGHT, //RIGHT +}; + +void SimulateGamepad(const uint8 *keys, InputState *input) { + input->pad_buttons = 0; + input->pad_lstick_x = 0; + input->pad_lstick_y = 0; + input->pad_rstick_x = 0; + input->pad_rstick_y = 0; + for (int b = 0; b < 12; b++) { + if (keys[buttonMappings[b]]) + input->pad_buttons |= (1<pad_lstick_y=32000; + else if (keys['K']) input->pad_lstick_y=-32000; + if (keys['J']) input->pad_lstick_x=-32000; + else if (keys['L']) input->pad_lstick_x=32000; + if (keys['8']) input->pad_rstick_y=32000; + else if (keys['2']) input->pad_rstick_y=-32000; + if (keys['4']) input->pad_rstick_x=-32000; + else if (keys['6']) input->pad_rstick_x=32000; +} + +extern void mixaudio(void *userdata, Uint8 *stream, int len) { + NativeMix((short *)stream, len / 4); +} + +#ifdef _WIN32 +#undef main +#endif +int main(int argc, char *argv[]) { + /* // Xoom resolution. Other common tablet resolutions: 1024x600 , 1366x768 + g_xres = 1280; + g_yres = 800; + */ + g_xres = 800; + g_yres = 480; + + std::string app_name; + std::string app_name_nice; + NativeGetAppInfo(&app_name, &app_name_nice); + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); + + if (SDL_SetVideoMode(g_xres, g_yres, 0, SDL_OPENGL) == NULL) { + fprintf(stderr, "SDL SetVideoMode failed: Unable to create OpenGL screen: %s\n", SDL_GetError()); + SDL_Quit(); + return(2); + } + SDL_WM_SetCaption(app_name_nice.c_str(), NULL); + + if (GLEW_OK != glewInit()) { + printf("Failed to initialize glew!\n"); + return 1; + } + + if (GLEW_VERSION_2_0) { + printf("OpenGL 2.0 or higher.\n"); + } else { + printf("Sorry, this program requires OpenGL 2.0.\n"); + return 1; + } + + + +#ifdef _MSC_VER + // VFSRegister("temp/", new DirectoryAssetReader("E:\\Temp\\")); + TCHAR path[MAX_PATH]; + SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path); + PathAppend(path, (app_name + "\\").c_str()); +#else + // Mac - what about linux? Also, ugly hardcoding. + const char *path = getenv("HOME"); + if (!homeDir) { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + path = pwd->pw_dir; + } + +#endif + + NativeInit(argc, (const char **)argv, path, "BADCOFFEE"); + NativeInitGraphics(); + + SDL_AudioSpec fmt; + fmt.freq = 44100; + fmt.format = AUDIO_S16; + fmt.channels = 2; + fmt.samples = 512; + fmt.callback = &mixaudio; + fmt.userdata = (void *)0; + + if (SDL_OpenAudio(&fmt, NULL) < 0) { + ELOG("Failed to open audio: %s", SDL_GetError()); + return 1; + } + + // Audio must be unpaused _after_ NativeInit() + SDL_PauseAudio(0); + + InputState input_state = {0}; + int framecount = 0; + + while (true) { + SDL_Event event; + + input_state.accelerometer_valid = false; + input_state.mouse_valid = true; + int done = 0; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + done = 1; + } else if (event.type == SDL_KEYDOWN) { + if (event.key.keysym.sym == SDLK_ESCAPE) { + done = 1; + } + } else if (event.type == SDL_MOUSEMOTION) { + input_state.mouse_x = event.motion.x; + input_state.mouse_y = event.motion.y; + } else if (event.type == SDL_MOUSEBUTTONDOWN) { + if (event.button.button == SDL_BUTTON_LEFT) { + input_state.mouse_buttons_down = 1; + input_state.mouse_buttons = 1; + } + } else if (event.type == SDL_MOUSEBUTTONUP) { + if (event.button.button == SDL_BUTTON_LEFT) { + input_state.mouse_buttons = 0; + input_state.mouse_buttons_up = 1; + } + } + } + + if (done) break; + + input_state.mouse_last_buttons = input_state.mouse_buttons; + uint8 *keys = (uint8 *)SDL_GetKeyState(NULL); + if (keys[SDLK_ESCAPE]) { + break; + } + SimulateGamepad(keys, &input_state); + UpdateInputState(&input_state); + NativeUpdate(input_state); + NativeRender(); + if (framecount % 60 == 0) { + // glsl_refresh(); // auto-reloads modified GLSL shaders once per second. + } + + SDL_GL_SwapBuffers(); + + // Simple framerate limiting + static float t=0; + while (time_now() < t+1.0f/60.0f) { + sleep_ms(0); + time_update(); + } + time_update(); + t = time_now(); + framecount++; + } + // Faster exit, thanks to the OS. Remove this if you want to debug shutdown + exit(0); + + NativeShutdownGraphics(); + SDL_PauseAudio(1); + NativeShutdown(); + SDL_CloseAudio(); + SDL_Quit(); + return 0; +} diff --git a/base/display.cpp b/base/display.cpp new file mode 100644 index 0000000000..b84f2dd604 --- /dev/null +++ b/base/display.cpp @@ -0,0 +1,4 @@ +#include "base/display.h" + +int g_xres; +int g_yres; diff --git a/base/display.h b/base/display.h new file mode 100644 index 0000000000..8dae4a6bb2 --- /dev/null +++ b/base/display.h @@ -0,0 +1,7 @@ +#pragma once + +// This is meant to be a framework for handling DPI scaling etc. +// For now, it just consists of these two ugly globals. + +extern int g_xres; +extern int g_yres; diff --git a/native.vcxproj b/native.vcxproj index 4a4506782e..1eed63f384 100644 --- a/native.vcxproj +++ b/native.vcxproj @@ -91,9 +91,11 @@ + + @@ -136,6 +138,7 @@ + @@ -176,4 +179,4 @@ - + \ No newline at end of file diff --git a/native.vcxproj.filters b/native.vcxproj.filters index 0dae95bf12..1de7570a8d 100644 --- a/native.vcxproj.filters +++ b/native.vcxproj.filters @@ -138,6 +138,12 @@ gfx + + base + + + base + @@ -248,6 +254,9 @@ gfx + + base +