Simple framework for virtual touchscreen buttons

This commit is contained in:
Henrik Rydgard 2012-10-26 15:58:09 +02:00
parent ce2be356b2
commit 70e6752884
12 changed files with 191 additions and 5 deletions

View File

@ -47,6 +47,7 @@ LOCAL_SRC_FILES :=\
image/zim_load.cpp \
ui/ui.cpp \
ui/screen.cpp \
ui/virtual_input.cpp \
util/random/perlin.cpp

View File

@ -128,6 +128,7 @@ extern "C" void Java_com_turboviking_libnative_NativeApp_init
net::Init();
g_dpi = dpi;
g_dpi_scale = 240.0f / (float)g_dpi;
pixel_xres = xxres;
pixel_yres = yyres;
@ -180,8 +181,8 @@ extern "C" void Java_com_turboviking_libnative_NativeRenderer_displayInit(JNIEnv
// We default to 240 dpi and all UI code is written to assume it. (DENSITY_HIGH, like Nexus S).
// Note that we don't compute dp_xscale and dp_yscale until later! This is so that NativeGetAppInfo
// can change the dp resolution if it feels like it.
dp_xres = pixel_xres * 240 / g_dpi;
dp_yres = pixel_yres * 240 / g_dpi;
dp_xres = pixel_xres * g_dpi_scale;
dp_yres = pixel_yres * g_dpi_scale;
NativeInitGraphics();

View File

@ -6,4 +6,5 @@ int dp_yres;
int pixel_xres;
int pixel_yres;
int g_dpi;
int g_dpi;
float g_dpi_scale;

View File

@ -8,4 +8,5 @@ extern int dp_yres;
extern int pixel_xres;
extern int pixel_yres;
extern int g_dpi;
extern int g_dpi;
extern float g_dpi_scale;

View File

@ -1,2 +1,18 @@
#include <string.h>
#include "gfx/texture_atlas.h"
const AtlasFont *Atlas::getFontByName(const char *name) const
{
for (int i = 0; i < num_fonts; i++) {
if (!strcmp(name, fonts[i]->name))
return fonts[i];
}
}
const AtlasImage *Atlas::getImageByName(const char *name) const
{
for (int i = 0; i < num_images; i++) {
if (!strcmp(name, images[i].name))
return &images[i];
}
}

View File

@ -17,11 +17,13 @@ struct AtlasFont {
float ascend;
float distslope;
AtlasChar chars[96];
const char *name;
};
struct AtlasImage {
float u1, v1, u2, v2;
int w, h;
const char *name;
};
struct Atlas {
@ -30,4 +32,8 @@ struct Atlas {
int num_fonts;
const AtlasImage *images;
int num_images;
// These are inefficient linear searches, try not to call every frame.
const AtlasFont *getFontByName(const char *name) const;
const AtlasImage *getImageByName(const char *name) const;
};

View File

@ -210,7 +210,9 @@ bool glsl_recompile(GLSLProgram *program) {
}
void GLSLProgram::GLLost() {
ILOG("Restoring GLSL program %s/%s", this->vshader_filename, this->fshader_filename);
ILOG("Restoring GLSL program %s/%s",
this->vshader_filename ? this->vshader_filename : "(mem)",
this->fshader_filename ? this->fshader_filename : "(mem)");
this->program_ = 0;
this->vsh_ = 0;
this->fsh_ = 0;

View File

@ -240,6 +240,7 @@
<ClInclude Include="ui\list_screen.h" />
<ClInclude Include="ui\screen.h" />
<ClInclude Include="ui\ui.h" />
<ClInclude Include="ui\virtual_input.h" />
<ClInclude Include="util\bits\bits.h" />
<ClInclude Include="util\random\perlin.h" />
<ClInclude Include="util\random\rng.h" />
@ -319,6 +320,7 @@
<ClCompile Include="ui\list_screen.cpp" />
<ClCompile Include="ui\screen.cpp" />
<ClCompile Include="ui\ui.cpp" />
<ClCompile Include="ui\virtual_input.cpp" />
<ClCompile Include="util\bits\bits.cpp" />
<ClCompile Include="util\random\perlin.cpp">
<AssemblerOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AssemblyAndSourceCode</AssemblerOutput>

View File

@ -221,6 +221,9 @@
<ClInclude Include="ext\stb_image\stb_image.h">
<Filter>ext</Filter>
</ClInclude>
<ClInclude Include="ui\virtual_input.h">
<Filter>ui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="gfx\gl_debug_log.cpp">
@ -391,6 +394,9 @@
<ClCompile Include="ext\stb_image\stb_image.c">
<Filter>ext</Filter>
</ClCompile>
<ClCompile Include="ui\virtual_input.cpp">
<Filter>ui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="gfx">

View File

@ -1,6 +1,7 @@
set(SRCS
ui.cpp
screen.cpp
virtual_input.cpp
)
set(SRCS ${SRCS})

80
ui/virtual_input.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "gfx_es2/draw_buffer.h"
#include "gfx/texture_atlas.h"
#include "input/input_state.h"
#include "virtual_input.h"
TouchButton::TouchButton(const Atlas *atlas, int imageIndex, int overlayImageIndex, int button, int rotationAngle)
: atlas_(atlas), imageIndex_(imageIndex), overlayImageIndex_(overlayImageIndex), button_(button), rotationAngle_(rotationAngle)
{
memset(pointerDown, 0, sizeof(pointerDown));
w_ = atlas->images[imageIndex].w;
h_ = atlas->images[imageIndex].h;
}
void TouchButton::update(InputState &input_state)
{
bool isDown = false;
for (int i = 0; i < MAX_POINTERS; i++) {
if (input_state.pointer_down[i] && isInside(input_state.pointer_x[i], input_state.pointer_y[i]))
isDown = true;
}
if (isDown) {
int prev_buttons = input_state.pad_buttons;
input_state.pad_buttons |= button_;
input_state.pad_buttons_down |= button_ & (~prev_buttons);
} else {
input_state.pad_buttons_up &= ~(button_ & input_state.pad_buttons);
input_state.pad_buttons &= ~button_;
}
}
void TouchButton::draw(DrawBuffer &db)
{
db.DrawImageRotated(imageIndex_, x_ + w_/2, y_ + h_/2, 1.0f, rotationAngle_, 0xFFFFFFFF);
if (overlayImageIndex_ != -1)
db.DrawImageRotated(overlayImageIndex_, x_ + w_/2, y_ + h_/2, 1.0f, rotationAngle_, 0xFFFFFFFF);
}
TouchStick::TouchStick(const Atlas *atlas, int bgImageIndex, int stickImageIndex, int stick)
: atlas_(atlas), bgImageIndex_(bgImageIndex), stickImageIndex_(stickImageIndex), stick_(stick)
{
}
void TouchStick::update(InputState &input_state)
{
float inv_stick_size = 1.0f / stick_size_;
for (int i = 0; i < MAX_POINTERS; i++) {
if (input_state.pointer_down[i]) {
float dx = (input_state.pointer_x[i] - stick_x_) * inv_stick_size;
float dy = (input_state.pointer_y[i] - stick_y_) * inv_stick_size;
// Ignore outside box
if (fabsf(dx) > 1.4f || fabsf(dy) > 1.4f)
continue;
// Clamp to a circle
float len = sqrtf(dx * dx + dy * dy);
if (len > 1.0f) {
dx /= len;
dy /= len;
}
stick_delta_x_ = dx;
stick_delta_y_ = dy;
if (stick_ == 0) {
input_state.pad_lstick_x = dx;
input_state.pad_lstick_y = -dy;
} else if (stick_ == 1) {
input_state.pad_rstick_x = dx;
input_state.pad_rstick_y = -dy;
}
}
}
}
void TouchStick::draw(DrawBuffer &db)
{
if (bgImageIndex_ != -1)
db.DrawImage(bgImageIndex_, stick_x_, stick_y_, 1.0f, 0xFFFFFFFF, ALIGN_CENTER);
db.DrawImage(stickImageIndex_, stick_x_ + stick_delta_x_, stick_y_ + stick_delta_y_, 1.0f, 0xFFFFFFFF, ALIGN_CENTER);
}

69
ui/virtual_input.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
// Multitouch-enabled emulation of a hardware button.
// (any finger will work, simultaneously with other virtual button/stick actions).
class TouchButton
{
public:
TouchButton(const Atlas *atlas, int imageIndex, int overlayImageIndex, int button, int rotationAngle = 0);
void update(InputState &input_state);
void draw(DrawBuffer &db);
void setPos(float x, float y) {
x_ = x - w_ / 2;
y_ = y - h_ / 2;
}
private:
virtual bool isInside(float px, float py) const
{
float margin = 5.0f;
return px >= x_ - margin && py >= y_ - margin && px <= x_ + w_ + margin && py <= y_ + h_ + margin;
}
const Atlas *atlas_;
int imageIndex_;
int overlayImageIndex_;
int button_;
int rotationAngle_;
float x_, y_;
float w_;
float h_;
// TODO: simplify into flags.
bool pointerDown[MAX_POINTERS];
};
// Multi-touch enabled virtual joystick
// (any finger will work, simultaneously with other virtual button/stick actions).
class TouchStick
{
public:
TouchStick(const Atlas *atlas, int bgImageIndex, int stickImageIndex, int stick);
void update(InputState &input_state);
void draw(DrawBuffer &db);
void setPos(float x, float y) {
stick_x_ = x;
stick_y_ = y;
}
private:
const Atlas *atlas_;
int bgImageIndex_;
int stickImageIndex_;
int stick_;
int stick_size_;
float stick_x_;
float stick_y_;
// maintained for drawing only
float stick_delta_x_;
float stick_delta_y_;
};