diff --git a/ion/src/sdl/Makefile b/ion/src/sdl/Makefile new file mode 100644 index 000000000..07368a953 --- /dev/null +++ b/ion/src/sdl/Makefile @@ -0,0 +1,33 @@ +# TODO +objs += $(addprefix ion/src/shared/, \ + crc32.o \ + crc32_padded.o \ + events.o \ + events_modifier.o \ + power.o \ + random.o \ + timing.o \ + dummy/backlight.o \ + dummy/battery.o \ + dummy/fcc_id.o \ + dummy/led.o \ + dummy/serial_number.o \ + dummy/stack.o \ + dummy/usb.o \ +) + +objs += $(addprefix ion/src/sdl/, \ + display.o \ + events.o \ + main.o \ + keyboard.o \ + layout.o \ +) + +objs += $(addprefix ion/src/sdl/android/, \ + images.o \ +) + +SFLAGS += -I/Users/romain/Sources/SDL/include + +include ion/src/sdl/external/Makefile diff --git a/ion/src/sdl/android/com.numworks.calculator/app/src/main/AndroidManifest.xml b/ion/src/sdl/android/com.numworks.calculator/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..afabdf7b4 --- /dev/null +++ b/ion/src/sdl/android/com.numworks.calculator/app/src/main/AndroidManifest.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ion/src/sdl/android/com.numworks.calculator/app/src/main/java/com/numworks/calculator/EpsilonActivity.java b/ion/src/sdl/android/com.numworks.calculator/app/src/main/java/com/numworks/calculator/EpsilonActivity.java new file mode 100644 index 000000000..b07febd5b --- /dev/null +++ b/ion/src/sdl/android/com.numworks.calculator/app/src/main/java/com/numworks/calculator/EpsilonActivity.java @@ -0,0 +1,34 @@ +package com.numworks.calculator; + +import android.graphics.Bitmap; +//import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.app.Activity; +import android.util.Log; + +import org.libsdl.app.SDLActivity; + +public class EpsilonActivity extends SDLActivity { + protected String[] getLibraries() { + return new String[] { + "SDL2", + "epsilon" + }; + } + + public Bitmap retrieveBitmapAsset(String identifier) { + Log.w("LoadTexture", "Retrieving bitmap asset"); + Log.w("LoadTexture", "Asset is " + identifier); + Bitmap bitmap = null; + try { + Log.w("LoadTexture", "Rez is " + this.getResources().getAssets().open(identifier)); + bitmap = BitmapFactory.decodeStream( + this.getResources().getAssets().open(identifier) + ); + } catch (Exception e) { + Log.w("LoadTexture", "Coundn't load a file:" + identifier); + } + + return bitmap; + } +} diff --git a/ion/src/sdl/android/images.cpp b/ion/src/sdl/android/images.cpp new file mode 100644 index 000000000..15a3905c6 --- /dev/null +++ b/ion/src/sdl/android/images.cpp @@ -0,0 +1,53 @@ +// This shall be implemented per-platform +// +#include +#include +#include + +SDL_Surface * loadImage(const char * identifier) { + JNIEnv * env = static_cast(SDL_AndroidGetJNIEnv()); + jobject activity = static_cast(SDL_AndroidGetActivity()); + + jstring j_identifier = env->NewStringUTF(identifier); + + jclass j_class = env->FindClass("com/numworks/calculator/EpsilonActivity"); + jmethodID j_methodId = env->GetMethodID( + j_class, + "retrieveBitmapAsset", + "(Ljava/lang/String;)Landroid/graphics/Bitmap;" + ); + + jobject j_bitmap = env->CallObjectMethod(activity, j_methodId, j_identifier); + + AndroidBitmapInfo bitmapInfo; + AndroidBitmap_getInfo(env, j_bitmap, &bitmapInfo); + + void * bitmapPixels = nullptr; + AndroidBitmap_lockPixels(env, j_bitmap, &bitmapPixels); + // TODO: Handle the case where lockPixels fails + + SDL_Surface * inputSurface = SDL_CreateRGBSurfaceWithFormatFrom( + bitmapPixels, + bitmapInfo.width, + bitmapInfo.height, + 32, // BPP. TODO: Infer from pixel format + 4 * bitmapInfo.width, // Pitch. TODO: Infer from pixel format + SDL_PIXELFORMAT_ABGR8888 + ); + + SDL_Surface * outputSurface = SDL_CreateRGBSurface( + 0, // Flags. Unused. + bitmapInfo.width, // Width + bitmapInfo.height, // Height + 32, // Bits per pixel + 0, 0, 0, 0 // Default masks for the given depth + ); + + SDL_BlitSurface(inputSurface, NULL, outputSurface, NULL); + + SDL_FreeSurface(inputSurface); + + AndroidBitmap_unlockPixels(env, j_bitmap); + + return outputSurface; +} diff --git a/ion/src/sdl/display.cpp b/ion/src/sdl/display.cpp new file mode 100644 index 000000000..6c2c5822a --- /dev/null +++ b/ion/src/sdl/display.cpp @@ -0,0 +1,59 @@ +#include "display.h" +#include "keyboard.h" +#include +#include + +static KDColor sPixels[Ion::Display::Width * Ion::Display::Height]; + +namespace Ion { +namespace Display { + +static KDFrameBuffer sFrameBuffer = KDFrameBuffer(sPixels, KDSize(Ion::Display::Width, Ion::Display::Height)); + +void pushRect(KDRect r, const KDColor * pixels) { + sFrameBuffer.pushRect(r, pixels); +} + +void pushRectUniform(KDRect r, KDColor c) { + sFrameBuffer.pushRectUniform(r, c); +} + +void pullRect(KDRect r, KDColor * pixels) { + sFrameBuffer.pullRect(r, pixels); +} + +void waitForVBlank() { +} + +} +} + +namespace Ion { +namespace SDL { +namespace Display { + +static SDL_Surface * sFramebufferSurface = nullptr; + +void init() { + sFramebufferSurface = SDL_CreateRGBSurfaceWithFormatFrom( + sPixels, + Ion::Display::Width, + Ion::Display::Height, + 16, + Ion::Display::Width * 2, + SDL_PIXELFORMAT_RGB565 + ); +} + +void quit() { + SDL_FreeSurface(sFramebufferSurface); + sFramebufferSurface = nullptr; +} + +void blit(SDL_Surface * dst, SDL_Rect * rect) { + SDL_BlitScaled(sFramebufferSurface, NULL, dst, rect); +} + +} +} +} diff --git a/ion/src/sdl/display.h b/ion/src/sdl/display.h new file mode 100644 index 000000000..7d3582304 --- /dev/null +++ b/ion/src/sdl/display.h @@ -0,0 +1,20 @@ +#ifndef ION_SDL_DISPLAY_H +#define ION_SDL_DISPLAY_H + +#include +#include + +namespace Ion { +namespace SDL { +namespace Display { + +void init(); +void quit(); + +void blit(SDL_Surface * dst, SDL_Rect * rect); + +} +} +} + +#endif diff --git a/ion/src/sdl/events.cpp b/ion/src/sdl/events.cpp new file mode 100644 index 000000000..2d6324cd3 --- /dev/null +++ b/ion/src/sdl/events.cpp @@ -0,0 +1,43 @@ +#include "main.h" +#include "layout.h" + +#include + +#include + +namespace Ion { +namespace Events { + +static bool needsRefresh = true; + +Event getEvent(int * timeout) { + + if (needsRefresh) { + Ion::SDL::Main::refresh(); + needsRefresh = false; + } + + SDL_Event event; + + if (!SDL_WaitEventTimeout(&event, *timeout)) { + return None; + } + + if (event.type == SDL_FINGERDOWN) { + SDL_FPoint fp; + fp.x = event.tfinger.x; + fp.y = event.tfinger.y; + Keyboard::Key key = SDL::Layout::keyAtF(&fp); + if (key == Keyboard::Key::None) { + return None; + } + needsRefresh = true; + Event event = Event(key, isShiftActive(), isAlphaActive()); + return event; + } + + return None; +} + +} +} diff --git a/ion/src/sdl/images.h b/ion/src/sdl/images.h new file mode 100644 index 000000000..189e42333 --- /dev/null +++ b/ion/src/sdl/images.h @@ -0,0 +1,5 @@ +// This shall be implemented per-platform +// +#include + +SDL_Surface * loadImage(const char * identifier); diff --git a/ion/src/sdl/keyboard.cpp b/ion/src/sdl/keyboard.cpp new file mode 100644 index 000000000..7ebf1b8a6 --- /dev/null +++ b/ion/src/sdl/keyboard.cpp @@ -0,0 +1,63 @@ +#include "keyboard.h" +#include + +#include + +#include "images.h" + +#define APPNAME "MyApp" + +namespace Ion { +namespace Keyboard { + +State scan() { + return State(0); +} + +} +} + +namespace Ion { +namespace SDL { +namespace Keyboard { + +using namespace Ion::Keyboard; + +static SDL_Rect s_rect; + +void init(SDL_Rect rect) { + s_rect = rect; +} + +static SDL_Rect rectForKey(Key k) { + int i = static_cast(k); + return {i%10, i/10, 10, 10}; +} + +void drawOnSurface(SDL_Surface * surface) { + for (int i=0; iformat, 0xFF, 0x00, 0xFF)); + } +} + +Key keyAt(SDL_Point p) { + __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Looking up %dx%d", p.x, p.y); + for (int i=0; i +#include +#include + +namespace Ion { +namespace SDL { +namespace Keyboard { + +void drawOnSurface(SDL_Surface * surface); +Ion::Keyboard::Key keyAt(SDL_Point p); + +} +} +} + +#endif diff --git a/ion/src/sdl/layout.cpp b/ion/src/sdl/layout.cpp new file mode 100644 index 000000000..df06e18c0 --- /dev/null +++ b/ion/src/sdl/layout.cpp @@ -0,0 +1,121 @@ +#include "layout.h" + +namespace Ion { +namespace SDL { +namespace Layout { + +#define X(x) ((x)/(1250.0f)) +#define Y(y) ((y)/(2100.0f)) + +static int sWidth = 0; +static int sHeight = 0; + +static void makeAbsolute(SDL_FRect * f, SDL_Rect * r) { + r->x = f->x * sWidth; + r->y = f->y * sHeight; + r->w = f->w * sWidth; + r->h = f->h * sHeight; +} + +static void makeAbsolute(SDL_FPoint * f, SDL_Point * p) { + p->x = f->x * sWidth; + p->y = f->y * sHeight; +} + +void setSize(int width, int height) { + sWidth = width; + sHeight = height; +} + +void getScreenRect(SDL_Rect * rect) { + SDL_FRect fRect; + fRect.x = X(310); + fRect.y = Y(215); + fRect.w = X(640); + fRect.h = Y(485); + makeAbsolute(&fRect, rect); +} + +Keyboard::Key keyAtF(SDL_FPoint * f) { + SDL_Point p; + makeAbsolute(f, &p); + return keyAt(&p); +} + +Keyboard::Key keyAt(SDL_Point * p) { + for (int i=0; i= 0); + assert(validKeyIndex < Keyboard::NumberOfValidKeys); + SDL_FRect rectForKey[Keyboard::NumberOfValidKeys] = { + {X(250), Y(880), X(85), Y(75) }, // A1, Left + {X(330), Y(795), X(75), Y(85) }, // A2, Up + {X(330), Y(950), X(75), Y(85) }, // A3, Down + {X(400), Y(880), X(85), Y(75) }, // A4, Right + {X(765), Y(855), X(110), Y(110)}, // A5, OK + {X(900), Y(855), X(110), Y(110)}, // A6, Back + + {X(565), Y(815), X(130), Y(85)}, // B1, Home + {X(565), Y(920), X(130), Y(85)}, // B2, Power + + {X(255), Y(1066), X(110), Y(75)}, // C1, Shift + {X(385), Y(1066), X(110), Y(75)}, // C2, Alpha + {X(512), Y(1066), X(110), Y(75)}, // C3, xnt + {X(638), Y(1066), X(110), Y(75)}, // C4, var + {X(768), Y(1066), X(110), Y(75)}, // C5, toolbox + {X(895), Y(1066), X(110), Y(75)}, // C6, Delete + + {X(255), Y(1170), X(110), Y(75)}, // D1, exp + {X(385), Y(1170), X(110), Y(75)}, // D2, ln + {X(512), Y(1170), X(110), Y(75)}, // D3, log + {X(638), Y(1170), X(110), Y(75)}, // D4, i + {X(768), Y(1170), X(110), Y(75)}, // D5, comma + {X(895), Y(1170), X(110), Y(75)}, // D6, power + + {X(255), Y(1272), X(110), Y(75)}, // E1, sin + {X(385), Y(1272), X(110), Y(75)}, // E2, cos + {X(512), Y(1272), X(110), Y(75)}, // E3, tan + {X(638), Y(1272), X(110), Y(75)}, // E4, pi + {X(768), Y(1272), X(110), Y(75)}, // E5, sqrt + {X(895), Y(1272), X(110), Y(75)}, // E6, square + + {X(255), Y(1376), X(130), X(85)}, // F1, 7 + {X(408), Y(1376), X(130), X(85)}, // F2, 8 + {X(564), Y(1376), X(130), X(85)}, // F3, 9 + {X(718), Y(1376), X(130), X(85)}, // F4, ( + {X(872), Y(1376), X(130), X(85)}, // F5, ) + + {X(255), Y(1490), X(130), X(85)}, // G1, 4 + {X(408), Y(1490), X(130), X(85)}, // G2, 5 + {X(564), Y(1490), X(130), X(85)}, // G3, 6 + {X(718), Y(1490), X(130), X(85)}, // G4, * + {X(872), Y(1490), X(130), X(85)}, // G5, / + + {X(255), Y(1605), X(130), X(85)}, // H1, 1 + {X(408), Y(1605), X(130), X(85)}, // H2, 2 + {X(564), Y(1605), X(130), X(85)}, // H3, 3 + {X(718), Y(1605), X(130), X(85)}, // H4, + + {X(872), Y(1605), X(130), X(85)}, // H5, - + + {X(255), Y(1718), X(130), X(85)}, // I1, 0 + {X(408), Y(1718), X(130), X(85)}, // I2, . + {X(564), Y(1718), X(130), X(85)}, // I3, x10 + {X(718), Y(1718), X(130), X(85)}, // I4, Ans + {X(872), Y(1718), X(130), X(85)}, // I5, EXE + }; + + makeAbsolute(&rectForKey[validKeyIndex], rect); +} + +} +} +} diff --git a/ion/src/sdl/layout.h b/ion/src/sdl/layout.h new file mode 100644 index 000000000..a1afca516 --- /dev/null +++ b/ion/src/sdl/layout.h @@ -0,0 +1,23 @@ +#ifndef ION_SDL_LAYOUT_H +#define ION_SDL_LAYOUT_H + +#include +#include + +namespace Ion { +namespace SDL { +namespace Layout { + +void setSize(int w, int h); + +void getScreenRect(SDL_Rect * rect); +Ion::Keyboard::Key keyAt(SDL_Point * p); +Ion::Keyboard::Key keyAtF(SDL_FPoint * p); + +void getKeyRect(int validKeyIndex, SDL_Rect * rect); + +} +} +} + +#endif diff --git a/ion/src/sdl/main.cpp b/ion/src/sdl/main.cpp new file mode 100644 index 000000000..49059cfe1 --- /dev/null +++ b/ion/src/sdl/main.cpp @@ -0,0 +1,78 @@ +#include "main.h" +#include "display.h" +#include +#include "images.h" +#include "layout.h" + +#include +#include + +#include + +void Ion::Timing::msleep(unsigned int) { + // Do nothing! +} + +int main(int argc, char * argv[]) { + Ion::SDL::Main::init(); + ion_main(argc, argv); + //Ion::SDL::Main::quit(); + return 0; +} + +namespace Ion { +namespace SDL { +namespace Main { + +static SDL_Window * sWindow = nullptr; +static SDL_Surface * sSurface = nullptr; +static SDL_Surface * sBackgroundSurface = nullptr; + +void init() { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + // Error... + return; + } + + sWindow = SDL_CreateWindow( + "Epsilon", + SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, + 0, 0, + SDL_WINDOW_RESIZABLE + ); + + SDL_SetWindowFullscreen(sWindow, 0); + + sSurface = SDL_GetWindowSurface(sWindow); + + Display::init(); + + sBackgroundSurface = loadImage("background.jpg"); +} + +void relayout() { + int windowWidth = 0; + int windowHeight = 0; + SDL_GetWindowSize(sWindow, &windowWidth, &windowHeight); + Layout::setSize(windowWidth, windowHeight); +} + +static void blitBackground(SDL_Rect * rect) { + SDL_BlitScaled(sBackgroundSurface, NULL, sSurface, rect); +} + +void refresh() { + relayout(); + + SDL_Rect screenRect; + Layout::getScreenRect(&screenRect); + + blitBackground(nullptr); + Display::blit(sSurface, &screenRect); + SDL_UpdateWindowSurface(sWindow); +} + +} +} +} diff --git a/ion/src/sdl/main.h b/ion/src/sdl/main.h new file mode 100644 index 000000000..5362dea02 --- /dev/null +++ b/ion/src/sdl/main.h @@ -0,0 +1,17 @@ +#ifndef ION_SDL_MAIN_H +#define ION_SDL_MAIN_H + +namespace Ion { +namespace SDL { +namespace Main { + +void init(); +void quit(); + +void refresh(); + +} +} +} + +#endif