2015-02-18 04:23:06 +00:00
|
|
|
/*
|
2015-10-22 05:13:26 +00:00
|
|
|
* Apple // emulator for *ix
|
2015-02-18 04:23:06 +00:00
|
|
|
*
|
|
|
|
* This software package is subject to the GNU General Public License
|
2015-10-22 05:13:26 +00:00
|
|
|
* version 3 or later (your choice) as published by the Free Software
|
2015-02-18 04:23:06 +00:00
|
|
|
* Foundation.
|
|
|
|
*
|
2015-10-22 05:13:26 +00:00
|
|
|
* Copyright 2013-2015 Aaron Culliney
|
2015-02-18 04:23:06 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
#include "video/gltouchjoy.h"
|
2015-04-12 22:35:16 +00:00
|
|
|
|
|
|
|
#if !INTERFACE_TOUCH
|
|
|
|
#error this is a touch interface module, possibly you mean to not compile this at all?
|
|
|
|
#endif
|
2015-02-18 04:23:06 +00:00
|
|
|
|
2015-04-27 01:12:56 +00:00
|
|
|
#define MODEL_DEPTH -1/32.f
|
2015-04-11 07:30:23 +00:00
|
|
|
|
2016-01-02 23:05:32 +00:00
|
|
|
#define AXIS_TEMPLATE_COLS 3
|
|
|
|
#define AXIS_TEMPLATE_ROWS 3
|
2015-04-04 19:51:32 +00:00
|
|
|
|
|
|
|
#define BUTTON_TEMPLATE_COLS 1
|
|
|
|
#define BUTTON_TEMPLATE_ROWS 1
|
|
|
|
|
2015-05-29 06:23:21 +00:00
|
|
|
#define AXIS_FB_WIDTH (AXIS_TEMPLATE_COLS * FONT80_WIDTH_PIXELS)
|
2015-04-04 19:51:32 +00:00
|
|
|
#define AXIS_FB_HEIGHT (AXIS_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-05-29 06:23:21 +00:00
|
|
|
#define BUTTON_FB_WIDTH (BUTTON_TEMPLATE_COLS * FONT80_WIDTH_PIXELS)
|
2015-04-04 19:51:32 +00:00
|
|
|
#define BUTTON_FB_HEIGHT (BUTTON_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
#define AXIS_OBJ_W 0.15
|
|
|
|
#define AXIS_OBJ_H 0.2
|
2015-04-04 19:51:32 +00:00
|
|
|
#define AXIS_OBJ_HALF_W (AXIS_OBJ_W/2.f)
|
|
|
|
#define AXIS_OBJ_HALF_H (AXIS_OBJ_H/2.f)
|
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
#define BUTTON_OBJ_W 0.075
|
|
|
|
#define BUTTON_OBJ_H 0.1
|
2015-04-04 19:51:32 +00:00
|
|
|
#define BUTTON_OBJ_HALF_W (BUTTON_OBJ_W/2.f)
|
|
|
|
#define BUTTON_OBJ_HALF_H (BUTTON_OBJ_H/2.f)
|
|
|
|
|
2015-06-07 04:28:12 +00:00
|
|
|
#define BUTTON_SWITCH_THRESHOLD_DEFAULT 22
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
GLTouchJoyGlobals joyglobals = { 0 };
|
|
|
|
GLTouchJoyAxes axes = { 0 };
|
|
|
|
GLTouchJoyButtons buttons = { 0 };
|
|
|
|
|
2015-08-02 19:37:28 +00:00
|
|
|
static struct {
|
2015-08-16 05:02:51 +00:00
|
|
|
GLTouchJoyVariant *joys;
|
|
|
|
GLTouchJoyVariant *kpad;
|
|
|
|
GLTouchJoyVariant *curr;
|
|
|
|
} variant = { 0 };
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
// viewport touch
|
|
|
|
static struct {
|
|
|
|
int width;
|
|
|
|
int height;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
// Axis box
|
|
|
|
int axisX;
|
|
|
|
int axisXMax;
|
|
|
|
int axisY;
|
|
|
|
int axisYMax;
|
2015-04-04 19:51:32 +00:00
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
// Button box
|
|
|
|
int buttonX;
|
|
|
|
int buttonXMax;
|
|
|
|
int buttonY;
|
|
|
|
int buttonYMax;
|
|
|
|
|
|
|
|
// TODO FIXME : support 2-players!
|
|
|
|
} touchport = { 0 };
|
2015-04-04 19:51:32 +00:00
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
#define AZIMUTH_CLASS(CLS, ...) \
|
2016-01-03 20:08:47 +00:00
|
|
|
MODEL_CLASS(CLS, \
|
|
|
|
GLuint vertShader; \
|
|
|
|
GLuint fragShader; \
|
|
|
|
GLuint program; \
|
|
|
|
GLint uniformMVPIdx;);
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
AZIMUTH_CLASS(GLModelJoystickAzimuth);
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
static void gltouchjoy_applyPrefs(void);
|
|
|
|
static void gltouchjoy_shutdown(void);
|
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// joystick azimuth model
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
static void _azimuth_destroy_model(GLModel *parent) {
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
GLModelJoystickAzimuth *azimuthJoystick = (GLModelJoystickAzimuth *)parent->custom;
|
2016-01-03 20:08:47 +00:00
|
|
|
if (!azimuthJoystick) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
// detach and delete the Azimuth shaders
|
2016-01-03 20:08:47 +00:00
|
|
|
// 2015/11/06 NOTE : Tegra 2 for mobile has a bug whereby you cannot detach/delete shaders immediately after
|
|
|
|
// creating the program. So we delete them during the shutdown sequence instead.
|
|
|
|
// https://code.google.com/p/android/issues/detail?id=61832
|
|
|
|
|
|
|
|
if (azimuthJoystick->program != UNINITIALIZED_GL) {
|
|
|
|
glDetachShader(azimuthJoystick->program, azimuthJoystick->vertShader);
|
|
|
|
glDetachShader(azimuthJoystick->program, azimuthJoystick->fragShader);
|
|
|
|
glDeleteShader(azimuthJoystick->vertShader);
|
|
|
|
glDeleteShader(azimuthJoystick->fragShader);
|
|
|
|
|
|
|
|
azimuthJoystick->vertShader = UNINITIALIZED_GL;
|
|
|
|
azimuthJoystick->fragShader = UNINITIALIZED_GL;
|
|
|
|
|
|
|
|
glDeleteProgram(azimuthJoystick->program);
|
|
|
|
azimuthJoystick->program = UNINITIALIZED_GL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE(parent->custom);
|
|
|
|
}
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
static void *_azimuth_create_model(GLModel *parent) {
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
parent->custom = CALLOC(sizeof(GLModelJoystickAzimuth), 1);
|
|
|
|
GLModelJoystickAzimuth *azimuthJoystick = (GLModelJoystickAzimuth *)parent->custom;
|
2016-01-03 20:08:47 +00:00
|
|
|
|
|
|
|
if (!azimuthJoystick) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// degenerate the quad model into just a single line model ... (should not need to adjust allocated memory size
|
|
|
|
// since we should be using less than what was originally allocated)
|
|
|
|
parent->primType = GL_LINES;
|
|
|
|
parent->numVertices = 2;
|
|
|
|
GLsizei posTypeSize = getGLTypeSize(parent->positionType);
|
|
|
|
parent->positionArraySize = (parent->positionSize * posTypeSize * parent->numVertices);
|
|
|
|
parent->numElements = 2;
|
|
|
|
GLsizei eltTypeSize = getGLTypeSize(parent->elementType);
|
|
|
|
parent->elementArraySize = (eltTypeSize * parent->numElements);
|
|
|
|
|
|
|
|
azimuthJoystick->vertShader = UNINITIALIZED_GL;
|
|
|
|
azimuthJoystick->fragShader = UNINITIALIZED_GL;
|
|
|
|
azimuthJoystick->program = UNINITIALIZED_GL;
|
|
|
|
azimuthJoystick->uniformMVPIdx = UNINITIALIZED_GL;
|
|
|
|
|
|
|
|
bool err = true;
|
|
|
|
demoSource *vtxSource = NULL;
|
|
|
|
demoSource *frgSource = NULL;
|
|
|
|
do {
|
|
|
|
// load/setup specific shaders
|
|
|
|
|
|
|
|
vtxSource = glshader_createSource("SolidColor.vsh");
|
|
|
|
if (!vtxSource) {
|
|
|
|
ERRLOG("Cannot compile vertex shader for joystick azimuth!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
frgSource = glshader_createSource("SolidColor.fsh");
|
|
|
|
if (!frgSource) {
|
|
|
|
ERRLOG("Cannot compile fragment shader for joystick azimuth!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build/use Program
|
|
|
|
azimuthJoystick->program = glshader_buildProgram(vtxSource, frgSource, /*withTexcoord:*/false, &azimuthJoystick->vertShader, &azimuthJoystick->fragShader);
|
|
|
|
|
|
|
|
azimuthJoystick->uniformMVPIdx = glGetUniformLocation(azimuthJoystick->program, "modelViewProjectionMatrix");
|
|
|
|
if (azimuthJoystick->uniformMVPIdx < 0) {
|
2016-01-30 18:35:55 +00:00
|
|
|
LOG("OOPS, no modelViewProjectionMatrix in Azimuth shader : %d", azimuthJoystick->uniformMVPIdx);
|
2016-01-03 20:08:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = false;
|
|
|
|
} while (0);
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
GL_ERRLOG("build Aziumth joystick");
|
2016-01-03 20:08:47 +00:00
|
|
|
|
|
|
|
if (vtxSource) {
|
|
|
|
glshader_destroySource(vtxSource);
|
|
|
|
}
|
|
|
|
if (frgSource) {
|
|
|
|
glshader_destroySource(frgSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
2016-01-30 18:35:55 +00:00
|
|
|
_azimuth_destroy_model(parent);
|
2016-01-03 20:08:47 +00:00
|
|
|
azimuthJoystick = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return azimuthJoystick;
|
|
|
|
}
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
static void _azimuth_render(void) {
|
2016-01-06 07:19:12 +00:00
|
|
|
if (!axes.azimuthModel) {
|
|
|
|
return;
|
|
|
|
}
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
GLModelJoystickAzimuth *azimuthJoystick = (GLModelJoystickAzimuth *)axes.azimuthModel->custom;
|
2016-01-03 20:08:47 +00:00
|
|
|
|
|
|
|
// use azimuth (SolidColor) program
|
|
|
|
glUseProgram(azimuthJoystick->program);
|
|
|
|
|
|
|
|
glUniformMatrix4fv(azimuthJoystick->uniformMVPIdx, 1, GL_FALSE, mvpIdentity);
|
|
|
|
|
|
|
|
// NOTE : assuming we should just upload new postion data every time ...
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, axes.azimuthModel->posBufferName);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, axes.azimuthModel->positionArraySize, axes.azimuthModel->positions, GL_DYNAMIC_DRAW);
|
|
|
|
|
|
|
|
// Bind our vertex array object
|
|
|
|
#if USE_VAO
|
|
|
|
glBindVertexArray(axes.azimuthModel->vaoName);
|
|
|
|
#else
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, axes.azimuthModel->posBufferName);
|
|
|
|
|
|
|
|
GLsizei posTypeSize = getGLTypeSize(axes.azimuthModel->positionType);
|
|
|
|
|
|
|
|
// Set up parmeters for position attribute in the VAO including, size, type, stride, and offset in the currenly
|
|
|
|
// bound VAO This also attaches the position VBO to the VAO
|
|
|
|
glVertexAttribPointer(POS_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
|
|
|
axes.azimuthModel->positionSize, // How many elements are there per position?
|
|
|
|
axes.azimuthModel->positionType, // What is the type of this data?
|
|
|
|
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
|
|
|
axes.azimuthModel->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)?
|
|
|
|
0); // What is the offset in the VBO to the position data?
|
|
|
|
glEnableVertexAttribArray(POS_ATTRIB_IDX);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, axes.azimuthModel->elementBufferName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// draw it
|
|
|
|
glDrawElements(axes.azimuthModel->primType, axes.azimuthModel->numElements, axes.azimuthModel->elementType, 0);
|
|
|
|
|
|
|
|
// back to main framebuffer/quad program
|
|
|
|
glUseProgram(mainShaderProgram);
|
|
|
|
|
2016-01-30 18:35:55 +00:00
|
|
|
GL_ERRLOG("Azimuth render");
|
2016-01-03 20:08:47 +00:00
|
|
|
}
|
|
|
|
|
2015-04-11 07:30:23 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-01-03 19:57:48 +00:00
|
|
|
static void _setup_axis_hud(GLModel *parent) {
|
2015-08-01 23:46:09 +00:00
|
|
|
if (UNLIKELY(!parent)) {
|
|
|
|
LOG("gltouchjoy WARN : cannot setup axis object without parent");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 18:05:18 +00:00
|
|
|
if (!joyglobals.showControls) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
|
|
|
|
|
|
|
if (hudElement->tpl == NULL) {
|
|
|
|
// deferred construction ...
|
|
|
|
const char axisTemplate[AXIS_TEMPLATE_ROWS][AXIS_TEMPLATE_COLS+1] = {
|
2016-01-02 23:05:32 +00:00
|
|
|
" @ ",
|
|
|
|
"@+@",
|
|
|
|
" @ ",
|
2015-04-11 19:29:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const unsigned int size = sizeof(axisTemplate);
|
2015-12-31 06:16:57 +00:00
|
|
|
hudElement->tpl = CALLOC(size, 1);
|
2015-04-11 19:29:44 +00:00
|
|
|
hudElement->tplWidth = AXIS_TEMPLATE_COLS;
|
|
|
|
hudElement->tplHeight = AXIS_TEMPLATE_ROWS;
|
|
|
|
memcpy(hudElement->tpl, axisTemplate, size);
|
|
|
|
|
2015-12-31 06:16:57 +00:00
|
|
|
hudElement->pixels = CALLOC(AXIS_FB_WIDTH * AXIS_FB_HEIGHT, 1);
|
2015-04-11 19:29:44 +00:00
|
|
|
hudElement->pixWidth = AXIS_FB_WIDTH;
|
|
|
|
hudElement->pixHeight = AXIS_FB_HEIGHT;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
|
|
|
|
const unsigned int row = (AXIS_TEMPLATE_COLS+1);
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
uint8_t *rosetteChars = variant.curr->rosetteChars();
|
2015-08-16 05:02:51 +00:00
|
|
|
for (unsigned int i=0; i<ROSETTE_ROWS; i++) {
|
|
|
|
for (unsigned int j=0; j<ROSETTE_COLS; j++) {
|
2016-04-06 05:04:57 +00:00
|
|
|
((hudElement->tpl)+(row*i))[j] = rosetteChars[(i*ROSETTE_ROWS)+j];
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
|
2015-04-12 18:27:33 +00:00
|
|
|
glhud_setupDefault(parent);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 19:57:48 +00:00
|
|
|
static void *_create_axis_hud(GLModel *parent) {
|
|
|
|
parent->custom = glhud_createDefault();
|
|
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
2015-04-27 01:12:56 +00:00
|
|
|
if (hudElement) {
|
|
|
|
hudElement->blackIsTransparent = true;
|
2016-01-03 19:57:48 +00:00
|
|
|
_setup_axis_hud(parent);
|
2015-04-27 01:12:56 +00:00
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
return hudElement;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 19:57:48 +00:00
|
|
|
static void _setup_button_hud(GLModel *parent) {
|
2015-08-01 23:46:09 +00:00
|
|
|
if (UNLIKELY(!parent)) {
|
|
|
|
LOG("gltouchjoy WARN : cannot setup button object without parent");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 18:05:18 +00:00
|
|
|
if (!joyglobals.showControls) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
|
|
|
|
|
|
|
if (hudElement->tpl == NULL) {
|
|
|
|
// deferred construction ...
|
|
|
|
const char buttonTemplate[BUTTON_TEMPLATE_ROWS][BUTTON_TEMPLATE_COLS+1] = {
|
|
|
|
"@",
|
|
|
|
};
|
|
|
|
|
|
|
|
const unsigned int size = sizeof(buttonTemplate);
|
2015-12-31 06:16:57 +00:00
|
|
|
hudElement->tpl = CALLOC(size, 1);
|
2015-04-11 19:29:44 +00:00
|
|
|
hudElement->tplWidth = BUTTON_TEMPLATE_COLS;
|
|
|
|
hudElement->tplHeight = BUTTON_TEMPLATE_ROWS;
|
|
|
|
memcpy(hudElement->tpl, buttonTemplate, size);
|
|
|
|
|
2015-12-31 06:16:57 +00:00
|
|
|
hudElement->pixels = CALLOC(BUTTON_FB_WIDTH * BUTTON_FB_HEIGHT, 1);
|
2015-04-11 19:29:44 +00:00
|
|
|
hudElement->pixWidth = BUTTON_FB_WIDTH;
|
|
|
|
hudElement->pixHeight = BUTTON_FB_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
const unsigned int row = (BUTTON_TEMPLATE_COLS+1);
|
|
|
|
((hudElement->tpl)+(row*0))[0] = buttons.activeChar;
|
|
|
|
|
2015-04-12 18:27:33 +00:00
|
|
|
glhud_setupDefault(parent);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 19:57:48 +00:00
|
|
|
static void *_create_button_hud(GLModel *parent) {
|
|
|
|
parent->custom = glhud_createDefault();
|
|
|
|
GLModelHUDElement *hudElement = (GLModelHUDElement *)parent->custom;
|
|
|
|
if (hudElement) {
|
|
|
|
hudElement->blackIsTransparent = true;
|
|
|
|
_setup_button_hud(parent);
|
|
|
|
}
|
|
|
|
return hudElement;
|
|
|
|
}
|
|
|
|
|
2015-06-07 04:28:12 +00:00
|
|
|
static inline void _setup_button_object_with_char(char newChar) {
|
|
|
|
if (buttons.activeChar != newChar) {
|
|
|
|
buttons.activeChar = newChar;
|
2016-01-03 19:57:48 +00:00
|
|
|
_setup_button_hud(buttons.model);
|
2015-06-07 04:28:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2015-08-30 23:55:57 +00:00
|
|
|
static inline void resetState() {
|
2015-09-16 03:39:30 +00:00
|
|
|
LOG("...");
|
2015-08-30 23:55:57 +00:00
|
|
|
axes.trackingIndex = TRACKING_NONE;
|
|
|
|
buttons.trackingIndex = TRACKING_NONE;
|
|
|
|
variant.joys->resetState();
|
|
|
|
variant.kpad->resetState();
|
|
|
|
}
|
|
|
|
|
2015-04-12 22:35:16 +00:00
|
|
|
static void gltouchjoy_setup(void) {
|
2015-09-16 03:39:30 +00:00
|
|
|
LOG("...");
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
gltouchjoy_shutdown();
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
if (joyglobals.prefsChanged) {
|
|
|
|
gltouchjoy_applyPrefs();
|
|
|
|
}
|
2015-06-07 04:28:12 +00:00
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
// axis origin object
|
2016-01-02 21:10:02 +00:00
|
|
|
|
|
|
|
axes.model = mdlCreateQuad((GLModelParams_s){
|
|
|
|
.skew_x = -1.05,
|
|
|
|
.skew_y = -1.0,
|
|
|
|
.z = MODEL_DEPTH,
|
|
|
|
.obj_w = AXIS_OBJ_W,
|
|
|
|
.obj_h = AXIS_OBJ_H,
|
|
|
|
.positionUsageHint = GL_DYNAMIC_DRAW, // positions can change
|
|
|
|
.tex_w = AXIS_FB_WIDTH,
|
|
|
|
.tex_h = AXIS_FB_HEIGHT,
|
|
|
|
.texcoordUsageHint = GL_DYNAMIC_DRAW, // so can texture
|
|
|
|
}, (GLCustom){
|
2016-01-03 19:57:48 +00:00
|
|
|
.create = &_create_axis_hud,
|
2015-04-12 18:27:33 +00:00
|
|
|
.destroy = &glhud_destroyDefault,
|
2016-01-02 21:10:02 +00:00
|
|
|
});
|
2015-04-11 19:29:44 +00:00
|
|
|
if (!axes.model) {
|
2015-04-11 07:30:23 +00:00
|
|
|
LOG("gltouchjoy not initializing axis");
|
2015-04-02 02:59:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-05-22 05:31:06 +00:00
|
|
|
if (!axes.model->custom) {
|
|
|
|
LOG("gltouchjoy axes initialization problem");
|
|
|
|
return;
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-02-20 04:00:42 +00:00
|
|
|
// axis azimuth object
|
2016-01-03 20:08:47 +00:00
|
|
|
|
|
|
|
bool azimuthError = true;
|
|
|
|
do {
|
|
|
|
axes.azimuthModel = mdlCreateQuad((GLModelParams_s){
|
|
|
|
.skew_x = -1.05,
|
|
|
|
.skew_y = -1.0,
|
|
|
|
.z = MODEL_DEPTH,
|
|
|
|
.obj_w = AXIS_OBJ_W,
|
|
|
|
.obj_h = AXIS_OBJ_H,
|
|
|
|
.positionUsageHint = GL_DYNAMIC_DRAW, // positions can change
|
|
|
|
.tex_w = 0,
|
|
|
|
.tex_h = 0,
|
|
|
|
.texcoordUsageHint = UNINITIALIZED_GL, // no texture data
|
|
|
|
}, (GLCustom){
|
2016-01-30 18:35:55 +00:00
|
|
|
.create = &_azimuth_create_model,
|
|
|
|
.destroy = &_azimuth_destroy_model,
|
2016-01-03 20:08:47 +00:00
|
|
|
});
|
|
|
|
if (!axes.azimuthModel) {
|
|
|
|
LOG("gltouchjoy azimuth model initialization problem");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!axes.azimuthModel->custom) {
|
|
|
|
LOG("gltouchjoy azimuth custom model initialization problem");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
azimuthError = false;
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
if (azimuthError) {
|
|
|
|
mdlDestroyModel(&axes.azimuthModel);
|
|
|
|
}
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
// button object
|
2016-04-06 05:04:57 +00:00
|
|
|
long lVal = 0;
|
|
|
|
if (variant.curr->variant() == TOUCH_DEVICE_JOYSTICK_KEYPAD) {
|
|
|
|
buttons.activeChar = prefs_parseLongValue(PREF_DOMAIN_JOYSTICK, PREF_KPAD_TOUCHDOWN_CHAR, &lVal, /*base:*/10) ? lVal : ICONTEXT_SPACE_VISUAL;
|
|
|
|
} else {
|
2016-04-16 21:15:21 +00:00
|
|
|
if (!prefs_parseLongValue(PREF_DOMAIN_JOYSTICK, PREF_JOY_TOUCHDOWN_CHAR, &lVal, /*base:*/10)) {
|
|
|
|
buttons.activeChar = MOUSETEXT_OPENAPPLE;
|
|
|
|
} else {
|
|
|
|
if (lVal == TOUCH_BUTTON2) {
|
|
|
|
buttons.activeChar = MOUSETEXT_CLOSEDAPPLE;
|
|
|
|
} else if (lVal == TOUCH_BOTH) {
|
|
|
|
buttons.activeChar = '+';
|
|
|
|
} else {
|
|
|
|
buttons.activeChar = MOUSETEXT_OPENAPPLE;
|
|
|
|
}
|
|
|
|
}
|
2016-04-06 05:04:57 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-01-02 21:10:02 +00:00
|
|
|
buttons.model = mdlCreateQuad((GLModelParams_s){
|
|
|
|
.skew_x = 1.05-BUTTON_OBJ_W,
|
|
|
|
.skew_y = -1.0,
|
|
|
|
.z = MODEL_DEPTH,
|
|
|
|
.obj_w = BUTTON_OBJ_W,
|
|
|
|
.obj_h = BUTTON_OBJ_H,
|
|
|
|
.positionUsageHint = GL_DYNAMIC_DRAW, // positions can change
|
|
|
|
.tex_w = BUTTON_FB_WIDTH,
|
|
|
|
.tex_h = BUTTON_FB_HEIGHT,
|
|
|
|
.texcoordUsageHint = GL_DYNAMIC_DRAW, // so can texture
|
|
|
|
}, (GLCustom){
|
2016-01-03 19:57:48 +00:00
|
|
|
.create = &_create_button_hud,
|
2015-04-12 18:27:33 +00:00
|
|
|
.destroy = &glhud_destroyDefault,
|
2016-01-02 21:10:02 +00:00
|
|
|
});
|
2015-04-11 19:29:44 +00:00
|
|
|
if (!buttons.model) {
|
2015-04-02 02:59:38 +00:00
|
|
|
LOG("gltouchjoy not initializing buttons");
|
|
|
|
return;
|
|
|
|
}
|
2015-05-22 05:31:06 +00:00
|
|
|
if (!buttons.model->custom) {
|
|
|
|
LOG("gltouchjoy buttons initialization problem");
|
|
|
|
return;
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-09-03 05:47:48 +00:00
|
|
|
variant.joys->setup(&_setup_button_object_with_char);
|
|
|
|
variant.kpad->setup(&_setup_button_object_with_char);
|
|
|
|
|
2015-08-21 05:15:56 +00:00
|
|
|
struct timespec now;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
axes.timingBegin = now;
|
|
|
|
buttons.timingBegin = now;
|
2015-04-11 07:30:23 +00:00
|
|
|
|
2015-08-02 19:37:28 +00:00
|
|
|
joyglobals.isAvailable = true;
|
2016-04-06 05:04:57 +00:00
|
|
|
|
|
|
|
if (joyglobals.ownsScreen) {
|
2017-07-15 23:25:00 +00:00
|
|
|
video_getAnimationDriver()->animation_showTouchJoystick();
|
2016-04-06 05:04:57 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2015-04-12 22:35:16 +00:00
|
|
|
static void gltouchjoy_shutdown(void) {
|
|
|
|
LOG("gltouchjoy_shutdown ...");
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.isAvailable) {
|
2015-04-02 02:59:38 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-30 23:55:57 +00:00
|
|
|
resetState();
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2015-08-02 19:37:28 +00:00
|
|
|
joyglobals.isAvailable = false;
|
2015-09-03 05:47:48 +00:00
|
|
|
|
|
|
|
variant.joys->shutdown();
|
|
|
|
variant.kpad->shutdown();
|
2015-06-07 04:28:12 +00:00
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
mdlDestroyModel(&axes.model);
|
2016-02-20 04:00:42 +00:00
|
|
|
mdlDestroyModel(&axes.azimuthModel);
|
2015-04-11 19:29:44 +00:00
|
|
|
mdlDestroyModel(&buttons.model);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_render(void) {
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.isAvailable) {
|
2015-04-02 02:59:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-04-06 05:04:57 +00:00
|
|
|
if (UNLIKELY(joyglobals.prefsChanged)) {
|
|
|
|
gltouchjoy_setup(); // fully set up again on prefs change
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-08-16 05:02:51 +00:00
|
|
|
if (!joyglobals.ownsScreen) {
|
|
|
|
return;
|
|
|
|
}
|
2015-08-22 18:05:18 +00:00
|
|
|
if (!joyglobals.showControls) {
|
|
|
|
return;
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-27 01:12:56 +00:00
|
|
|
glViewport(0, 0, touchport.width, touchport.height); // NOTE : show these HUD elements beyond the A2 framebuffer dimensions
|
2015-04-04 19:51:32 +00:00
|
|
|
|
|
|
|
// draw axis
|
2016-01-30 19:42:17 +00:00
|
|
|
float alpha = 1.f;
|
|
|
|
if (axes.trackingIndex == TRACKING_NONE) {
|
|
|
|
alpha = glhud_getTimedVisibility(axes.timingBegin, joyglobals.minAlpha, 1.0);
|
|
|
|
if (alpha < joyglobals.minAlpha) {
|
|
|
|
alpha = joyglobals.minAlpha;
|
|
|
|
}
|
2016-01-02 22:23:09 +00:00
|
|
|
}
|
2015-04-11 19:16:54 +00:00
|
|
|
if (alpha > 0.0) {
|
|
|
|
glUniform1f(alphaValue, alpha);
|
|
|
|
|
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHJOY_AXIS);
|
2015-04-11 19:29:44 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, axes.model->textureName);
|
|
|
|
if (axes.model->texDirty) {
|
|
|
|
axes.model->texDirty = false;
|
2015-10-01 04:55:07 +00:00
|
|
|
_HACKAROUND_GLTEXIMAGE2D_PRE(TEXTURE_ACTIVE_TOUCHJOY_AXIS, axes.model->textureName);
|
2015-05-31 02:08:00 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, TEX_FORMAT_INTERNAL, axes.model->texWidth, axes.model->texHeight, /*border*/0, TEX_FORMAT, TEX_TYPE, axes.model->texPixels);
|
2015-04-11 19:16:54 +00:00
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
if (axes.modelDirty) {
|
|
|
|
axes.modelDirty = false;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, axes.model->posBufferName);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, axes.model->positionArraySize, axes.model->positions, GL_DYNAMIC_DRAW);
|
2015-04-11 19:16:54 +00:00
|
|
|
}
|
2015-09-27 18:45:37 +00:00
|
|
|
glUniform1i(texSamplerLoc, TEXTURE_ID_TOUCHJOY_AXIS);
|
2015-04-12 18:27:33 +00:00
|
|
|
glhud_renderDefault(axes.model);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-01-30 19:42:17 +00:00
|
|
|
if (joyglobals.showAzimuth && axes.trackingIndex != TRACKING_NONE) {
|
2016-01-30 18:35:55 +00:00
|
|
|
_azimuth_render();
|
2016-01-03 20:08:47 +00:00
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
// draw button(s)
|
|
|
|
|
2016-01-30 19:42:17 +00:00
|
|
|
alpha = 1.f;
|
|
|
|
if (buttons.trackingIndex == TRACKING_NONE) {
|
|
|
|
alpha = glhud_getTimedVisibility(buttons.timingBegin, joyglobals.minAlpha, 1.0);
|
|
|
|
if (alpha < joyglobals.minAlpha) {
|
|
|
|
alpha = joyglobals.minAlpha;
|
|
|
|
}
|
2016-01-02 22:23:09 +00:00
|
|
|
}
|
2015-04-11 19:16:54 +00:00
|
|
|
if (alpha > 0.0) {
|
|
|
|
glUniform1f(alphaValue, alpha);
|
|
|
|
|
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHJOY_BUTTON);
|
2015-04-11 19:29:44 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, buttons.model->textureName);
|
|
|
|
if (buttons.model->texDirty) {
|
|
|
|
buttons.model->texDirty = false;
|
2015-10-01 04:55:07 +00:00
|
|
|
_HACKAROUND_GLTEXIMAGE2D_PRE(TEXTURE_ACTIVE_TOUCHJOY_BUTTON, buttons.model->textureName);
|
2015-05-31 02:08:00 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, TEX_FORMAT_INTERNAL, buttons.model->texWidth, buttons.model->texHeight, /*border*/0, TEX_FORMAT, TEX_TYPE, buttons.model->texPixels);
|
2015-04-11 19:16:54 +00:00
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
if (buttons.modelDirty) {
|
|
|
|
buttons.modelDirty = false;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buttons.model->posBufferName);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, buttons.model->positionArraySize, buttons.model->positions, GL_DYNAMIC_DRAW);
|
2015-04-11 19:16:54 +00:00
|
|
|
}
|
2015-09-27 18:45:37 +00:00
|
|
|
glUniform1i(texSamplerLoc, TEXTURE_ID_TOUCHJOY_BUTTON);
|
2015-04-12 18:27:33 +00:00
|
|
|
glhud_renderDefault(buttons.model);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-07 21:12:59 +00:00
|
|
|
static void gltouchjoy_reshape(int w, int h, bool landscape) {
|
|
|
|
LOG("w:%d h:%d landscape:%d", w, h, landscape);
|
2016-04-06 05:04:57 +00:00
|
|
|
assert(video_isRenderThread());
|
2016-02-07 21:12:59 +00:00
|
|
|
|
|
|
|
swizzleDimensions(&w, &h, landscape);
|
|
|
|
touchport.width = w;
|
|
|
|
touchport.height = h;
|
|
|
|
|
|
|
|
touchport.axisY = 0;
|
|
|
|
touchport.axisYMax = h;
|
|
|
|
touchport.buttonY = 0;
|
|
|
|
touchport.buttonYMax = h;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-08-02 18:28:48 +00:00
|
|
|
if (joyglobals.axisIsOnLeft) {
|
|
|
|
touchport.axisX = 0;
|
2016-02-07 21:12:59 +00:00
|
|
|
touchport.axisXMax = (w * joyglobals.screenDivider);
|
|
|
|
touchport.buttonX = (w * joyglobals.screenDivider);
|
|
|
|
touchport.buttonXMax = w;
|
2015-08-02 18:28:48 +00:00
|
|
|
} else {
|
|
|
|
touchport.buttonX = 0;
|
2016-02-07 21:12:59 +00:00
|
|
|
touchport.buttonXMax = (w * joyglobals.screenDivider);
|
|
|
|
touchport.axisX = (w * joyglobals.screenDivider);
|
|
|
|
touchport.axisXMax = w;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_resetJoystick(void) {
|
|
|
|
// no-op
|
|
|
|
}
|
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
static inline bool _is_point_on_axis_side(int x, int y) {
|
2015-04-11 19:29:44 +00:00
|
|
|
return (x >= touchport.axisX && x <= touchport.axisXMax && y >= touchport.axisY && y <= touchport.axisYMax);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
static inline void _reset_model_position(GLModel *model, float touchX, float touchY, float objHalfW, float objHalfH, GLModel *azimuthModel) {
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
float centerX = 0.f;
|
|
|
|
float centerY = 0.f;
|
2015-04-19 21:28:47 +00:00
|
|
|
glhud_screenToModel(touchX, touchY, touchport.width, touchport.height, ¢erX, ¢erY);
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
/* 2...3
|
|
|
|
* .
|
|
|
|
* .
|
|
|
|
* .
|
|
|
|
* 0...1
|
|
|
|
*/
|
|
|
|
|
|
|
|
GLfloat *quad = (GLfloat *)(model->positions);
|
|
|
|
quad[0 +0] = centerX-objHalfW;
|
|
|
|
quad[0 +1] = centerY-objHalfH;
|
|
|
|
quad[4 +0] = centerX+objHalfW;
|
|
|
|
quad[4 +1] = centerY-objHalfH;
|
|
|
|
quad[8 +0] = centerX-objHalfW;
|
|
|
|
quad[8 +1] = centerY+objHalfH;
|
|
|
|
quad[12+0] = centerX+objHalfW;
|
|
|
|
quad[12+1] = centerY+objHalfH;
|
2016-01-03 20:08:47 +00:00
|
|
|
|
|
|
|
if (azimuthModel) {
|
2016-01-30 18:35:55 +00:00
|
|
|
GLfloat *quadAzimuth = (GLfloat *)(azimuthModel->positions);
|
|
|
|
quadAzimuth[0 +0] = centerX;
|
|
|
|
quadAzimuth[0 +1] = centerY;
|
|
|
|
quadAzimuth[4 +0] = centerX;
|
|
|
|
quadAzimuth[4 +1] = centerY;
|
2016-01-03 20:08:47 +00:00
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-01-24 18:08:44 +00:00
|
|
|
static inline void _axis_touch_down(interface_touch_event_t action, int x, int y) {
|
2015-08-16 05:02:51 +00:00
|
|
|
axes.centerX = x;
|
|
|
|
axes.centerY = y;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
_reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H, axes.azimuthModel);
|
2015-08-16 05:02:51 +00:00
|
|
|
axes.modelDirty = true;
|
2015-08-01 23:46:09 +00:00
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
TOUCH_JOY_LOG("---TOUCH %sDOWN (axis index %d) center:(%d,%d) -> joy(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), axes.trackingIndex, axes.centerX, axes.centerY, joy_x, joy_y);
|
|
|
|
variant.curr->axisDown();
|
|
|
|
}
|
2015-08-01 23:46:09 +00:00
|
|
|
|
2016-01-24 18:08:44 +00:00
|
|
|
static inline void _button_touch_down(interface_touch_event_t action, int x, int y) {
|
2015-08-16 05:02:51 +00:00
|
|
|
buttons.centerX = x;
|
|
|
|
buttons.centerY = y;
|
2015-04-04 19:51:32 +00:00
|
|
|
|
2016-01-03 20:08:47 +00:00
|
|
|
_reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H, NULL);
|
2015-08-16 05:02:51 +00:00
|
|
|
buttons.modelDirty = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
TOUCH_JOY_LOG("---TOUCH %sDOWN (buttons index %d) center:(%d,%d) -> buttons(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "), buttons.trackingIndex, buttons.centerX, buttons.centerY, joy_button0, joy_button1);
|
2015-09-03 05:47:48 +00:00
|
|
|
variant.curr->buttonDown();
|
2015-04-04 19:51:32 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
static inline void _axis_move(int x, int y) {
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2016-01-06 07:19:12 +00:00
|
|
|
if (joyglobals.showAzimuth && axes.azimuthModel) {
|
2016-01-03 20:08:47 +00:00
|
|
|
float centerX = 0.f;
|
|
|
|
float centerY = 0.f;
|
|
|
|
glhud_screenToModel(x, y, touchport.width, touchport.height, ¢erX, ¢erY);
|
2016-01-30 18:35:55 +00:00
|
|
|
GLfloat *quadAzimuth = (GLfloat *)axes.azimuthModel->positions;
|
|
|
|
quadAzimuth[4 +0] = centerX;
|
|
|
|
quadAzimuth[4 +1] = centerY;
|
2016-01-03 20:08:47 +00:00
|
|
|
};
|
|
|
|
|
2015-09-03 05:47:48 +00:00
|
|
|
x -= axes.centerX;
|
|
|
|
y -= axes.centerY;
|
2015-08-16 05:02:51 +00:00
|
|
|
TOUCH_JOY_LOG("---TOUCH MOVE ...tracking axis:%d (%d,%d) -> joy(0x%02X,0x%02X)", axes.trackingIndex, x, y, joy_x, joy_y);
|
|
|
|
variant.curr->axisMove(x, y);
|
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
static inline void _button_move(int x, int y) {
|
2015-04-11 19:29:44 +00:00
|
|
|
x -= buttons.centerX;
|
|
|
|
y -= buttons.centerY;
|
2015-09-03 05:47:48 +00:00
|
|
|
TOUCH_JOY_LOG("+++TOUCH MOVE ...tracking button:%d (%d,%d) -> buttons(0x%02X,0x%02X)", buttons.trackingIndex, x, y, joy_button0, joy_button1);
|
|
|
|
variant.curr->buttonMove(x, y);
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 18:08:44 +00:00
|
|
|
static inline void _axis_touch_up(interface_touch_event_t action, int x, int y) {
|
2015-08-16 05:02:51 +00:00
|
|
|
#if DEBUG_TOUCH_JOY
|
|
|
|
bool resetIndex = false;
|
|
|
|
if (buttons.trackingIndex > axes.trackingIndex) {
|
|
|
|
// TODO FIXME : is resetting the pointer index just an Android-ism?
|
|
|
|
resetIndex = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
}
|
2015-08-16 05:02:51 +00:00
|
|
|
TOUCH_JOY_LOG("---TOUCH %sUP (axis went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset buttons index!)" : ""));
|
|
|
|
#endif
|
2015-09-03 05:47:48 +00:00
|
|
|
x -= axes.centerX;
|
|
|
|
y -= axes.centerY;
|
2015-08-30 23:55:57 +00:00
|
|
|
if (buttons.trackingIndex > axes.trackingIndex) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : DECREMENTING buttons.trackingIndex");
|
2015-08-30 23:55:57 +00:00
|
|
|
--buttons.trackingIndex;
|
|
|
|
}
|
|
|
|
variant.curr->axisUp(x, y);
|
|
|
|
axes.trackingIndex = TRACKING_NONE;
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 18:08:44 +00:00
|
|
|
static inline void _button_touch_up(interface_touch_event_t action, int x, int y) {
|
2015-08-16 05:02:51 +00:00
|
|
|
#if DEBUG_TOUCH_JOY
|
|
|
|
bool resetIndex = false;
|
|
|
|
if (axes.trackingIndex > buttons.trackingIndex) {
|
|
|
|
// TODO FIXME : is resetting the pointer index just an Android-ism?
|
|
|
|
resetIndex = true;
|
|
|
|
}
|
|
|
|
TOUCH_JOY_LOG("---TOUCH %sUP (buttons went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset axis index!)" : ""));
|
|
|
|
#endif
|
2015-09-03 05:47:48 +00:00
|
|
|
x -= buttons.centerX;
|
|
|
|
y -= buttons.centerY;
|
2015-08-16 05:02:51 +00:00
|
|
|
if (axes.trackingIndex > buttons.trackingIndex) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : DECREMENTING axes.trackingIndex");
|
2015-08-16 05:02:51 +00:00
|
|
|
--axes.trackingIndex;
|
|
|
|
}
|
2015-09-03 05:47:48 +00:00
|
|
|
variant.curr->buttonUp(x, y);
|
2015-08-30 23:55:57 +00:00
|
|
|
buttons.trackingIndex = TRACKING_NONE;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2015-07-31 04:36:22 +00:00
|
|
|
static int64_t gltouchjoy_onTouchEvent(interface_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.isAvailable) {
|
2015-07-31 04:36:22 +00:00
|
|
|
return 0x0LL;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2016-04-06 05:04:57 +00:00
|
|
|
if (UNLIKELY(joyglobals.prefsChanged)) {
|
2015-07-31 04:36:22 +00:00
|
|
|
return 0x0LL;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.ownsScreen) {
|
2015-07-31 04:36:22 +00:00
|
|
|
return 0x0LL;
|
2015-04-27 01:12:56 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
bool axisConsumed = false;
|
|
|
|
bool buttonConsumed = false;
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case TOUCH_DOWN:
|
|
|
|
case TOUCH_POINTER_DOWN:
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("------DOWN:");
|
2015-08-16 05:02:51 +00:00
|
|
|
{
|
|
|
|
int x = (int)x_coords[pointer_idx];
|
|
|
|
int y = (int)y_coords[pointer_idx];
|
|
|
|
if (_is_point_on_axis_side(x, y)) {
|
2015-09-03 05:33:13 +00:00
|
|
|
if (pointer_idx == buttons.trackingIndex) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : INCREMENTING buttons.trackingIndex");
|
2015-09-03 05:33:13 +00:00
|
|
|
++buttons.trackingIndex;
|
|
|
|
}
|
2015-08-30 23:55:57 +00:00
|
|
|
if (axes.trackingIndex != TRACKING_NONE) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : IGNORING OTHER AXIS TOUCH DOWN %d", pointer_idx);
|
2015-08-30 23:55:57 +00:00
|
|
|
} else {
|
|
|
|
axisConsumed = true;
|
|
|
|
axes.trackingIndex = pointer_idx;
|
2016-01-24 18:08:44 +00:00
|
|
|
_axis_touch_down(action, x, y);
|
2015-08-30 23:55:57 +00:00
|
|
|
}
|
2015-09-13 21:12:16 +00:00
|
|
|
} else {
|
2015-09-03 05:33:13 +00:00
|
|
|
if (pointer_idx == axes.trackingIndex) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : INCREMENTING axes.trackingIndex");
|
2015-09-03 05:33:13 +00:00
|
|
|
++axes.trackingIndex;
|
|
|
|
}
|
2015-08-30 23:55:57 +00:00
|
|
|
if (buttons.trackingIndex != TRACKING_NONE) {
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("!!! : IGNORING OTHER BUTTON TOUCH DOWN %d", pointer_idx);
|
2015-08-30 23:55:57 +00:00
|
|
|
} else {
|
|
|
|
buttonConsumed = true;
|
|
|
|
buttons.trackingIndex = pointer_idx;
|
2016-01-24 18:08:44 +00:00
|
|
|
_button_touch_down(action, x, y);
|
2015-08-30 23:55:57 +00:00
|
|
|
}
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_MOVE:
|
2015-09-16 03:39:30 +00:00
|
|
|
TOUCH_JOY_LOG("------MOVE:");
|
2015-04-11 19:29:44 +00:00
|
|
|
if (axes.trackingIndex >= 0) {
|
2015-04-02 02:59:38 +00:00
|
|
|
axisConsumed = true;
|
2015-08-16 05:02:51 +00:00
|
|
|
int x = (int)x_coords[axes.trackingIndex];
|
|
|
|
int y = (int)y_coords[axes.trackingIndex];
|
|
|
|
_axis_move(x, y);
|
2015-04-04 19:51:32 +00:00
|
|
|
}
|
2015-04-11 19:29:44 +00:00
|
|
|
if (buttons.trackingIndex >= 0) {
|
2015-04-04 19:51:32 +00:00
|
|
|
buttonConsumed = true;
|
2015-08-16 05:02:51 +00:00
|
|
|
int x = (int)x_coords[buttons.trackingIndex];
|
|
|
|
int y = (int)y_coords[buttons.trackingIndex];
|
|
|
|
_button_move(x, y);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_UP:
|
|
|
|
case TOUCH_POINTER_UP:
|
2016-01-30 19:42:17 +00:00
|
|
|
{
|
|
|
|
TOUCH_JOY_LOG("------UP:");
|
|
|
|
struct timespec now;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
if (pointer_idx == axes.trackingIndex) {
|
|
|
|
axes.timingBegin = now;
|
|
|
|
int x = (int)x_coords[axes.trackingIndex];
|
|
|
|
int y = (int)y_coords[axes.trackingIndex];
|
|
|
|
_axis_touch_up(action, x, y);
|
|
|
|
} else if (pointer_idx == buttons.trackingIndex) {
|
|
|
|
buttons.timingBegin = now;
|
|
|
|
int x = (int)x_coords[buttons.trackingIndex];
|
|
|
|
int y = (int)y_coords[buttons.trackingIndex];
|
|
|
|
_button_touch_up(action, x, y);
|
2015-08-30 23:55:57 +00:00
|
|
|
} else {
|
2016-01-30 19:42:17 +00:00
|
|
|
if (pointer_count == 1) {
|
|
|
|
TOUCH_JOY_LOG("!!! : RESETTING TOUCH JOYSTICK STATE MACHINE");
|
|
|
|
resetState();
|
|
|
|
} else {
|
|
|
|
TOUCH_JOY_LOG("!!! : IGNORING OTHER TOUCH UP %d", pointer_idx);
|
|
|
|
}
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_CANCEL:
|
|
|
|
LOG("---TOUCH CANCEL");
|
2015-08-30 23:55:57 +00:00
|
|
|
resetState();
|
2015-04-02 02:59:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2015-04-04 19:51:32 +00:00
|
|
|
LOG("!!! UNKNOWN TOUCH EVENT : %d", action);
|
2015-04-02 02:59:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-07-31 04:36:22 +00:00
|
|
|
return TOUCH_FLAGS_HANDLED | TOUCH_FLAGS_JOY;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
2016-01-03 20:08:47 +00:00
|
|
|
|
2015-04-27 01:12:56 +00:00
|
|
|
static void _animation_showTouchJoystick(void) {
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.isAvailable) {
|
2015-04-27 01:12:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-08-21 05:15:56 +00:00
|
|
|
|
|
|
|
int x = touchport.axisX + ((touchport.axisXMax - touchport.axisX)/2);
|
|
|
|
int y = touchport.axisY + ((touchport.axisYMax - touchport.axisY)/2);
|
2016-01-03 20:08:47 +00:00
|
|
|
_reset_model_position(axes.model, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H, NULL);
|
2015-08-21 05:15:56 +00:00
|
|
|
axes.modelDirty = true;
|
|
|
|
|
|
|
|
x = touchport.buttonX + ((touchport.buttonXMax - touchport.buttonX)/2);
|
|
|
|
y = touchport.buttonY + ((touchport.buttonYMax - touchport.buttonY)/2);
|
2016-01-03 20:08:47 +00:00
|
|
|
_reset_model_position(buttons.model, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H, NULL);
|
2015-08-21 05:15:56 +00:00
|
|
|
buttons.modelDirty = true;
|
|
|
|
|
|
|
|
struct timespec now;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
axes.timingBegin = now;
|
|
|
|
buttons.timingBegin = now;
|
2015-04-27 01:12:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void _animation_hideTouchJoystick(void) {
|
2015-08-02 19:37:28 +00:00
|
|
|
if (!joyglobals.isAvailable) {
|
2015-04-27 01:12:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
axes.timingBegin = (struct timespec){ 0 };
|
|
|
|
buttons.timingBegin = (struct timespec){ 0 };
|
|
|
|
}
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
static void gltouchjoy_applyPrefs(void) {
|
|
|
|
assert(video_isRenderThread());
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
joyglobals.prefsChanged = false;
|
2015-08-01 23:46:09 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
bool bVal = false;
|
|
|
|
float fVal = 0.f;
|
|
|
|
long lVal = 0;
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
const interface_device_t screenOwner = prefs_parseLongValue(PREF_DOMAIN_TOUCHSCREEN, PREF_SCREEN_OWNER, &lVal, /*base:*/10) ? lVal : TOUCH_DEVICE_NONE;
|
|
|
|
joyglobals.ownsScreen = (screenOwner == TOUCH_DEVICE_JOYSTICK || screenOwner == TOUCH_DEVICE_JOYSTICK_KEYPAD);
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2015-08-30 23:55:57 +00:00
|
|
|
resetState();
|
2016-04-06 05:04:57 +00:00
|
|
|
if (joyglobals.ownsScreen) {
|
|
|
|
caps_lock = true; // HACK FOR NOW : force uppercase scancodes for touchjoy_kpad variant
|
|
|
|
joyglobals.minAlpha = joyglobals.minAlphaWhenOwnsScreen;
|
|
|
|
variant.curr = (screenOwner == TOUCH_DEVICE_JOYSTICK) ? variant.joys : variant.kpad;
|
|
|
|
} else {
|
|
|
|
joyglobals.minAlpha = 0.0;
|
|
|
|
}
|
2015-08-01 23:46:09 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
joyglobals.showControls = prefs_parseBoolValue (PREF_DOMAIN_JOYSTICK, PREF_SHOW_CONTROLS, &bVal) ? bVal : true;
|
2016-04-14 02:50:03 +00:00
|
|
|
joyglobals.showAzimuth = true;//prefs_parseBoolValue (PREF_DOMAIN_JOYSTICK, PREF_SHOW_AZIMUTH, &bVal) ? bVal : true;
|
2016-04-06 05:04:57 +00:00
|
|
|
joyglobals.switchThreshold = prefs_parseLongValue (PREF_DOMAIN_JOYSTICK, PREF_SWITCH_THRESHOLD, &lVal, 10) ? lVal : BUTTON_SWITCH_THRESHOLD_DEFAULT;
|
|
|
|
joyglobals.screenDivider = prefs_parseFloatValue(PREF_DOMAIN_JOYSTICK, PREF_SCREEN_DIVISION, &fVal) ? fVal : 0.5f;
|
|
|
|
joyglobals.axisIsOnLeft = prefs_parseBoolValue (PREF_DOMAIN_JOYSTICK, PREF_AXIS_ON_LEFT, &bVal) ? bVal : true;
|
|
|
|
axes.multiplier = prefs_parseFloatValue(PREF_DOMAIN_JOYSTICK, PREF_AXIS_SENSITIVITY, &fVal) ? fVal : 1.f;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
joyglobals.isCalibrating = prefs_parseBoolValue (PREF_DOMAIN_TOUCHSCREEN, PREF_CALIBRATING, &bVal) ? bVal : false;
|
2015-08-02 18:28:48 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
variant.joys->prefsChanged(PREF_DOMAIN_JOYSTICK);
|
|
|
|
variant.kpad->prefsChanged(PREF_DOMAIN_JOYSTICK);
|
2015-08-02 18:28:48 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
long width = prefs_parseLongValue (PREF_DOMAIN_INTERFACE, PREF_DEVICE_WIDTH, &lVal, 10) ? lVal : (long)(SCANWIDTH*1.5);
|
|
|
|
long height = prefs_parseLongValue (PREF_DOMAIN_INTERFACE, PREF_DEVICE_HEIGHT, &lVal, 10) ? lVal : (long)(SCANHEIGHT*1.5);
|
|
|
|
bool isLandscape = prefs_parseBoolValue (PREF_DOMAIN_INTERFACE, PREF_DEVICE_LANDSCAPE, &bVal) ? bVal : true;
|
2015-08-02 18:28:48 +00:00
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
gltouchjoy_reshape(width, height, isLandscape);
|
2015-08-02 18:28:48 +00:00
|
|
|
}
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
static void gltouchjoy_prefsChanged(const char *domain) {
|
|
|
|
joyglobals.prefsChanged = true;
|
2015-08-16 05:02:51 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
static void _init_gltouchjoy(void) {
|
|
|
|
LOG("Registering OpenGL software touch joystick");
|
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
axes.centerX = 240;
|
|
|
|
axes.centerY = 160;
|
2015-08-30 23:55:57 +00:00
|
|
|
axes.trackingIndex = TRACKING_NONE;
|
2015-08-16 05:02:51 +00:00
|
|
|
|
2015-04-11 19:29:44 +00:00
|
|
|
buttons.centerX = 240;
|
|
|
|
buttons.centerY = 160;
|
2015-08-30 23:55:57 +00:00
|
|
|
buttons.trackingIndex = TRACKING_NONE;
|
2015-04-11 19:29:44 +00:00
|
|
|
buttons.activeChar = MOUSETEXT_OPENAPPLE;
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
joyglobals.prefsChanged = true; // force reload preferences/defaults
|
2015-08-02 19:37:28 +00:00
|
|
|
|
2017-07-15 23:25:00 +00:00
|
|
|
video_getAnimationDriver()->animation_showTouchJoystick = &_animation_showTouchJoystick;
|
|
|
|
video_getAnimationDriver()->animation_hideTouchJoystick = &_animation_hideTouchJoystick;
|
2015-04-27 01:12:56 +00:00
|
|
|
|
2015-04-12 22:35:16 +00:00
|
|
|
glnode_registerNode(RENDER_LOW, (GLNode){
|
2016-02-07 21:12:59 +00:00
|
|
|
.type = TOUCH_DEVICE_JOYSTICK,
|
2015-04-12 23:20:01 +00:00
|
|
|
.setup = &gltouchjoy_setup,
|
|
|
|
.shutdown = &gltouchjoy_shutdown,
|
|
|
|
.render = &gltouchjoy_render,
|
|
|
|
.onTouchEvent = &gltouchjoy_onTouchEvent,
|
2015-04-12 22:35:16 +00:00
|
|
|
});
|
2016-04-06 05:04:57 +00:00
|
|
|
|
|
|
|
prefs_registerListener(PREF_DOMAIN_JOYSTICK, &gltouchjoy_prefsChanged);
|
|
|
|
prefs_registerListener(PREF_DOMAIN_TOUCHSCREEN, &gltouchjoy_prefsChanged);
|
|
|
|
prefs_registerListener(PREF_DOMAIN_INTERFACE, &gltouchjoy_prefsChanged);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2016-02-23 05:36:08 +00:00
|
|
|
static __attribute__((constructor)) void __init_gltouchjoy(void) {
|
|
|
|
emulator_registerStartupCallback(CTOR_PRIORITY_LATE, &_init_gltouchjoy);
|
|
|
|
}
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
void gltouchjoy_registerVariant(interface_device_t variantType, GLTouchJoyVariant *touchJoyVariant) {
|
2015-08-16 05:02:51 +00:00
|
|
|
switch (variantType) {
|
2016-04-06 05:04:57 +00:00
|
|
|
case TOUCH_DEVICE_JOYSTICK:
|
2015-08-16 05:02:51 +00:00
|
|
|
variant.joys = touchJoyVariant;
|
2016-04-06 05:04:57 +00:00
|
|
|
variant.curr = variant.joys;
|
2015-08-16 05:02:51 +00:00
|
|
|
break;
|
|
|
|
|
2016-04-06 05:04:57 +00:00
|
|
|
case TOUCH_DEVICE_JOYSTICK_KEYPAD:
|
2015-08-16 05:02:51 +00:00
|
|
|
variant.kpad = touchJoyVariant;
|
|
|
|
variant.curr = variant.kpad;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert(false && "invalid touch variant registration");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|