diff --git a/android/app-android.cpp b/android/app-android.cpp index 27b26d05ff..5eaaa513ec 100644 --- a/android/app-android.cpp +++ b/android/app-android.cpp @@ -150,6 +150,7 @@ extern "C" void Java_com_henrikrydgard_libnative_NativeApp_init g_dpi_scale = 240.0f / (float)g_dpi; pixel_xres = xxres; pixel_yres = yyres; + pixel_in_dps = (float)pixel_xres / (float)dp_xres; NativeGetAppInfo(&app_name, &app_nice_name, &landscape); diff --git a/base/PCMain.cpp b/base/PCMain.cpp index 466872ac3f..1a729541fd 100644 --- a/base/PCMain.cpp +++ b/base/PCMain.cpp @@ -135,11 +135,6 @@ extern void mixaudio(void *userdata, Uint8 *stream, int len) { #undef main #endif int main(int argc, char *argv[]) { - /* // Xoom/Nexus 7 resolution. Other common tablet resolutions: 1024x600 , 1366x768 - dp_xres = 1280; - dp_yres = 800; - - */ std::string app_name; std::string app_name_nice; @@ -156,7 +151,8 @@ int main(int argc, char *argv[]) { bool landscape; NativeGetAppInfo(&app_name, &app_name_nice, &landscape); - + + tablet = false; if (landscape) { if (tablet) { pixel_xres = 1280 * zoom; @@ -250,12 +246,14 @@ int main(int argc, char *argv[]) { float density = 1.0f; dp_xres = (float)pixel_xres * density / zoom; dp_yres = (float)pixel_yres * density / zoom; + pixel_in_dps = (float)pixel_xres / dp_xres; NativeInitGraphics(); float dp_xscale = (float)dp_xres / pixel_xres; float dp_yscale = (float)dp_yres / pixel_yres; + printf("Pixels: %i x %i\n", pixel_xres, pixel_yres); printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres); @@ -350,8 +348,8 @@ int main(int argc, char *argv[]) { NativeShutdownGraphics(); SDL_PauseAudio(1); - NativeShutdown(); SDL_CloseAudio(); + NativeShutdown(); SDL_Quit(); net::Shutdown(); exit(0); diff --git a/base/display.cpp b/base/display.cpp index a18a30be77..3ceebf334c 100644 --- a/base/display.cpp +++ b/base/display.cpp @@ -7,4 +7,5 @@ int pixel_xres; int pixel_yres; int g_dpi; -float g_dpi_scale; \ No newline at end of file +float g_dpi_scale; +float pixel_in_dps; \ No newline at end of file diff --git a/base/display.h b/base/display.h index 43199561f0..d72ba4dafd 100644 --- a/base/display.h +++ b/base/display.h @@ -9,4 +9,5 @@ extern int pixel_xres; extern int pixel_yres; extern int g_dpi; -extern float g_dpi_scale; \ No newline at end of file +extern float g_dpi_scale; +extern float pixel_in_dps; \ No newline at end of file diff --git a/gfx_es2/draw_buffer.cpp b/gfx_es2/draw_buffer.cpp index c4452d0bfe..698ab346c5 100644 --- a/gfx_es2/draw_buffer.cpp +++ b/gfx_es2/draw_buffer.cpp @@ -233,15 +233,15 @@ void DrawBuffer::DrawTexRect(float x1, float y1, float x2, float y2, float u1, f void DrawBuffer::DrawImage4Grid(int atlas_image, float x1, float y1, float x2, float y2, Color color, float corner_scale) { const AtlasImage &image = atlas->images[atlas_image]; - float um = (image.u2 - image.u1) * 0.5f; - float vm = (image.v2 - image.v1) * 0.5f; + float u1 = image.u1, v1 = image.v1, u2 = image.u2, v2 = image.v2; + float um = (u2 + u1) * 0.5f; + float vm = (v2 + v1) * 0.5f; float iw2 = (image.w * 0.5f) * corner_scale; float ih2 = (image.h * 0.5f) * corner_scale; float xa = x1 + iw2; float xb = x2 - iw2; float ya = y1 + ih2; float yb = y2 - ih2; - float u1 = image.u1, v1 = image.v1, u2 = image.u2, v2 = image.v2; // Top row DrawTexRect(x1, y1, xa, ya, u1, v1, um, vm, color); DrawTexRect(xa, y1, xb, ya, um, v1, um, vm, color); @@ -358,8 +358,11 @@ void DrawBuffer::DrawText(int font, const char *text, float x, float y, Color co void DrawBuffer::EnableBlend(bool enable) { if (enable) + { glEnable(GL_BLEND); - else + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else glDisable(GL_BLEND); } diff --git a/gfx_es2/draw_buffer.h b/gfx_es2/draw_buffer.h index 66f7b23072..7f40829ac1 100644 --- a/gfx_es2/draw_buffer.h +++ b/gfx_es2/draw_buffer.h @@ -4,6 +4,7 @@ #include "base/basictypes.h" #include "base/color.h" +#include "base/display.h" struct Atlas; @@ -54,16 +55,16 @@ public: void Flush(const GLSLProgram *program, bool set_blend_state=true); void Rect(float x, float y, float w, float h, uint32 color, int align = ALIGN_TOPLEFT); - void hLine(float x1, float y, float x2, uint32 color) { Rect(x1, y, x2 - x1, 1, color); } - void vLine(float x, float y1, float y2, uint32 color) { Rect(x, y1, 1, y2 - y1, color); } - void vLineAlpha50(float x, float y1, float y2, uint32 color) { Rect(x, y1, 1, y2 - y1, (color | 0xFF000000) & 0x7F000000); } + void hLine(float x1, float y, float x2, uint32 color) { Rect(x1, y, x2 - x1, pixel_in_dps, color); } + void vLine(float x, float y1, float y2, uint32 color) { Rect(x, y1, pixel_in_dps, y2 - y1, color); } + void vLineAlpha50(float x, float y1, float y2, uint32 color) { Rect(x, y1, pixel_in_dps, y2 - y1, (color | 0xFF000000) & 0x7F000000); } void RectOutline(float x, float y, float w, float h, uint32 color, int align = ALIGN_TOPLEFT) { - hLine(x, y, x + w + 1, color); - hLine(x, y + h, x + w + 1, color); + hLine(x, y, x + w + pixel_in_dps, color); + hLine(x, y + h, x + w + pixel_in_dps, color); - vLine(x, y, y + h + 1, color); - vLine(x + w, y, y + h + 1, color); + vLine(x, y, y + h + pixel_in_dps, color); + vLine(x + w, y, y + h + pixel_in_dps, color); } void RectVGradient(float x, float y, float w, float h, uint32 colorTop, uint32 colorBottom); diff --git a/math/curves.cpp b/math/curves.cpp index c86f87ae5d..00c6303a50 100644 --- a/math/curves.cpp +++ b/math/curves.cpp @@ -36,6 +36,13 @@ float ease(float val) { return ((-cosf(val * PI)) + 1.0f) * 0.5; } +float ease(int t, int fadeLength) +{ + if (t < 0) return 0.0f; + if (t >= fadeLength) return 1.0f; + return ease((float)t / (float)fadeLength); +} + float sawtooth(int t, int period) { return (t % period) * (1.0f / (period - 1)); } diff --git a/math/curves.h b/math/curves.h index fb21d91fb5..be5133326a 100644 --- a/math/curves.h +++ b/math/curves.h @@ -12,6 +12,7 @@ float linearOut(int t, int fadeInLength); // smooth operator [0, 1] -> [0, 1] float ease(float val); +float ease(int t, int fadeLength); // need a bouncy ease diff --git a/ui/screen.cpp b/ui/screen.cpp index 4ff06e8476..db0cd5fa37 100644 --- a/ui/screen.cpp +++ b/ui/screen.cpp @@ -1,27 +1,22 @@ #include "base/logging.h" #include "input/input_state.h" #include "ui/screen.h" +#include "ui/ui.h" Screen::Screen(bool isUiScreen) : screenManager_(0), isUiScreen_(isUiScreen) { } Screen::~Screen() { } ScreenManager::ScreenManager() { - currentScreen_ = 0; nextScreen_ = 0; uiContext_ = 0; + dialogFinished_ = 0; } ScreenManager::~ScreenManager() { - delete currentScreen_; + shutdown(); } void ScreenManager::switchScreen(Screen *screen) { - if (dialog_.size()) - { - WLOG("Switching screens - dropping the whole dialog stack"); - while (dialog_.size()) - pop(); - } // Note that if a dialog is found, this will be a silent background switch that // will only become apparent if the dialog is closed. The previous screen will stick around // until that switch. @@ -29,113 +24,148 @@ void ScreenManager::switchScreen(Screen *screen) { if (nextScreen_ != 0) { FLOG("WTF? Already had a nextScreen_"); } - if (screen != currentScreen_) { + if (stack_.empty() || screen != stack_.back().screen) { nextScreen_ = screen; nextScreen_->setScreenManager(this); } } void ScreenManager::update(InputState &input) { - if (dialog_.size()) { - dialog_.back()->update(input); - return; - } - if (nextScreen_) { - ILOG("Screen switch!"); - Screen *temp = currentScreen_; - currentScreen_ = nextScreen_; - delete temp; - temp = 0; - nextScreen_ = 0; + ILOG("Screen switch! Top of the stack switches."); + switchToNext(); } - if (currentScreen_) { - currentScreen_->update(input); + if (stack_.size()) { + stack_.back().screen->update(input); } } +void ScreenManager::switchToNext() +{ + Layer temp = {0, 0}; + if (!stack_.empty()) + { + temp = stack_.back(); + stack_.pop_back(); + } + Layer newLayer = {nextScreen_, 0}; + stack_.push_back(newLayer); + delete temp.screen; + nextScreen_ = 0; +} + void ScreenManager::touch(int pointer, float x, float y, double time, TouchEvent event) { - if (dialog_.size()) { - dialog_.back()->touch(pointer, x, y, time, event); + if (stack_.size()) { + stack_.back().screen->touch(pointer, x, y, time, event); return; } - if (currentScreen_) - { - currentScreen_->touch(pointer, x, y, time, event); - } } void ScreenManager::render() { - if (dialog_.size()) { - dialog_.back()->render(); - return; - } - if (currentScreen_) { - currentScreen_->render(); - } - else { + if (stack_.size()) { + switch (stack_.back().flags) + { + case LAYER_SIDEMENU: + if (stack_.size() == 1) + { + ELOG("Can't have sidemenu over nothing"); + break; + } + else + { + auto iter = stack_.end(); + iter--; + iter--; + Layer backback = *iter; + UIDisableBegin(); + // Also shift to the right somehow... + backback.screen->render(); + UIDisableEnd(); + stack_.back().screen->render(); + break; + } + default: + stack_.back().screen->render(); + break; + } + } else { ELOG("No current screen!"); } + + processFinishDialog(); } void ScreenManager::deviceLost() { - if (currentScreen_) - currentScreen_->deviceLost(); + if (stack_.size()) + stack_.back().screen->deviceLost(); // Dialogs too? Nah, they should only use the standard UI texture anyway. // TODO: Change this when it becomes necessary. } Screen *ScreenManager::topScreen() { - if (dialog_.size()) - return dialog_.back(); + if (stack_.size()) + return stack_.back().screen; else - return currentScreen_; + return 0; } void ScreenManager::shutdown() { - if (nextScreen_) { - delete nextScreen_; - nextScreen_ = 0; - } - if (currentScreen_) { - delete currentScreen_; - currentScreen_ = 0; + for (auto x = stack_.begin(); x != stack_.end(); x++) + { + delete x->screen; } + stack_.clear(); + delete nextScreen_; } -void ScreenManager::push(Screen *screen) { +void ScreenManager::push(Screen *screen, int layerFlags) { + if (nextScreen_ && stack_.empty()) { + // we're during init, this is OK + switchToNext(); + } screen->setScreenManager(this); - dialog_.push_back(screen); + Layer layer = {screen, layerFlags}; + stack_.push_back(layer); } void ScreenManager::pop() { - if (dialog_.size()) { - delete dialog_.back(); - dialog_.pop_back(); + if (stack_.size()) { + delete stack_.back().screen; + stack_.pop_back(); } else { - ELOG("Can't push when no dialog is shown"); + ELOG("Can't pop when stack empty"); } } void ScreenManager::finishDialog(const Screen *dialog, DialogResult result) { - if (!dialog_.size()) { - ELOG("Must be in a dialog to finishDialog"); - return; - } - Screen *dlg = dialog_.back(); - if (dialog != dialog_.back()) + if (dialog != stack_.back().screen) { ELOG("Wrong dialog being finished!"); return; } - if (dialog_.size()) { - dialog_.pop_back(); + if (!stack_.size()) { + ELOG("Must be in a dialog to finishDialog"); + return; } - Screen *caller = topScreen(); - caller->dialogFinished(dialog, result); - delete dialog; + dialogFinished_ = dialog; + dialogResult_ = result; } + +void ScreenManager::processFinishDialog() +{ + if (dialogFinished_) + { + if (stack_.size()) { + stack_.pop_back(); + } + + Screen *caller = topScreen(); + caller->dialogFinished(dialogFinished_, dialogResult_); + delete dialogFinished_; + dialogFinished_ = 0; + } +} \ No newline at end of file diff --git a/ui/screen.h b/ui/screen.h index 0ff3e27015..14f7cd85cb 100644 --- a/ui/screen.h +++ b/ui/screen.h @@ -44,6 +44,8 @@ public: ScreenManager *screenManager() { return screenManager_; } void setScreenManager(ScreenManager *sm) { screenManager_ = sm; } + virtual void *dialogData() { return 0; } + private: ScreenManager *screenManager_; bool isUiScreen_; @@ -76,7 +78,7 @@ public: void shutdown(); // Push a dialog box in front. Currently 1-level only. - void push(Screen *screen); + void push(Screen *screen, int layerFlags = 0); // Pops the dialog away. void finishDialog(const Screen *dialog, DialogResult result = DR_OK); @@ -86,14 +88,16 @@ public: private: void pop(); + void switchToNext(); + void processFinishDialog(); Screen *topScreen(); - // Base screen. These don't "stack" and you can move in any order between them. - Screen *currentScreen_; Screen *nextScreen_; - UIContext *uiContext_; + const Screen *dialogFinished_; + DialogResult dialogResult_; + struct Layer { Screen *screen; int flags; // From LAYER_ enum above @@ -101,5 +105,5 @@ private: // Dialog stack. These are shown "on top" of base screens and the Android back button works as expected. // Used for options, in-game menus and other things you expect to be able to back out from onto something. - std::list dialog_; + std::list stack_; }; diff --git a/ui/ui.cpp b/ui/ui.cpp index 0735a248b9..da57aa777b 100644 --- a/ui/ui.cpp +++ b/ui/ui.cpp @@ -286,7 +286,7 @@ void UIList::pointerDown(int pointer, float x, float y) { const int holdFrames = 6; -void UIList::pointerMove(int pointer, float x, float y) { +void UIList::pointerMove(int pointer, float x, float y, bool inside) { float deltaY = y - lastY; movedDistanceY += fabsf(deltaY); @@ -298,7 +298,7 @@ void UIList::pointerMove(int pointer, float x, float y) { inertiaY = 0.8 * inertiaY + 0.2 * -deltaY; } - if (movedDistanceY > 15 && !scrolling && uistate.mouseframesdown[0] > holdFrames) { + if (inside && movedDistanceY > 10 && !scrolling && uistate.mouseframesdown[0] > holdFrames) { scrolling = true; } } @@ -319,7 +319,9 @@ int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) { // TODO: Abstract this stuff out into EmulatePointerEvents for (int i = 0; i < 1; i++) { // Check for hover + bool isInside = false; if (UIRegionHit(i, x, y, w, h, 0)) { + isInside = true; uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) { // Mousedown @@ -331,7 +333,7 @@ int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) { if (uistate.activeitem[i] == id) { // NOTE: won't work with multiple pointers if (uistate.mousex[i] != lastX || uistate.mousey[i] != lastY) { - pointerMove(i, uistate.mousex[i], uistate.mousey[i]); + pointerMove(i, uistate.mousex[i], uistate.mousey[i], isInside); } } @@ -343,7 +345,7 @@ int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) { if (uistate.hotitem[i] == id) { clicked = 1; } - pointerUp(i, uistate.mousex[i], uistate.mousey[i], uistate.hotitem[i] == id); + pointerUp(i, uistate.mousex[i], uistate.mousey[i], isInside); } } @@ -358,13 +360,15 @@ int UIList::Do(int id, int x, int y, int w, int h, UIListAdapter *adapter) { if (!uistate.mousedown[0]) { // Let it slide if the pointer is not down scrollY += inertiaY; - } else if (scrolling && mouseY > y && mouseY < y + h) { + } else if (scrolling /* && mouseY > y && mouseY < y + h*/ ) { // Pointer is down so stick to it scrollY = startScrollY - (uistate.mousey[0] - startDragY); } // Inertia gradually trails off inertiaY *= 0.92f; + if (scrolling && fabsf(inertiaY) < 0.001f) + scrolling = false; // Cap top and bottom softly. float maxScrollY = numItems * itemHeight - h; diff --git a/ui/ui.h b/ui/ui.h index 1f2015e988..6fdfdb334b 100644 --- a/ui/ui.h +++ b/ui/ui.h @@ -237,7 +237,7 @@ private: // TODO: Migrate to using these directly. void pointerDown(int pointer, float x, float y); void pointerUp(int pointer, float x, float y, bool inside); - void pointerMove(int pointer, float x, float y); + void pointerMove(int pointer, float x, float y, bool inside); DISALLOW_COPY_AND_ASSIGN(UIList); }; diff --git a/ui/ui_context.cpp b/ui/ui_context.cpp index 800780532c..f5fd58dd0a 100644 --- a/ui/ui_context.cpp +++ b/ui/ui_context.cpp @@ -23,19 +23,54 @@ void UIContext::Begin() uidrawbufferTop_->Begin();*/ } -void UIContext::End() +void UIContext::RebindTexture() +{ + if (uitexture_) + uitexture_->Bind(0); +} + +void UIContext::Flush() { - UIEnd(); if (uidrawbuffer_) { uidrawbuffer_->End(); - if (uishader_) + if (uishader_) { + glsl_bind(uishader_); uidrawbuffer_->Flush(uishader_); + } } if (uidrawbufferTop_) { - uidrawbuffer_->End(); - if (uishader_) + uidrawbufferTop_->End(); + if (uishader_) { + glsl_bind(uishader_); uidrawbufferTop_->Flush(uishader_); + } } +} + +void UIContext::FlushNoTex() +{ + if (uidrawbuffer_) + { + uidrawbuffer_->End(); + if (uishadernotex_) { + glsl_bind(uishadernotex_); + uidrawbuffer_->Flush(uishadernotex_); + } + } + if (uidrawbufferTop_) + { + uidrawbufferTop_->End(); + if (uishadernotex_) { + glsl_bind(uishadernotex_); + uidrawbufferTop_->Flush(uishadernotex_); + } + } +} + +void UIContext::End() +{ + UIEnd(); + Flush(); } \ No newline at end of file diff --git a/ui/ui_context.h b/ui/ui_context.h index daea6915f5..c756a3a175 100644 --- a/ui/ui_context.h +++ b/ui/ui_context.h @@ -11,19 +11,24 @@ class UIContext { public: UIContext() : uishader_(0), uitexture_(0), uidrawbuffer_(0), uidrawbufferTop_(0) {} - void Init(const GLSLProgram *uishader, Texture *uitexture, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop) { + void Init(const GLSLProgram *uishader, const GLSLProgram *uishadernotex, Texture *uitexture, DrawBuffer *uidrawbuffer, DrawBuffer *uidrawbufferTop) { uishader_ = uishader; + uishadernotex_ = uishadernotex; uitexture_ = uitexture; uidrawbuffer_ = uidrawbuffer; uidrawbufferTop_ = uidrawbufferTop; } void Begin(); + void Flush(); + void FlushNoTex(); void End(); + void RebindTexture(); private: // TODO: Collect these into a UIContext const GLSLProgram *uishader_; + const GLSLProgram *uishadernotex_; Texture *uitexture_; DrawBuffer *uidrawbuffer_; DrawBuffer *uidrawbufferTop_;