mirror of
https://github.com/mauiaaron/apple2.git
synced 2025-08-10 03:25:05 +00:00
680 lines
20 KiB
C
680 lines
20 KiB
C
/*
|
|
* Apple // emulator for *nix
|
|
*
|
|
* This software package is subject to the GNU General Public License
|
|
* version 2 or later (your choice) as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* THERE ARE NO WARRANTIES WHATSOEVER.
|
|
*
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "video/glvideo.h"
|
|
#include "video/glhudmodel.h"
|
|
#include "video/glnode.h"
|
|
|
|
#if !INTERFACE_TOUCH
|
|
#error this is a touch interface module, possibly you mean to not compile this at all?
|
|
#endif
|
|
|
|
#define MODEL_DEPTH -1/32.f
|
|
|
|
#define MENU_TEMPLATE_COLS 2
|
|
#define MENU_TEMPLATE_ROWS 2
|
|
|
|
#define MENU_FB_WIDTH (MENU_TEMPLATE_COLS * FONT80_WIDTH_PIXELS)
|
|
#define MENU_FB_HEIGHT (MENU_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
|
|
|
#define MENU_OBJ_W 1/2.f
|
|
#define MENU_OBJ_H 1/2.f
|
|
|
|
HUD_CLASS(GLModelHUDMenu,
|
|
char *pixelsAlt; // alternate color pixels
|
|
);
|
|
|
|
static bool isAvailable = false; // Were there any OpenGL/memory errors on initialization?
|
|
static bool isEnabled = true; // Does player want this enabled?
|
|
static float minAlpha = 1/4.f; // Minimum alpha value of components (at zero, will not render)
|
|
|
|
static char topLeftTemplateHidden[MENU_TEMPLATE_ROWS][MENU_TEMPLATE_COLS+1] = {
|
|
"++",
|
|
"++",
|
|
};
|
|
|
|
static char topLeftTemplateShowing[MENU_TEMPLATE_ROWS][MENU_TEMPLATE_COLS+1] = {
|
|
"++",
|
|
"++",
|
|
};
|
|
|
|
static char topRightTemplateHidden[MENU_TEMPLATE_ROWS][MENU_TEMPLATE_COLS+1] = {
|
|
"++",
|
|
"++",
|
|
};
|
|
|
|
static char topRightTemplateShowing[MENU_TEMPLATE_ROWS][MENU_TEMPLATE_COLS+1] = {
|
|
"++",
|
|
"++",
|
|
};
|
|
|
|
// touch viewport
|
|
|
|
static struct {
|
|
int width;
|
|
int height;
|
|
|
|
// top left hitbox
|
|
int topLeftX;
|
|
int topLeftXHalf;
|
|
int topLeftXMax;
|
|
int topLeftY;
|
|
int topLeftYHalf;
|
|
int topLeftYMax;
|
|
|
|
// top right hitbox
|
|
int topRightX;
|
|
int topRightXHalf;
|
|
int topRightXMax;
|
|
int topRightY;
|
|
int topRightYHalf;
|
|
int topRightYMax;
|
|
|
|
} touchport = { 0 };
|
|
|
|
// touch menu variables
|
|
|
|
static struct {
|
|
GLModel *model;
|
|
bool modelDirty; // TODO : movement animation
|
|
bool isShowing;
|
|
} hudTopLeft = { 0 };
|
|
|
|
static struct {
|
|
GLModel *model;
|
|
bool modelDirty; // TODO : movement animation
|
|
bool isShowing;
|
|
} hudTopRight = { 0 };
|
|
|
|
struct timespec timingBegin = { 0 };
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static inline void _present_menu(GLModel *parent, char *template) {
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom;
|
|
memcpy(hudMenu->tpl, template, sizeof(topLeftTemplateHidden/* assuming all templates the same size */));
|
|
|
|
// setup the alternate color (AKA selected) pixels
|
|
hudMenu->colorScheme = GREEN_ON_BLACK;
|
|
glhud_setupDefault(parent);
|
|
memcpy(hudMenu->pixelsAlt, hudMenu->pixels, (hudMenu->pixWidth * hudMenu->pixHeight));
|
|
|
|
// setup normal color pixels
|
|
hudMenu->colorScheme = RED_ON_BLACK;
|
|
glhud_setupDefault(parent);
|
|
}
|
|
|
|
static inline void _show_top_left(void) {
|
|
_present_menu(hudTopLeft.model, topLeftTemplateShowing[0]);
|
|
hudTopLeft.isShowing = true;
|
|
}
|
|
|
|
static inline void _hide_top_left(void) {
|
|
_present_menu(hudTopLeft.model, topLeftTemplateHidden[0]);
|
|
hudTopLeft.isShowing = false;
|
|
}
|
|
|
|
static inline void _show_top_right(void) {
|
|
_present_menu(hudTopRight.model, topRightTemplateShowing[0]);
|
|
hudTopRight.isShowing = true;
|
|
}
|
|
|
|
static inline void _hide_top_right(void) {
|
|
_present_menu(hudTopRight.model, topRightTemplateHidden[0]);
|
|
hudTopRight.isShowing = false;
|
|
}
|
|
|
|
static float _get_menu_visibility(void) {
|
|
struct timespec now = { 0 };
|
|
struct timespec deltat = { 0 };
|
|
float alpha = minAlpha;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
alpha = minAlpha;
|
|
deltat = timespec_diff(timingBegin, now, NULL);
|
|
if (deltat.tv_sec == 0) {
|
|
alpha = 1.0;
|
|
if (deltat.tv_nsec >= NANOSECONDS_PER_SECOND/2) {
|
|
alpha -= ((float)deltat.tv_nsec-(NANOSECONDS_PER_SECOND/2)) / (float)(NANOSECONDS_PER_SECOND/2);
|
|
if (alpha < minAlpha) {
|
|
alpha = minAlpha;
|
|
}
|
|
}
|
|
}
|
|
|
|
return alpha;
|
|
}
|
|
|
|
static inline bool _is_point_on_left_menu(float x, float y) {
|
|
if (hudTopLeft.isShowing) {
|
|
return (x >= touchport.topLeftX && x <= touchport.topLeftXMax && y >= touchport.topLeftY && y <= touchport.topLeftYMax);
|
|
} else {
|
|
return (x >= touchport.topLeftX && x <= touchport.topLeftXHalf && y >= touchport.topLeftY && y <= touchport.topLeftYHalf);
|
|
}
|
|
}
|
|
|
|
static inline bool _is_point_on_right_menu(float x, float y) {
|
|
if (hudTopRight.isShowing) {
|
|
return (x >= touchport.topRightX && x <= touchport.topRightXMax && y >= touchport.topRightY && y <= touchport.topRightYMax);
|
|
} else {
|
|
return (x >= touchport.topRightXHalf && x <= touchport.topRightXMax && y >= touchport.topRightY && y <= touchport.topRightYHalf);
|
|
}
|
|
}
|
|
|
|
#warning FIXME TODO : make this function generic _screen_to_model() ?
|
|
static inline void _screen_to_menu(float x, float y, OUTPARM int *col, OUTPARM int *row, OUTPARM bool *isTopLeft) {
|
|
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)(/* assuming both have same width/height */hudTopLeft.model->custom);
|
|
|
|
unsigned int keyW = (touchport.topLeftXMax - touchport.topLeftX) / hudMenu->tplWidth;
|
|
unsigned int keyH = (touchport.topLeftYMax - touchport.topLeftY) / hudMenu->tplHeight;
|
|
|
|
hudMenu = NULL;
|
|
if (x < touchport.width/2) {
|
|
*isTopLeft = true;
|
|
hudMenu = (GLModelHUDMenu *)hudTopLeft.model->custom;
|
|
*col = (x - touchport.topLeftX) / keyW;
|
|
*row = (y - touchport.topLeftY) / keyH;
|
|
LOG("SCREEN TO MENU : topLeftX:%d topLeftXMax:%d keyW:%d ... scrn:(%d,%d)->menu:(%d,%d)", touchport.topLeftX, touchport.topLeftXMax, keyW, (int)x, (int)y, *col, *row);
|
|
} else {
|
|
*isTopLeft = false;
|
|
hudMenu = (GLModelHUDMenu *)hudTopRight.model->custom;
|
|
*col = (x - touchport.topRightX) / keyW;
|
|
*row = (y - touchport.topRightY) / keyH;
|
|
LOG("SCREEN TO MENU : topRightX:%d topRightXMax:%d keyW:%d ... scrn:(%d,%d)->menu:(%d,%d)", touchport.topRightX, touchport.topRightXMax, keyW, (int)x, (int)y, *col, *row);
|
|
}
|
|
|
|
if (*col < 0) {
|
|
*col = 0;
|
|
} else if (*col >= hudMenu->tplWidth) {
|
|
*col = hudMenu->tplWidth-1;
|
|
}
|
|
if (*row < 0) {
|
|
*row = 0;
|
|
}
|
|
}
|
|
|
|
static void _increase_cpu_speed(void) {
|
|
pthread_mutex_lock(&interface_mutex);
|
|
|
|
int percent_scale = (int)round(cpu_scale_factor * 100.0);
|
|
if (percent_scale >= 100) {
|
|
percent_scale += 25;
|
|
} else {
|
|
percent_scale += 5;
|
|
}
|
|
cpu_scale_factor = percent_scale/100.0;
|
|
|
|
if (cpu_scale_factor > CPU_SCALE_FASTEST) {
|
|
cpu_scale_factor = CPU_SCALE_FASTEST;
|
|
}
|
|
|
|
LOG("native set emulation percentage to %f", cpu_scale_factor);
|
|
|
|
if (video_backend->animation_showCPUSpeed) {
|
|
video_backend->animation_showCPUSpeed();
|
|
}
|
|
|
|
#warning HACK TODO FIXME ... refactor timing stuff
|
|
timing_toggle_cpu_speed();
|
|
timing_toggle_cpu_speed();
|
|
|
|
pthread_mutex_unlock(&interface_mutex);
|
|
}
|
|
|
|
void _decrease_cpu_speed(void) {
|
|
pthread_mutex_lock(&interface_mutex);
|
|
|
|
int percent_scale = (int)round(cpu_scale_factor * 100.0);
|
|
if (cpu_scale_factor == CPU_SCALE_FASTEST) {
|
|
cpu_scale_factor = CPU_SCALE_FASTEST0;
|
|
percent_scale = (int)round(cpu_scale_factor * 100);
|
|
} else {
|
|
if (percent_scale > 100) {
|
|
percent_scale -= 25;
|
|
} else {
|
|
percent_scale -= 5;
|
|
}
|
|
}
|
|
cpu_scale_factor = percent_scale/100.0;
|
|
|
|
if (cpu_scale_factor < CPU_SCALE_SLOWEST) {
|
|
cpu_scale_factor = CPU_SCALE_SLOWEST;
|
|
}
|
|
|
|
LOG("native set emulation percentage to %f", cpu_scale_factor);
|
|
|
|
if (video_backend->animation_showCPUSpeed) {
|
|
video_backend->animation_showCPUSpeed();
|
|
}
|
|
|
|
#warning HACK TODO FIXME ... refactor timing stuff
|
|
timing_toggle_cpu_speed();
|
|
timing_toggle_cpu_speed();
|
|
|
|
pthread_mutex_unlock(&interface_mutex);
|
|
}
|
|
|
|
static inline bool _sprout_menu(float x, float y) {
|
|
|
|
if (! (_is_point_on_left_menu(x, y) || _is_point_on_right_menu(x, y)) ) {
|
|
return false;
|
|
}
|
|
|
|
bool isTopLeft = false;
|
|
int col = -1;
|
|
int row = -1;
|
|
|
|
_screen_to_menu(x, y, &col, &row, &isTopLeft);
|
|
|
|
if (isTopLeft) {
|
|
|
|
// hide other
|
|
_hide_top_right();
|
|
|
|
// maybe show this one
|
|
if (!hudTopLeft.isShowing) {
|
|
if (col == 0 && row == 0) {
|
|
_show_top_left();
|
|
}
|
|
}
|
|
|
|
return hudTopLeft.isShowing;
|
|
} else {
|
|
|
|
// hide other
|
|
_hide_top_left();
|
|
|
|
// maybe show this one
|
|
if (!hudTopRight.isShowing) {
|
|
if (col == 1 && row == 0) {
|
|
_show_top_right();
|
|
}
|
|
}
|
|
return hudTopRight.isShowing;
|
|
}
|
|
}
|
|
|
|
static inline bool _tap_menu_item(float x, float y) {
|
|
if (! (_is_point_on_left_menu(x, y) || _is_point_on_right_menu(x, y)) ) {
|
|
return false;
|
|
}
|
|
|
|
bool isTopLeft = false;
|
|
int col = -1;
|
|
int row = -1;
|
|
|
|
_screen_to_menu(x, y, &col, &row, &isTopLeft);
|
|
|
|
int selectedItem = -1;
|
|
if (isTopLeft && hudTopLeft.isShowing) {
|
|
selectedItem = topLeftTemplateShowing[row][col];
|
|
} else if (!isTopLeft && hudTopRight.isShowing) {
|
|
selectedItem = topRightTemplateShowing[row][col];
|
|
}
|
|
|
|
switch (selectedItem) {
|
|
|
|
case MOUSETEXT_LEFT:
|
|
LOG("decreasing cpu speed...");
|
|
_decrease_cpu_speed();
|
|
break;
|
|
|
|
case MOUSETEXT_RIGHT:
|
|
LOG("increasing cpu speed...");
|
|
_increase_cpu_speed();
|
|
break;
|
|
|
|
case MOUSETEXT_CHECKMARK:
|
|
LOG("showing main menu...");
|
|
if (video_backend->hostenv_showMainMenu) {
|
|
video_backend->hostenv_showMainMenu();
|
|
}
|
|
_hide_top_right();
|
|
break;
|
|
|
|
case ICONTEXT_MENU_TOUCHJOY:
|
|
LOG("showing touch joystick ...");
|
|
keydriver_setTouchKeyboardOwnsScreen(false);
|
|
if (video_backend->animation_hideTouchKeyboard) {
|
|
video_backend->animation_hideTouchKeyboard();
|
|
}
|
|
joydriver_setTouchJoystickOwnsScreen(true);
|
|
if (video_backend->animation_showTouchJoystick) {
|
|
video_backend->animation_showTouchJoystick();
|
|
}
|
|
topLeftTemplateShowing[1][0] = ICONTEXT_UPPERCASE;
|
|
_hide_top_left();
|
|
break;
|
|
|
|
case ICONTEXT_UPPERCASE:
|
|
LOG("showing touch keyboard ...");
|
|
joydriver_setTouchJoystickOwnsScreen(false);
|
|
if (video_backend->animation_hideTouchJoystick) {
|
|
video_backend->animation_hideTouchJoystick();
|
|
}
|
|
keydriver_setTouchKeyboardOwnsScreen(true);
|
|
if (video_backend->animation_showTouchKeyboard) {
|
|
video_backend->animation_showTouchKeyboard();
|
|
}
|
|
topLeftTemplateShowing[1][0] = ICONTEXT_MENU_TOUCHJOY;
|
|
_hide_top_left();
|
|
break;
|
|
|
|
case ICONTEXT_MENU_SPROUT:
|
|
LOG("sprout ...");
|
|
break;
|
|
|
|
case ICONTEXT_NONACTIONABLE:
|
|
default:
|
|
LOG("nonactionable ...");
|
|
_hide_top_left();
|
|
_hide_top_right();
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// GLCustom functions
|
|
|
|
static void _setup_touchmenu_top_left(GLModel *parent) {
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom;
|
|
|
|
hudMenu->tplWidth = MENU_TEMPLATE_COLS;
|
|
hudMenu->tplHeight = MENU_TEMPLATE_ROWS;
|
|
hudMenu->pixWidth = MENU_FB_WIDTH;
|
|
hudMenu->pixHeight = MENU_FB_HEIGHT;
|
|
|
|
topLeftTemplateHidden[0][0] = ICONTEXT_MENU_SPROUT;
|
|
topLeftTemplateHidden[0][1] = ICONTEXT_NONACTIONABLE;
|
|
topLeftTemplateHidden[1][0] = ICONTEXT_NONACTIONABLE;
|
|
topLeftTemplateHidden[1][1] = ICONTEXT_NONACTIONABLE;
|
|
|
|
topLeftTemplateShowing[0][0] = ICONTEXT_MENU_SPROUT;
|
|
topLeftTemplateShowing[0][1] = MOUSETEXT_RIGHT;
|
|
topLeftTemplateShowing[1][0] = ICONTEXT_UPPERCASE;
|
|
topLeftTemplateShowing[1][1] = ICONTEXT_NONACTIONABLE;
|
|
|
|
const unsigned int size = sizeof(topLeftTemplateHidden);
|
|
hudMenu->tpl = calloc(size, 1);
|
|
hudMenu->pixels = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1);
|
|
hudMenu->pixelsAlt = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1);
|
|
|
|
_present_menu(parent, topLeftTemplateHidden[0]);
|
|
}
|
|
|
|
static void _setup_touchmenu_top_right(GLModel *parent) {
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom;
|
|
|
|
hudMenu->tplWidth = MENU_TEMPLATE_COLS;
|
|
hudMenu->tplHeight = MENU_TEMPLATE_ROWS;
|
|
hudMenu->pixWidth = MENU_FB_WIDTH;
|
|
hudMenu->pixHeight = MENU_FB_HEIGHT;
|
|
|
|
topRightTemplateHidden[0][0] = ICONTEXT_NONACTIONABLE;
|
|
topRightTemplateHidden[0][1] = ICONTEXT_MENU_SPROUT;
|
|
topRightTemplateHidden[1][0] = ICONTEXT_NONACTIONABLE;
|
|
topRightTemplateHidden[1][1] = ICONTEXT_NONACTIONABLE;
|
|
|
|
topRightTemplateShowing[0][0] = MOUSETEXT_LEFT;
|
|
topRightTemplateShowing[0][1] = ICONTEXT_MENU_SPROUT;
|
|
topRightTemplateShowing[1][0] = ICONTEXT_NONACTIONABLE;
|
|
topRightTemplateShowing[1][1] = MOUSETEXT_CHECKMARK;
|
|
|
|
const unsigned int size = sizeof(topRightTemplateHidden);
|
|
hudMenu->tpl = calloc(size, 1);
|
|
hudMenu->pixels = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1);
|
|
hudMenu->pixelsAlt = calloc(MENU_FB_WIDTH * MENU_FB_HEIGHT, 1);
|
|
|
|
_present_menu(parent, topRightTemplateHidden[0]);
|
|
}
|
|
|
|
static void *_create_touchmenu(void) {
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)calloc(sizeof(GLModelHUDMenu), 1);
|
|
if (hudMenu) {
|
|
hudMenu->blackIsTransparent = true;
|
|
hudMenu->opaquePixelHalo = true;
|
|
}
|
|
return hudMenu;
|
|
}
|
|
|
|
static void _destroy_touchmenu(GLModel *parent) {
|
|
GLModelHUDMenu *hudMenu = (GLModelHUDMenu *)parent->custom;
|
|
if (!hudMenu) {
|
|
return;
|
|
}
|
|
FREE(hudMenu->pixelsAlt);
|
|
glhud_destroyDefault(parent);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// GLNode functions
|
|
|
|
static void gltouchmenu_setup(void) {
|
|
LOG("gltouchmenu_setup ...");
|
|
|
|
mdlDestroyModel(&hudTopLeft.model);
|
|
hudTopLeft.model = mdlCreateQuad(-1.0, 1.0-MENU_OBJ_H, MENU_OBJ_W, MENU_OBJ_H, MODEL_DEPTH, MENU_FB_WIDTH, MENU_FB_HEIGHT, GL_RGBA/*RGBA_8888*/, (GLCustom){
|
|
.create = &_create_touchmenu,
|
|
.setup = &_setup_touchmenu_top_left,
|
|
.destroy = &_destroy_touchmenu,
|
|
});
|
|
if (!hudTopLeft.model) {
|
|
LOG("gltouchmenu initialization problem");
|
|
return;
|
|
}
|
|
if (!hudTopLeft.model->custom) {
|
|
LOG("gltouchmenu HUD initialization problem");
|
|
return;
|
|
}
|
|
|
|
mdlDestroyModel(&hudTopRight.model);
|
|
hudTopRight.model = mdlCreateQuad(1.0-MENU_OBJ_W, 1.0-MENU_OBJ_H, MENU_OBJ_W, MENU_OBJ_H, MODEL_DEPTH, MENU_FB_WIDTH, MENU_FB_HEIGHT, GL_RGBA/*RGBA_8888*/, (GLCustom){
|
|
.create = &_create_touchmenu,
|
|
.setup = &_setup_touchmenu_top_right,
|
|
.destroy = &_destroy_touchmenu,
|
|
});
|
|
if (!hudTopRight.model) {
|
|
LOG("gltouchmenu initialization problem");
|
|
return;
|
|
}
|
|
if (!hudTopRight.model->custom) {
|
|
LOG("gltouchmenu HUD initialization problem");
|
|
return;
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &timingBegin);
|
|
|
|
isAvailable = true;
|
|
|
|
GL_ERRLOG("gltouchmenu_setup");
|
|
}
|
|
|
|
static void gltouchmenu_shutdown(void) {
|
|
LOG("gltouchmenu_shutdown ...");
|
|
if (!isAvailable) {
|
|
return;
|
|
}
|
|
|
|
isAvailable = false;
|
|
|
|
mdlDestroyModel(&hudTopLeft.model);
|
|
mdlDestroyModel(&hudTopRight.model);
|
|
}
|
|
|
|
static void gltouchmenu_render(void) {
|
|
if (!isAvailable) {
|
|
return;
|
|
}
|
|
if (!isEnabled) {
|
|
return;
|
|
}
|
|
|
|
float alpha = _get_menu_visibility();
|
|
if (alpha <= 0.0) {
|
|
return;
|
|
}
|
|
|
|
glViewport(0, 0, touchport.width, touchport.height); // NOTE : show these HUD elements beyond the A2 framebuffer dimensions
|
|
glUniform1f(alphaValue, alpha);
|
|
|
|
// render top left sprouting menu
|
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHMENU_LEFT);
|
|
glBindTexture(GL_TEXTURE_2D, hudTopLeft.model->textureName);
|
|
if (hudTopLeft.model->texDirty) {
|
|
hudTopLeft.model->texDirty = false;
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, hudTopLeft.model->texWidth, hudTopLeft.model->texHeight, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, hudTopLeft.model->texPixels);
|
|
}
|
|
if (hudTopLeft.modelDirty) {
|
|
hudTopLeft.modelDirty = false;
|
|
glBindBuffer(GL_ARRAY_BUFFER, hudTopLeft.model->posBufferName);
|
|
glBufferData(GL_ARRAY_BUFFER, hudTopLeft.model->positionArraySize, hudTopLeft.model->positions, GL_DYNAMIC_DRAW);
|
|
}
|
|
glUniform1i(uniformTex2Use, TEXTURE_ID_TOUCHMENU_LEFT);
|
|
glhud_renderDefault(hudTopLeft.model);
|
|
|
|
// render top right sprouting menu
|
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHMENU_RIGHT);
|
|
glBindTexture(GL_TEXTURE_2D, hudTopRight.model->textureName);
|
|
if (hudTopRight.model->texDirty) {
|
|
hudTopRight.model->texDirty = false;
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, hudTopRight.model->texWidth, hudTopRight.model->texHeight, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, hudTopRight.model->texPixels);
|
|
}
|
|
if (hudTopRight.modelDirty) {
|
|
hudTopRight.modelDirty = false;
|
|
glBindBuffer(GL_ARRAY_BUFFER, hudTopRight.model->posBufferName);
|
|
glBufferData(GL_ARRAY_BUFFER, hudTopRight.model->positionArraySize, hudTopRight.model->positions, GL_DYNAMIC_DRAW);
|
|
}
|
|
glUniform1i(uniformTex2Use, TEXTURE_ID_TOUCHMENU_RIGHT);
|
|
glhud_renderDefault(hudTopRight.model);
|
|
|
|
GL_ERRLOG("gltouchmenu_render");
|
|
}
|
|
|
|
static void gltouchmenu_reshape(int w, int h) {
|
|
LOG("gltouchmenu_reshape(%d, %d)", w, h);
|
|
|
|
touchport.topLeftX = 0;
|
|
touchport.topLeftY = 0;
|
|
touchport.topRightY = 0;
|
|
|
|
if (w > touchport.width) {
|
|
const int menuPixelW = w * (MENU_OBJ_W/2.f);
|
|
touchport.width = w;
|
|
touchport.topLeftXHalf = menuPixelW/2;
|
|
touchport.topLeftXMax = menuPixelW;
|
|
touchport.topRightX = w - menuPixelW;
|
|
touchport.topRightXHalf = w - (menuPixelW/2);
|
|
touchport.topRightXMax = w;
|
|
}
|
|
if (h > touchport.height) {
|
|
const int menuPixelH = h * (MENU_OBJ_H/2.f);
|
|
touchport.height = h;
|
|
touchport.topLeftYHalf = menuPixelH/2;
|
|
touchport.topLeftYMax = menuPixelH;
|
|
touchport.topRightYHalf = menuPixelH/2;
|
|
touchport.topRightYMax = menuPixelH;
|
|
}
|
|
}
|
|
|
|
static bool gltouchmenu_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
|
|
|
if (!isAvailable) {
|
|
return false;
|
|
}
|
|
if (!isEnabled) {
|
|
return false;
|
|
}
|
|
|
|
LOG("gltouchmenu_onTouchEvent ...");
|
|
|
|
float x = x_coords[pointer_idx];
|
|
float y = y_coords[pointer_idx];
|
|
|
|
bool handled = (_is_point_on_left_menu(x, y) || _is_point_on_right_menu(x, y));
|
|
|
|
switch (action) {
|
|
case TOUCH_DOWN:
|
|
case TOUCH_POINTER_DOWN:
|
|
_sprout_menu(x, y);
|
|
break;
|
|
|
|
case TOUCH_MOVE:
|
|
break;
|
|
|
|
case TOUCH_UP:
|
|
case TOUCH_POINTER_UP:
|
|
_tap_menu_item(x, y);
|
|
break;
|
|
|
|
case TOUCH_CANCEL:
|
|
LOG("---MENU TOUCH CANCEL");
|
|
break;
|
|
|
|
default:
|
|
LOG("!!!MENU UNKNOWN TOUCH EVENT : %d", action);
|
|
break;
|
|
}
|
|
|
|
if (handled) {
|
|
clock_gettime(CLOCK_MONOTONIC, &timingBegin);
|
|
}
|
|
|
|
return handled;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Animation and settings handling
|
|
|
|
static bool gltouchmenu_isTouchMenuAvailable(void) {
|
|
return isAvailable;
|
|
}
|
|
|
|
static void gltouchmenu_setTouchMenuEnabled(bool enabled) {
|
|
isEnabled = enabled;
|
|
}
|
|
|
|
static void _animation_showTouchMenu(void) {
|
|
clock_gettime(CLOCK_MONOTONIC, &timingBegin);
|
|
}
|
|
|
|
static void _animation_hideTouchMenu(void) {
|
|
timingBegin = (struct timespec){ 0 };
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Constructor
|
|
|
|
__attribute__((constructor(CTOR_PRIORITY_LATE)))
|
|
static void _init_gltouchmenu(void) {
|
|
LOG("Registering OpenGL software touch menu");
|
|
|
|
video_backend->animation_showTouchMenu = &_animation_showTouchMenu;
|
|
video_backend->animation_hideTouchMenu = &_animation_hideTouchMenu;
|
|
|
|
interface_isTouchMenuAvailable = &gltouchmenu_isTouchMenuAvailable;
|
|
interface_setTouchMenuEnabled = &gltouchmenu_setTouchMenuEnabled;
|
|
|
|
glnode_registerNode(RENDER_TOP, (GLNode){
|
|
.setup = &gltouchmenu_setup,
|
|
.shutdown = &gltouchmenu_shutdown,
|
|
.render = &gltouchmenu_render,
|
|
.reshape = &gltouchmenu_reshape,
|
|
.onTouchEvent = &gltouchmenu_onTouchEvent,
|
|
});
|
|
}
|
|
|