2015-02-18 04:23:06 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
2015-03-23 01:53:13 +00:00
|
|
|
#include "video/glvideo.h"
|
2015-02-18 04:23:06 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
#define AXIS_TEMPLATE_COLS 5
|
|
|
|
#define AXIS_TEMPLATE_ROWS 5
|
|
|
|
|
|
|
|
#define BUTTON_TEMPLATE_COLS 1
|
|
|
|
#define BUTTON_TEMPLATE_ROWS 1
|
|
|
|
|
|
|
|
// HACK NOTE FIXME TODO : interpolated pixel adjustment still necessary ...
|
|
|
|
#define AXIS_FB_WIDTH ((AXIS_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) + INTERPOLATED_PIXEL_ADJUSTMENT)
|
|
|
|
#define AXIS_FB_HEIGHT (AXIS_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
// HACK NOTE FIXME TODO : interpolated pixel adjustment still necessary ...
|
2015-04-04 19:51:32 +00:00
|
|
|
#define BUTTON_FB_WIDTH ((BUTTON_TEMPLATE_COLS * FONT80_WIDTH_PIXELS) + INTERPOLATED_PIXEL_ADJUSTMENT)
|
|
|
|
#define BUTTON_FB_HEIGHT (BUTTON_TEMPLATE_ROWS * FONT_HEIGHT_PIXELS)
|
|
|
|
|
|
|
|
#define AXIS_OBJ_W 0.4
|
|
|
|
#define AXIS_OBJ_H 0.5
|
|
|
|
#define AXIS_OBJ_HALF_W (AXIS_OBJ_W/2.f)
|
|
|
|
#define AXIS_OBJ_HALF_H (AXIS_OBJ_H/2.f)
|
|
|
|
|
|
|
|
#define BUTTON_OBJ_W 0.2
|
|
|
|
#define BUTTON_OBJ_H 0.25
|
|
|
|
#define BUTTON_OBJ_HALF_W (BUTTON_OBJ_W/2.f)
|
|
|
|
#define BUTTON_OBJ_HALF_H (BUTTON_OBJ_H/2.f)
|
|
|
|
|
|
|
|
#define BUTTON_SWITCH_THRESHOLD_DEFAULT 44
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
enum {
|
|
|
|
TOUCHED_NONE = -1,
|
|
|
|
TOUCHED_BUTTON0 = 0,
|
|
|
|
TOUCHED_BUTTON1,
|
|
|
|
TOUCHED_BOTH,
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool isAvailable = false;
|
|
|
|
static bool isEnabled = true;
|
|
|
|
static bool isVisible = true;
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static char axisTemplate[AXIS_TEMPLATE_ROWS][AXIS_TEMPLATE_COLS+1] = {
|
|
|
|
" @ ",
|
|
|
|
" | ",
|
|
|
|
"@-+-@",
|
|
|
|
" | ",
|
|
|
|
" @ ",
|
2015-04-02 02:59:38 +00:00
|
|
|
};
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static char buttonTemplate[BUTTON_TEMPLATE_ROWS][BUTTON_TEMPLATE_COLS+1] = {
|
|
|
|
"@",
|
2015-04-02 02:59:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static glanim_t touchjoyAnimation = { 0 };
|
|
|
|
|
|
|
|
static int viewportWidth = 0;
|
|
|
|
static int viewportHeight = 0;
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static int axisSideX = 0;
|
|
|
|
static int axisSideXMax = 0;
|
|
|
|
static int axisSideY = 0;
|
|
|
|
static int axisSideYMax = 0;
|
|
|
|
|
|
|
|
static int buttSideX = 0;
|
|
|
|
static int buttSideXMax = 0;
|
|
|
|
static int buttSideY = 0;
|
|
|
|
static int buttSideYMax = 0;
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
// touch axis variables
|
|
|
|
|
|
|
|
static demoModel *touchAxisObjModel = NULL;
|
|
|
|
static GLuint touchAxisObjVAOName = UNINITIALIZED_GL;
|
|
|
|
static GLuint touchAxisObjTextureName = UNINITIALIZED_GL;
|
|
|
|
static GLuint touchAxisObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
static GLuint touchAxisObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
static GLuint touchAxisObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static uint8_t touchAxisObjFB[AXIS_FB_WIDTH * AXIS_FB_HEIGHT] = { 0 };
|
|
|
|
static uint8_t touchAxisObjPixels[AXIS_FB_WIDTH * AXIS_FB_HEIGHT * 4] = { 0 };// RGBA8888
|
2015-04-02 02:59:38 +00:00
|
|
|
static bool axisTextureDirty = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
static bool axisModelDirty = true;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static int axisCenterX = 480;
|
|
|
|
static int axisCenterY = 320;
|
2015-04-02 02:59:38 +00:00
|
|
|
static int trackingAxisIndex = TOUCHED_NONE;
|
2015-04-04 19:51:32 +00:00
|
|
|
static struct timespec axisTimingBegin = { 0 };
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
// button object variables
|
|
|
|
|
|
|
|
static demoModel *buttonObjModel = NULL;
|
|
|
|
static GLuint buttonObjVAOName = UNINITIALIZED_GL;
|
|
|
|
static GLuint buttonObjTextureName = UNINITIALIZED_GL;
|
|
|
|
static GLuint buttonObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
static GLuint buttonObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
static GLuint buttonObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static uint8_t buttonObjFB[BUTTON_FB_WIDTH * BUTTON_FB_HEIGHT] = { 0 };
|
|
|
|
static uint8_t buttonObjPixels[BUTTON_FB_WIDTH * BUTTON_FB_HEIGHT * 4] = { 0 };// RGBA8888
|
2015-04-02 02:59:38 +00:00
|
|
|
static bool buttonTextureDirty = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
static bool buttonModelDirty = true;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static int buttonCenterX = 480;
|
|
|
|
static int buttonCenterY = 320;
|
|
|
|
static int trackingButtonIndex = TOUCHED_NONE;
|
|
|
|
static int touchDownButton = TOUCHED_BUTTON0;
|
|
|
|
static int upButtonAxisButton = TOUCHED_BOTH;
|
|
|
|
static int downButtonAxisButton = TOUCHED_BUTTON1;
|
|
|
|
static int buttonSwitchThreshold = BUTTON_SWITCH_THRESHOLD_DEFAULT;
|
|
|
|
static struct timespec buttonTimingBegin = { 0 };
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
// configurables for current touchjoy
|
|
|
|
|
|
|
|
static uint8_t button0Char = MOUSETEXT_OPENAPPLE;
|
2015-04-04 19:51:32 +00:00
|
|
|
static uint8_t buttonActiveChar = MOUSETEXT_OPENAPPLE;
|
2015-04-02 02:59:38 +00:00
|
|
|
static uint8_t button1Char = MOUSETEXT_CLOSEDAPPLE;
|
2015-04-04 19:51:32 +00:00
|
|
|
static uint8_t buttonBothChar = '+';
|
2015-04-02 02:59:38 +00:00
|
|
|
static touchjoy_axis_type_t touchjoy_axisType = AXIS_EMULATED_DEVICE;
|
|
|
|
static uint8_t upChar = MOUSETEXT_UP;
|
|
|
|
static uint8_t leftChar = MOUSETEXT_LEFT;
|
|
|
|
static uint8_t rightChar = MOUSETEXT_RIGHT;
|
|
|
|
static uint8_t downChar = MOUSETEXT_DOWN;
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static demoModel *_create_model(GLfloat skew_x, GLfloat skew_y, GLfloat obj_w, GLfloat obj_h) {
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
/* 2...3
|
|
|
|
* .
|
|
|
|
* .
|
|
|
|
* .
|
|
|
|
* 0...1
|
|
|
|
*/
|
|
|
|
|
|
|
|
const GLfloat obj_positions[] = {
|
2015-04-04 19:51:32 +00:00
|
|
|
skew_x, skew_y, -0.03125, 1.0,
|
|
|
|
skew_x+obj_w, skew_y, -0.03125, 1.0,
|
|
|
|
skew_x, skew_y+obj_h, -0.03125, 1.0,
|
|
|
|
skew_x+obj_w, skew_y+obj_h, -0.03125, 1.0,
|
2015-04-02 02:59:38 +00:00
|
|
|
};
|
|
|
|
const GLfloat obj_texcoords[] = {
|
|
|
|
0.0, 1.0,
|
|
|
|
1.0, 1.0,
|
|
|
|
0.0, 0.0,
|
|
|
|
1.0, 0.0,
|
|
|
|
};
|
|
|
|
const GLushort indices[] = {
|
|
|
|
0, 1, 2, 2, 1, 3
|
|
|
|
};
|
|
|
|
|
|
|
|
demoModel *obj = calloc(1, sizeof(demoModel));
|
|
|
|
obj->numVertices = 4;
|
|
|
|
obj->numElements = 6;
|
|
|
|
|
|
|
|
obj->positions = malloc(sizeof(obj_positions));
|
|
|
|
memcpy(obj->positions, &obj_positions[0], sizeof(obj_positions));
|
|
|
|
obj->positionType = GL_FLOAT;
|
|
|
|
obj->positionSize = 4; // x,y,z coordinates
|
|
|
|
obj->positionArraySize = sizeof(obj_positions);
|
|
|
|
|
|
|
|
obj->texcoords = malloc(sizeof(obj_texcoords));
|
|
|
|
memcpy(obj->texcoords, &obj_texcoords[0], sizeof(obj_texcoords));
|
|
|
|
obj->texcoordType = GL_FLOAT;
|
|
|
|
obj->texcoordSize = 2; // s,t coordinates
|
|
|
|
obj->texcoordArraySize = sizeof(obj_texcoords);
|
|
|
|
|
|
|
|
obj->normals = NULL;
|
|
|
|
obj->normalType = GL_NONE;
|
|
|
|
obj->normalSize = GL_NONE;
|
|
|
|
obj->normalArraySize = 0;
|
|
|
|
|
|
|
|
obj->elements = malloc(sizeof(indices));
|
|
|
|
memcpy(obj->elements, &indices[0], sizeof(indices));
|
|
|
|
obj->elementType = GL_UNSIGNED_SHORT;
|
|
|
|
obj->elementArraySize = sizeof(indices);
|
|
|
|
|
|
|
|
return obj;
|
2015-02-18 04:23:06 +00:00
|
|
|
}
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
static void _create_VAO_VBOs(const demoModel *model, GLuint *vaoName, GLuint *posBufferName, GLuint *texcoordBufferName, GLuint *elementBufferName) {
|
|
|
|
|
|
|
|
// Create a vertex array object (VAO) to cache model parameters
|
|
|
|
#if USE_VAO
|
|
|
|
glGenVertexArrays(1, vaoName);
|
|
|
|
glBindVertexArray(*vaoName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Create a vertex buffer object (VBO) to store positions and load data
|
|
|
|
glGenBuffers(1, posBufferName);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, *posBufferName);
|
2015-04-04 19:51:32 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, model->positionArraySize, model->positions, GL_DYNAMIC_DRAW);
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
#if USE_VAO
|
|
|
|
// Enable the position attribute for this VAO
|
|
|
|
glEnableVertexAttribArray(POS_ATTRIB_IDX);
|
|
|
|
|
|
|
|
// Get the size of the position type so we can set the stride properly
|
|
|
|
GLsizei posTypeSize = _get_gl_type_size(model->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)
|
|
|
|
model->positionSize, // How many elements are there per position?
|
|
|
|
model->positionType, // What is the type of this data?
|
|
|
|
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
|
|
|
model->positionSize*posTypeSize, // What is the stride (i.e. bytes between positions)?
|
|
|
|
0); // What is the offset in the VBO to the position data?
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (model->texcoords) {
|
|
|
|
// Create a VBO to store texcoords
|
|
|
|
glGenBuffers(1, texcoordBufferName);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, *texcoordBufferName);
|
|
|
|
|
|
|
|
// Allocate and load texcoord data into the VBO
|
2015-04-04 19:51:32 +00:00
|
|
|
glBufferData(GL_ARRAY_BUFFER, model->texcoordArraySize, model->texcoords, GL_DYNAMIC_DRAW);
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
#if USE_VAO
|
|
|
|
// Enable the texcoord attribute for this VAO
|
|
|
|
glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX);
|
|
|
|
|
|
|
|
// Get the size of the texcoord type so we can set the stride properly
|
|
|
|
GLsizei texcoordTypeSize = _get_gl_type_size(model->texcoordType);
|
|
|
|
|
|
|
|
// Set up parmeters for texcoord attribute in the VAO including,
|
|
|
|
// size, type, stride, and offset in the currenly bound VAO
|
|
|
|
// This also attaches the texcoord VBO to VAO
|
|
|
|
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
|
|
|
model->texcoordSize, // How many elements are there per texture coord?
|
|
|
|
model->texcoordType, // What is the type of this data in the array?
|
|
|
|
GL_TRUE, // Do we want to normalize this data (0-1 range for fixed-point types)
|
|
|
|
model->texcoordSize*texcoordTypeSize, // What is the stride (i.e. bytes between texcoords)?
|
|
|
|
0); // What is the offset in the VBO to the texcoord data?
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a VBO to vertex array elements
|
|
|
|
// This also attaches the element array buffer to the VAO
|
|
|
|
glGenBuffers(1, elementBufferName);
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *elementBufferName);
|
|
|
|
|
|
|
|
// Allocate and load vertex array element data into VBO
|
2015-04-04 19:51:32 +00:00
|
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->elementArraySize, model->elements, GL_DYNAMIC_DRAW);
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
GL_ERRLOG("gltouchjoy finished creating VAO/VBOs");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _destroy_VAO_VBOs(GLuint vaoName, GLuint posBufferName, GLuint texcoordBufferName, GLuint elementBufferName) {
|
|
|
|
|
|
|
|
// Bind the VAO so we can get data from it
|
|
|
|
#if USE_VAO
|
|
|
|
glBindVertexArray(vaoName);
|
|
|
|
|
|
|
|
// For every possible attribute set in the VAO
|
|
|
|
for (GLuint index = 0; index < 16; index++) {
|
|
|
|
// Get the VBO set for that attibute
|
|
|
|
GLuint bufName = 0;
|
|
|
|
glGetVertexAttribiv(index , GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint*)&bufName);
|
|
|
|
|
|
|
|
// If there was a VBO set...
|
|
|
|
if (bufName) {
|
|
|
|
//...delete the VBO
|
|
|
|
glDeleteBuffers(1, &bufName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get any element array VBO set in the VAO
|
|
|
|
{
|
|
|
|
GLuint bufName = 0;
|
|
|
|
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, (GLint*)&bufName);
|
|
|
|
|
|
|
|
// If there was a element array VBO set in the VAO
|
|
|
|
if (bufName) {
|
|
|
|
//...delete the VBO
|
|
|
|
glDeleteBuffers(1, &bufName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, delete the VAO
|
|
|
|
glDeleteVertexArrays(1, &vaoName);
|
|
|
|
#else
|
|
|
|
glDeleteBuffers(1, &posBufferName);
|
|
|
|
glDeleteBuffers(1, &texcoordBufferName);
|
|
|
|
glDeleteBuffers(1, &elementBufferName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
GL_ERRLOG("gltouchjoy destroying VAO/VBOs");
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static GLuint _create_texture(GLvoid *pixels, int w, int h) {
|
2015-04-02 02:59:38 +00:00
|
|
|
GLuint texName = UNINITIALIZED_GL;
|
|
|
|
|
|
|
|
// Create a texture object to apply to model
|
|
|
|
glGenTextures(1, &texName);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texName);
|
|
|
|
|
|
|
|
// Set up filter and wrap modes for this texture object
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
|
|
|
// Indicate that pixel rows are tightly packed
|
|
|
|
// (defaults to stride of 4 which is kind of only good for
|
|
|
|
// RGBA or FLOAT data types)
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
|
|
|
|
// register texture with OpenGL
|
2015-04-04 19:51:32 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, w, h, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
GL_ERRLOG("gltouchjoy texture");
|
|
|
|
|
|
|
|
return texName;
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static void _setup_object(char *submenu, unsigned int cols, unsigned int rows, uint8_t *fb, unsigned int fb_w, unsigned int fb_h, uint8_t *pixels) {
|
2015-04-02 02:59:38 +00:00
|
|
|
|
|
|
|
// render template into indexed fb
|
2015-04-04 19:51:32 +00:00
|
|
|
unsigned int submenu_width = cols;
|
|
|
|
unsigned int submenu_height = rows;
|
2015-04-02 02:59:38 +00:00
|
|
|
video_interface_print_submenu_centered_fb(fb, submenu_width, submenu_height, submenu, submenu_width, submenu_height);
|
|
|
|
|
|
|
|
// generate RGBA_8888 from indexed color
|
2015-04-04 19:51:32 +00:00
|
|
|
unsigned int count = fb_w * fb_h;
|
2015-04-02 02:59:38 +00:00
|
|
|
for (unsigned int i=0, j=0; i<count; i++, j+=4) {
|
|
|
|
uint8_t index = *(fb + i);
|
|
|
|
uint32_t rgb = (((uint32_t)(colormap[index].red) << 0 ) |
|
|
|
|
((uint32_t)(colormap[index].green) << 8 ) |
|
|
|
|
((uint32_t)(colormap[index].blue) << 16));
|
|
|
|
if (rgb == 0) {
|
|
|
|
// make black transparent for joystick
|
|
|
|
} else {
|
|
|
|
rgb |= ((uint32_t)0xff << 24);
|
|
|
|
}
|
|
|
|
*( (uint32_t*)(pixels + j) ) = rgb;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _setup_axis_object(void) {
|
2015-04-04 19:51:32 +00:00
|
|
|
axisTemplate[0][2] = upChar;
|
|
|
|
axisTemplate[2][0] = leftChar;
|
|
|
|
axisTemplate[2][4] = rightChar;
|
|
|
|
axisTemplate[4][2] = downChar;
|
|
|
|
_setup_object(axisTemplate[0], AXIS_TEMPLATE_COLS, AXIS_TEMPLATE_ROWS, touchAxisObjFB, AXIS_FB_WIDTH, AXIS_FB_HEIGHT, touchAxisObjPixels);
|
2015-04-02 02:59:38 +00:00
|
|
|
axisTextureDirty = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _setup_button_object(void) {
|
2015-04-04 19:51:32 +00:00
|
|
|
buttonTemplate[0][0] = buttonActiveChar;
|
|
|
|
_setup_object(buttonTemplate[0], BUTTON_TEMPLATE_COLS, BUTTON_TEMPLATE_ROWS, buttonObjFB, BUTTON_FB_WIDTH, BUTTON_FB_HEIGHT, buttonObjPixels);
|
2015-04-02 02:59:38 +00:00
|
|
|
buttonTextureDirty = true;
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline void _screen_to_model(float x, float y, float *screenX, float *screenY) {
|
|
|
|
*screenX = (x/(viewportWidth>>1))-1.f;
|
|
|
|
*screenY = ((viewportHeight-y)/(viewportHeight>>1))-1.f;
|
|
|
|
}
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
static void _model_to_screen(float screenCoords[4], demoModel *model) {
|
|
|
|
|
|
|
|
float x0 = 1.0;
|
|
|
|
float y0 = 1.0;
|
|
|
|
float x1 = -1.0;
|
|
|
|
float y1 = -1.0;
|
|
|
|
|
|
|
|
#if PERSPECTIVE
|
|
|
|
#error TODO FIXME we really should do it this way regardless of whether we are using PERSPECTIVE ...
|
|
|
|
// project models to screen space for touch handling
|
|
|
|
GLfloat mvp[16];
|
|
|
|
#else
|
|
|
|
#warning TODO FIXME ... should really use matrix calculations (assuming identity/orthographic for now)
|
|
|
|
GLfloat *positions = (GLfloat *)(model->positions);
|
|
|
|
unsigned int stride = model->positionSize;
|
|
|
|
unsigned int len = model->positionArraySize/_get_gl_type_size(model->positionType);
|
|
|
|
for (unsigned int i=0; i < len; i += stride) {
|
|
|
|
float x = (positions[i] + 1.f) / 2.f;
|
|
|
|
if (x < x0) {
|
|
|
|
x0 = x;
|
|
|
|
}
|
|
|
|
if (x > x1) {
|
|
|
|
x1 = x;
|
|
|
|
}
|
|
|
|
float y = (positions[i+1] + 1.f) / 2.f;
|
|
|
|
LOG("\tmodel x:%f, y:%f", x, y);
|
|
|
|
if (y < y0) {
|
|
|
|
y0 = y;
|
|
|
|
}
|
|
|
|
if (y > y1) {
|
|
|
|
y1 = y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// OpenGL screen origin is bottom-left (Android is top-left)
|
|
|
|
float yFlip0 = viewportHeight - (y1 * viewportHeight);
|
|
|
|
float yFlip1 = viewportHeight - (y0 * viewportHeight);
|
|
|
|
|
|
|
|
screenCoords[0] = x0 * viewportWidth;
|
|
|
|
screenCoords[1] = yFlip0;
|
|
|
|
screenCoords[2] = x1 * viewportWidth;
|
|
|
|
screenCoords[3] = yFlip1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_init(void) {
|
|
|
|
LOG("gltouchjoy_init ...");
|
|
|
|
|
|
|
|
mdlDestroyModel(touchAxisObjModel);
|
|
|
|
mdlDestroyModel(buttonObjModel);
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
touchAxisObjModel = _create_model(-1.05, -1.0, AXIS_OBJ_W, AXIS_OBJ_H);
|
2015-04-02 02:59:38 +00:00
|
|
|
touchAxisObjVAOName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
_create_VAO_VBOs(touchAxisObjModel, &touchAxisObjVAOName, &touchAxisObjPosBufferName, &touchAxisObjTexcoordBufferName, &touchAxisObjElementBufferName);
|
|
|
|
if (touchAxisObjPosBufferName == UNINITIALIZED_GL || touchAxisObjTexcoordBufferName == UNINITIALIZED_GL || touchAxisObjElementBufferName == UNINITIALIZED_GL)
|
|
|
|
{
|
|
|
|
LOG("gltouchjoy not initializing axis");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
touchAxisObjTextureName = _create_texture(touchAxisObjPixels, AXIS_FB_WIDTH, AXIS_FB_HEIGHT);
|
2015-04-02 02:59:38 +00:00
|
|
|
if (touchAxisObjTextureName == UNINITIALIZED_GL) {
|
|
|
|
LOG("gltouchjoy not initializing axis: texture error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_setup_axis_object();
|
|
|
|
|
|
|
|
// button object
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
buttonObjModel = _create_model(1.05-BUTTON_OBJ_W, -1.0, BUTTON_OBJ_W, BUTTON_OBJ_H);
|
2015-04-02 02:59:38 +00:00
|
|
|
buttonObjVAOName = UNINITIALIZED_GL;
|
|
|
|
buttonObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
buttonObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
buttonObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
_create_VAO_VBOs(buttonObjModel, &buttonObjVAOName, &buttonObjPosBufferName, &buttonObjTexcoordBufferName, &buttonObjElementBufferName);
|
|
|
|
if (buttonObjPosBufferName == UNINITIALIZED_GL || buttonObjTexcoordBufferName == UNINITIALIZED_GL || buttonObjElementBufferName == UNINITIALIZED_GL)
|
|
|
|
{
|
|
|
|
LOG("gltouchjoy not initializing buttons");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
buttonObjTextureName = _create_texture(buttonObjPixels, BUTTON_FB_WIDTH, BUTTON_FB_HEIGHT);
|
2015-04-02 02:59:38 +00:00
|
|
|
if (buttonObjTextureName == UNINITIALIZED_GL) {
|
|
|
|
LOG("not initializing buttons: texture error");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_setup_button_object();
|
|
|
|
|
|
|
|
isAvailable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_destroy(void) {
|
|
|
|
LOG("gltouchjoy_destroy ...");
|
|
|
|
if (!isAvailable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
isAvailable = false;
|
|
|
|
|
|
|
|
glDeleteTextures(1, &touchAxisObjTextureName);
|
|
|
|
touchAxisObjTextureName = UNINITIALIZED_GL;
|
|
|
|
_destroy_VAO_VBOs(touchAxisObjVAOName, touchAxisObjPosBufferName, touchAxisObjTexcoordBufferName, touchAxisObjElementBufferName);
|
|
|
|
touchAxisObjVAOName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
touchAxisObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
mdlDestroyModel(touchAxisObjModel);
|
|
|
|
touchAxisObjModel = NULL;
|
|
|
|
|
|
|
|
glDeleteTextures(1, &buttonObjTextureName);
|
|
|
|
buttonObjTextureName = UNINITIALIZED_GL;
|
|
|
|
_destroy_VAO_VBOs(buttonObjVAOName, buttonObjPosBufferName, buttonObjTexcoordBufferName, buttonObjElementBufferName);
|
|
|
|
buttonObjVAOName = UNINITIALIZED_GL;
|
|
|
|
buttonObjPosBufferName = UNINITIALIZED_GL;
|
|
|
|
buttonObjTexcoordBufferName = UNINITIALIZED_GL;
|
|
|
|
buttonObjElementBufferName = UNINITIALIZED_GL;
|
|
|
|
mdlDestroyModel(buttonObjModel);
|
|
|
|
buttonObjModel = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _render_object(demoModel *model, GLuint vaoName, GLuint posBufferName, GLuint texcoordBufferName, GLuint elementBufferName) {
|
|
|
|
|
|
|
|
// Bind our vertex array object
|
|
|
|
#if USE_VAO
|
|
|
|
glBindVertexArray(vaoName);
|
|
|
|
#else
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, posBufferName);
|
|
|
|
|
|
|
|
GLsizei posTypeSize = _get_gl_type_size(model->positionType);
|
|
|
|
GLsizei texcoordTypeSize = _get_gl_type_size(model->texcoordType);
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
model->positionSize, // How many elements are there per position?
|
|
|
|
model->positionType, // What is the type of this data?
|
|
|
|
GL_FALSE, // Do we want to normalize this data (0-1 range for fixed-pont types)
|
|
|
|
model->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);
|
|
|
|
|
|
|
|
// Set up parmeters for texcoord attribute in the VAO including, size, type, stride, and offset in the currenly
|
|
|
|
// bound VAO This also attaches the texcoord VBO to VAO
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, texcoordBufferName);
|
|
|
|
glVertexAttribPointer(TEXCOORD_ATTRIB_IDX, // What attibute index will this array feed in the vertex shader (see buildProgram)
|
|
|
|
model->texcoordSize, // How many elements are there per texture coord?
|
|
|
|
model->texcoordType, // What is the type of this data in the array?
|
|
|
|
GL_TRUE, // Do we want to normalize this data (0-1 range for fixed-point types)
|
|
|
|
model->texcoordSize*texcoordTypeSize,// What is the stride (i.e. bytes between texcoords)?
|
|
|
|
0); // What is the offset in the VBO to the texcoord data?
|
|
|
|
glEnableVertexAttribArray(TEXCOORD_ATTRIB_IDX);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Draw the object
|
|
|
|
glDrawElements(GL_TRIANGLES, model->numElements, model->elementType, 0);
|
|
|
|
GL_ERRLOG("gltouchjoy render");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_render(void) {
|
|
|
|
if (!isAvailable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!isEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!isVisible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
glViewport(0, 0, viewportWidth, viewportHeight);
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
struct timespec now = { 0 };
|
|
|
|
const float min_alpha = 0.0625;
|
|
|
|
float alpha = min_alpha;
|
|
|
|
struct timespec deltat = { 0 };
|
|
|
|
|
|
|
|
// draw axis
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
alpha = min_alpha;
|
|
|
|
deltat = timespec_diff(axisTimingBegin, 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 < min_alpha) {
|
|
|
|
alpha = min_alpha;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glUniform1f(alphaValue, alpha);
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHJOY_AXIS);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, touchAxisObjTextureName);
|
|
|
|
if (axisTextureDirty) {
|
|
|
|
axisTextureDirty = false;
|
2015-04-04 19:51:32 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, AXIS_FB_WIDTH, AXIS_FB_HEIGHT, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)touchAxisObjPixels);
|
|
|
|
}
|
|
|
|
if (axisModelDirty) {
|
|
|
|
axisModelDirty = false;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, touchAxisObjPosBufferName);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, touchAxisObjModel->positionArraySize, touchAxisObjModel->positions, GL_DYNAMIC_DRAW);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
glUniform1i(uniformTex2Use, TEXTURE_ID_TOUCHJOY_AXIS);
|
|
|
|
_render_object(touchAxisObjModel, touchAxisObjVAOName, touchAxisObjPosBufferName, touchAxisObjTexcoordBufferName, touchAxisObjElementBufferName);
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
// draw button(s)
|
|
|
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
|
|
alpha = min_alpha;
|
|
|
|
deltat = timespec_diff(buttonTimingBegin, 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 < min_alpha) {
|
|
|
|
alpha = min_alpha;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glUniform1f(alphaValue, alpha);
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
glActiveTexture(TEXTURE_ACTIVE_TOUCHJOY_BUTTON);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, buttonObjTextureName);
|
|
|
|
if (buttonTextureDirty) {
|
|
|
|
buttonTextureDirty = false;
|
2015-04-04 19:51:32 +00:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, /*level*/0, /*internal format*/GL_RGBA, BUTTON_FB_WIDTH, BUTTON_FB_HEIGHT, /*border*/0, /*format*/GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *)buttonObjPixels);
|
|
|
|
}
|
|
|
|
if (buttonModelDirty) {
|
|
|
|
buttonModelDirty = false;
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, buttonObjPosBufferName);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, buttonObjModel->positionArraySize, buttonObjModel->positions, GL_DYNAMIC_DRAW);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
glUniform1i(uniformTex2Use, TEXTURE_ID_TOUCHJOY_BUTTON);
|
|
|
|
_render_object(buttonObjModel, buttonObjVAOName, buttonObjPosBufferName, buttonObjTexcoordBufferName, buttonObjElementBufferName);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_reshape(int w, int h) {
|
|
|
|
LOG("gltouchjoy_reshape(%d, %d)", w, h);
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
axisSideX = 0;
|
|
|
|
|
2015-04-02 02:59:38 +00:00
|
|
|
if (w > viewportWidth) {
|
|
|
|
viewportWidth = w;
|
2015-04-04 19:51:32 +00:00
|
|
|
axisSideXMax = w>>1;
|
|
|
|
buttSideX = w>>1;
|
|
|
|
buttSideXMax = w;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
if (h > viewportHeight) {
|
|
|
|
viewportHeight = h;
|
2015-04-04 19:51:32 +00:00
|
|
|
axisSideY = h>>1;
|
|
|
|
axisSideYMax = h;
|
|
|
|
buttSideY = h>>1;
|
|
|
|
buttSideYMax = h;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_resetJoystick(void) {
|
|
|
|
// no-op
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline bool _is_point_on_axis_side(float x, float y) {
|
|
|
|
return (x >= axisSideX && x <= axisSideXMax && y >= axisSideY && y <= axisSideYMax);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline bool _is_point_on_button_side(float x, float y) {
|
|
|
|
return (x >= buttSideX && x <= buttSideXMax && y >= buttSideY && y <= buttSideYMax);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline void _reset_model_position(demoModel *model, float touchX, float touchY, float objHalfW, float objHalfH) {
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
float centerX = 0.f;
|
|
|
|
float centerY = 0.f;
|
|
|
|
_screen_to_model(touchX, touchY, ¢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;
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline void _move_joystick_axis(int x, int y) {
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
x = (x - axisCenterX) + 0x80;
|
|
|
|
y = (y - axisCenterY) + 0x80;
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
if (x < 0) {
|
|
|
|
x = 0;
|
|
|
|
}
|
|
|
|
if (x > 0xff) {
|
|
|
|
x = 0xff;
|
|
|
|
}
|
|
|
|
if (y < 0) {
|
|
|
|
y = 0;
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
if (y > 0xff) {
|
|
|
|
y = 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
joy_x = x;
|
|
|
|
joy_y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _setup_button_object_with_char(char newChar) {
|
|
|
|
if (buttonActiveChar != newChar) {
|
|
|
|
buttonActiveChar = newChar;
|
|
|
|
_setup_button_object();
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static inline void _move_button_axis(int x, int y) {
|
|
|
|
|
|
|
|
x -= buttonCenterX;
|
|
|
|
y -= buttonCenterY;
|
|
|
|
|
|
|
|
if ((y < -buttonSwitchThreshold) || (y > buttonSwitchThreshold)) {
|
|
|
|
if (y < 0) {
|
|
|
|
//LOG("\tbutton neg y threshold (%d)", y);
|
|
|
|
if (upButtonAxisButton == TOUCHED_BUTTON0) {
|
|
|
|
joy_button0 = 0x80;
|
|
|
|
_setup_button_object_with_char(button0Char);
|
|
|
|
} else if (upButtonAxisButton == TOUCHED_BUTTON1) {
|
|
|
|
joy_button1 = 0x80;
|
|
|
|
_setup_button_object_with_char(button1Char);
|
|
|
|
} else if (upButtonAxisButton == TOUCHED_BOTH) {
|
|
|
|
joy_button0 = 0x80;
|
|
|
|
joy_button1 = 0x80;
|
|
|
|
_setup_button_object_with_char(buttonBothChar);
|
|
|
|
} else {
|
|
|
|
joy_button0 = 0;
|
|
|
|
joy_button1 = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//LOG("\tbutton pos y threshold (%d)", y);
|
|
|
|
if (downButtonAxisButton == TOUCHED_BUTTON0) {
|
|
|
|
joy_button0 = 0x80;
|
|
|
|
_setup_button_object_with_char(button0Char);
|
|
|
|
} else if (downButtonAxisButton == TOUCHED_BUTTON1) {
|
|
|
|
joy_button1 = 0x80;
|
|
|
|
_setup_button_object_with_char(button1Char);
|
|
|
|
} else if (downButtonAxisButton == TOUCHED_BOTH) {
|
|
|
|
joy_button0 = 0x80;
|
|
|
|
joy_button1 = 0x80;
|
|
|
|
_setup_button_object_with_char(buttonBothChar);
|
|
|
|
} else {
|
|
|
|
joy_button0 = 0;
|
|
|
|
joy_button1 = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool gltouchjoy_onTouchEvent(joystick_touch_event_t action, int pointer_count, int pointer_idx, float *x_coords, float *y_coords) {
|
|
|
|
|
|
|
|
if (!isAvailable) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!isEnabled) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool axisConsumed = false;
|
|
|
|
bool buttonConsumed = false;
|
|
|
|
|
|
|
|
float x = x_coords[pointer_idx];
|
|
|
|
float y = y_coords[pointer_idx];
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case TOUCH_DOWN:
|
|
|
|
case TOUCH_POINTER_DOWN:
|
2015-04-04 19:51:32 +00:00
|
|
|
if (_is_point_on_axis_side(x, y)) {
|
|
|
|
axisConsumed = true;
|
|
|
|
trackingAxisIndex = pointer_idx;
|
|
|
|
axisCenterX = (int)x;
|
|
|
|
axisCenterY = (int)y;
|
|
|
|
_reset_model_position(touchAxisObjModel, x, y, AXIS_OBJ_HALF_W, AXIS_OBJ_HALF_H);
|
|
|
|
axisModelDirty = true;
|
|
|
|
LOG("---TOUCH %sDOWN (axis index %d) center:(%d,%d) -> joy(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "),
|
|
|
|
trackingAxisIndex, axisCenterX, axisCenterY, joy_x, joy_y);
|
|
|
|
} else if (_is_point_on_button_side(x, y)) {
|
|
|
|
buttonConsumed = true;
|
|
|
|
trackingButtonIndex = pointer_idx;
|
|
|
|
if (touchDownButton == TOUCHED_BUTTON0) {
|
2015-04-02 02:59:38 +00:00
|
|
|
joy_button0 = 0x80;
|
2015-04-04 19:51:32 +00:00
|
|
|
_setup_button_object_with_char(button0Char);
|
|
|
|
} else if (touchDownButton == TOUCHED_BUTTON1) {
|
2015-04-02 02:59:38 +00:00
|
|
|
joy_button1 = 0x80;
|
2015-04-04 19:51:32 +00:00
|
|
|
_setup_button_object_with_char(button1Char);
|
|
|
|
} else if (touchDownButton == TOUCHED_BOTH) {
|
2015-04-02 02:59:38 +00:00
|
|
|
joy_button0 = 0x80;
|
|
|
|
joy_button1 = 0x80;
|
2015-04-04 19:51:32 +00:00
|
|
|
_setup_button_object_with_char(buttonBothChar);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
buttonCenterX = (int)x;
|
|
|
|
buttonCenterY = (int)y;
|
|
|
|
_reset_model_position(buttonObjModel, x, y, BUTTON_OBJ_HALF_W, BUTTON_OBJ_HALF_H);
|
|
|
|
buttonModelDirty = true;
|
|
|
|
LOG("---TOUCH %sDOWN (buttons index %d) center:(%d,%d) -> buttons(0x%02X,0x%02X)", (action == TOUCH_DOWN ? "" : "POINTER "),
|
|
|
|
trackingButtonIndex, buttonCenterX, buttonCenterY, joy_button0, joy_button1);
|
|
|
|
} else {
|
|
|
|
// not tracking tap/gestures originating from control-gesture portion of screen
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_MOVE:
|
|
|
|
if (trackingAxisIndex >= 0) {
|
|
|
|
axisConsumed = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
_move_joystick_axis((int)x_coords[trackingAxisIndex], (int)y_coords[trackingAxisIndex]);
|
|
|
|
LOG("---TOUCH MOVE ...tracking axis:%d (%d,%d) -> joy(0x%02X,0x%02X)", trackingAxisIndex,
|
|
|
|
(int)x_coords[trackingAxisIndex], (int)y_coords[trackingAxisIndex], joy_x, joy_y);
|
|
|
|
}
|
|
|
|
if (trackingButtonIndex >= 0) {
|
|
|
|
buttonConsumed = true;
|
|
|
|
_move_button_axis((int)x_coords[trackingButtonIndex], (int)y_coords[trackingButtonIndex]);
|
|
|
|
LOG("+++TOUCH MOVE ...tracking button:%d (%d,%d) -> buttons(0x%02X,0x%02X)", trackingButtonIndex,
|
|
|
|
(int)x_coords[trackingButtonIndex], (int)y_coords[trackingButtonIndex], joy_button0, joy_button1);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_UP:
|
|
|
|
case TOUCH_POINTER_UP:
|
|
|
|
if (pointer_idx == trackingAxisIndex) {
|
|
|
|
axisConsumed = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
bool resetIndex = false;
|
|
|
|
if (trackingButtonIndex > trackingAxisIndex) {
|
|
|
|
// TODO FIXME : is resetting the pointer index just an Android-ism?
|
|
|
|
resetIndex = true;
|
|
|
|
--trackingButtonIndex;
|
|
|
|
}
|
2015-04-02 02:59:38 +00:00
|
|
|
trackingAxisIndex = TOUCHED_NONE;
|
|
|
|
joy_x = HALF_JOY_RANGE;
|
|
|
|
joy_y = HALF_JOY_RANGE;
|
2015-04-04 19:51:32 +00:00
|
|
|
LOG("---TOUCH %sUP (axis went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset buttons index!)" : ""));
|
|
|
|
} else if (pointer_idx == trackingButtonIndex) {
|
2015-04-02 02:59:38 +00:00
|
|
|
buttonConsumed = true;
|
2015-04-04 19:51:32 +00:00
|
|
|
bool resetIndex = false;
|
|
|
|
if (trackingAxisIndex > trackingButtonIndex) {
|
|
|
|
// TODO FIXME : is resetting the pointer index just an Android-ism?
|
|
|
|
resetIndex = true;
|
|
|
|
--trackingAxisIndex;
|
|
|
|
}
|
|
|
|
trackingButtonIndex = TOUCHED_NONE;
|
2015-04-02 02:59:38 +00:00
|
|
|
joy_button0 = 0x0;
|
|
|
|
joy_button1 = 0x0;
|
2015-04-04 19:51:32 +00:00
|
|
|
LOG("---TOUCH %sUP (buttons went up)%s", (action == TOUCH_UP ? "" : "POINTER "), (resetIndex ? " (reset axis index!)" : ""));
|
|
|
|
} else {
|
|
|
|
// not tracking tap/gestures originating from control-gesture portion of screen
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOUCH_CANCEL:
|
|
|
|
LOG("---TOUCH CANCEL");
|
|
|
|
trackingAxisIndex = TOUCHED_NONE;
|
2015-04-04 19:51:32 +00:00
|
|
|
trackingButtonIndex = TOUCHED_NONE;
|
2015-04-02 02:59:38 +00:00
|
|
|
joy_button0 = 0x0;
|
|
|
|
joy_button1 = 0x0;
|
|
|
|
joy_x = HALF_JOY_RANGE;
|
|
|
|
joy_y = HALF_JOY_RANGE;
|
|
|
|
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-04-04 19:51:32 +00:00
|
|
|
if (axisConsumed) {
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &axisTimingBegin);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
2015-04-04 19:51:32 +00:00
|
|
|
if (buttonConsumed) {
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &buttonTimingBegin);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (axisConsumed || buttonConsumed);
|
2015-04-02 02:59:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool gltouchjoy_isTouchJoystickAvailable(void) {
|
|
|
|
return isAvailable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gltouchjoy_setTouchJoyEnabled(bool enabled) {
|
|
|
|
isEnabled = enabled;
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static void gltouchjoy_setTouchButtonValues(char c0, char c1) {
|
|
|
|
button0Char = c0;
|
|
|
|
button1Char = c1;
|
2015-04-02 02:59:38 +00:00
|
|
|
_setup_button_object();
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static void gltouchjoy_setTouchAxisType(touchjoy_axis_type_t axisType) {
|
2015-04-02 02:59:38 +00:00
|
|
|
touchjoy_axisType = axisType;
|
|
|
|
_setup_axis_object();
|
|
|
|
}
|
|
|
|
|
2015-04-04 19:51:32 +00:00
|
|
|
static void gltouchjoy_setTouchAxisValues(char up, char left, char right, char down) {
|
2015-04-02 02:59:38 +00:00
|
|
|
upChar = up;
|
|
|
|
leftChar = left;
|
|
|
|
rightChar = right;
|
|
|
|
downChar = down;
|
|
|
|
if (touchjoy_axisType == AXIS_EMULATED_KEYBOARD) {
|
|
|
|
_setup_axis_object();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
__attribute__((constructor))
|
|
|
|
static void _init_gltouchjoy(void) {
|
|
|
|
LOG("Registering OpenGL software touch joystick");
|
|
|
|
|
|
|
|
joydriver_onTouchEvent = &gltouchjoy_onTouchEvent;
|
|
|
|
joydriver_isTouchJoystickAvailable = &gltouchjoy_isTouchJoystickAvailable;
|
|
|
|
joydriver_setTouchJoyEnabled = &gltouchjoy_setTouchJoyEnabled;
|
|
|
|
joydriver_setTouchButtonValues = &gltouchjoy_setTouchButtonValues;
|
|
|
|
joydriver_setTouchAxisType = &gltouchjoy_setTouchAxisType;
|
|
|
|
joydriver_setTouchAxisValues = &gltouchjoy_setTouchAxisValues;
|
|
|
|
|
|
|
|
touchjoyAnimation.ctor = &gltouchjoy_init;
|
|
|
|
touchjoyAnimation.dtor = &gltouchjoy_destroy;
|
|
|
|
touchjoyAnimation.render = &gltouchjoy_render;
|
|
|
|
touchjoyAnimation.reshape = &gltouchjoy_reshape;
|
|
|
|
gldriver_register_animation(&touchjoyAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gldriver_joystick_reset(void) {
|
|
|
|
#warning FIXME
|
|
|
|
#warning TODO
|
|
|
|
#warning expunge
|
|
|
|
#warning this
|
|
|
|
#warning API
|
|
|
|
#warning ...
|
|
|
|
}
|