mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-10 08:12:39 +00:00
Simple framework for virtual touchscreen buttons
This commit is contained in:
parent
ce2be356b2
commit
70e6752884
@ -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
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -6,4 +6,5 @@ int dp_yres;
|
||||
int pixel_xres;
|
||||
int pixel_yres;
|
||||
|
||||
int g_dpi;
|
||||
int g_dpi;
|
||||
float g_dpi_scale;
|
@ -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;
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -1,6 +1,7 @@
|
||||
set(SRCS
|
||||
ui.cpp
|
||||
screen.cpp
|
||||
virtual_input.cpp
|
||||
)
|
||||
|
||||
set(SRCS ${SRCS})
|
||||
|
80
ui/virtual_input.cpp
Normal file
80
ui/virtual_input.cpp
Normal 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
69
ui/virtual_input.h
Normal 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_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user