mirror of
https://github.com/GayPizzaSpecifications/padlab.git
synced 2025-08-03 21:21:33 +00:00
ch ch ch ch changes! big ol overhaul:
- Hidpi support - Display & edit both sticks individually - Clearer distinction between raw & filtered position - Param editing & preview for digital - Digital has an angle parameter - Touched up CMakeLists.txt - gitignore
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.idea/
|
||||||
|
cmake-build-*/
|
||||||
|
build/
|
||||||
|
|
||||||
|
.DS_Store
|
@ -1,13 +1,14 @@
|
|||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
|
||||||
set(PROJECT analogue)
|
project(analogue C)
|
||||||
set(SOURCES analogue.c)
|
|
||||||
|
|
||||||
project(${PROJECT} C)
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
find_package(SDL2 REQUIRED)
|
set(TARGET analogue)
|
||||||
add_definitions(${SDL2_CFLAGS})
|
set(SOURCES
|
||||||
include_directories(${SDL2_INCLUDE_DIRS})
|
maths.c maths.h
|
||||||
set(LIBRARIES ${SDL2_LIBRARIES} m)
|
analogue.c)
|
||||||
|
|
||||||
add_executable(${PROJECT} ${SOURCES})
|
find_package(SDL2 REQUIRED)
|
||||||
target_link_libraries(${PROJECT} ${LIBRARIES})
|
|
||||||
|
add_executable(${TARGET} ${SOURCES})
|
||||||
|
target_link_libraries(${TARGET} SDL2::SDL2 m)
|
||||||
|
target_compile_options(${TARGET} PRIVATE
|
||||||
|
-Wall -Wextra -pedantic -Wno-unused-parameter)
|
||||||
|
471
analogue.c
471
analogue.c
@ -1,9 +1,9 @@
|
|||||||
|
#include "maths.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#define CAPTIION "Analogue"
|
#define CAPTION "Analogue"
|
||||||
#define WINDOW_WIDTH 512
|
#define WINDOW_WIDTH 512
|
||||||
#define WINDOW_HEIGHT 288
|
#define WINDOW_HEIGHT 288
|
||||||
|
|
||||||
@ -14,24 +14,6 @@ SDL_Renderer* rend = NULL;
|
|||||||
SDL_JoystickID joyid = -1;
|
SDL_JoystickID joyid = -1;
|
||||||
SDL_GameController* pad = NULL;
|
SDL_GameController* pad = NULL;
|
||||||
|
|
||||||
typedef double vec_t;
|
|
||||||
typedef struct {vec_t x, y;} vector;
|
|
||||||
|
|
||||||
static inline vector VecAdd(vector l, vector r)
|
|
||||||
{
|
|
||||||
return (vector){l.x + r.x, l.y + r.y};
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline vector VecScale(vector v, vec_t x)
|
|
||||||
{
|
|
||||||
return (vector){v.x * x, v.y * x};
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double pfmod(double x, double d)
|
|
||||||
{
|
|
||||||
return fmod(fmod(x, d) + d, (d));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UseGamepad(int a_joyid)
|
bool UseGamepad(int a_joyid)
|
||||||
{
|
{
|
||||||
pad = SDL_GameControllerOpen(a_joyid);
|
pad = SDL_GameControllerOpen(a_joyid);
|
||||||
@ -46,7 +28,7 @@ bool UseGamepad(int a_joyid)
|
|||||||
|
|
||||||
void DrawCircle(int x, int y, int r, int steps)
|
void DrawCircle(int x, int y, int r, int steps)
|
||||||
{
|
{
|
||||||
double stepsz = (M_PI * 2.0) / steps;
|
double stepsz = (TAU) / steps;
|
||||||
int lastx = r;
|
int lastx = r;
|
||||||
int lasty = 0;
|
int lasty = 0;
|
||||||
for (int i = 0; i <= steps; ++i)
|
for (int i = 0; i <= steps; ++i)
|
||||||
@ -54,7 +36,7 @@ void DrawCircle(int x, int y, int r, int steps)
|
|||||||
const double mag = (double)r;
|
const double mag = (double)r;
|
||||||
int ofsx = (int)round(cos(stepsz * i) * mag);
|
int ofsx = (int)round(cos(stepsz * i) * mag);
|
||||||
int ofsy = (int)round(sin(stepsz * i) * mag);
|
int ofsy = (int)round(sin(stepsz * i) * mag);
|
||||||
|
|
||||||
SDL_RenderDrawLine(rend,
|
SDL_RenderDrawLine(rend,
|
||||||
x + lastx, y + lasty,
|
x + lastx, y + lasty,
|
||||||
x + ofsx, y + ofsy);
|
x + ofsx, y + ofsy);
|
||||||
@ -82,33 +64,28 @@ vector RadialDeadzone(vector v, double min, double max)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector DigitalEight(vector v, double deadzone)
|
vector DigitalEight(vector v, double angle, double deadzone)
|
||||||
{
|
{
|
||||||
vector res = {0, 0};
|
vector res = {0, 0};
|
||||||
|
|
||||||
if (fabs(v.x) > fabs(v.y * 2.0))
|
if (fabs(v.x) * angle > fabs(v.y))
|
||||||
{
|
{
|
||||||
if (fabs(v.x) > deadzone)
|
if (fabs(v.x) > deadzone)
|
||||||
res.x = copysign(1.0, v.x);
|
res.x = copysign(1.0, v.x);
|
||||||
}
|
}
|
||||||
else if (fabs(v.y) > fabs(v.x * 2.0))
|
else if (fabs(v.y) * angle > fabs(v.x))
|
||||||
{
|
{
|
||||||
if (fabs(v.y) > deadzone)
|
if (fabs(v.y) > deadzone)
|
||||||
res.y = copysign(1.0, v.y);
|
res.y = copysign(1.0, v.y);
|
||||||
}
|
}
|
||||||
else if (fabs(v.x) + fabs(v.y) > deadzone * 1.5)
|
else if (fabs(v.x) + fabs(v.y) > deadzone * (1.0 + angle))
|
||||||
{
|
{
|
||||||
const double dscale = 1/sqrt(2);
|
const double dscale = 1/sqrt(2);
|
||||||
res.x = copysign(dscale, v.x);
|
res.x = copysign(dscale, v.x);
|
||||||
res.y = copysign(dscale, v.y);
|
res.y = copysign(dscale, v.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline double AccelCurve(double x, double y)
|
return res;
|
||||||
{
|
|
||||||
return (x * (x + y)) / (1.0 + y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vector ApplyAcceleration(vector v, double y)
|
vector ApplyAcceleration(vector v, double y)
|
||||||
@ -125,6 +102,234 @@ vector ApplyAcceleration(vector v, double y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// common
|
||||||
|
vector rawpos, compos;
|
||||||
|
bool recalc;
|
||||||
|
|
||||||
|
// analogue
|
||||||
|
double preaccel, postacel;
|
||||||
|
double accelpow;
|
||||||
|
double deadzone;
|
||||||
|
|
||||||
|
// digital
|
||||||
|
double digiangle;
|
||||||
|
double digideadzone;
|
||||||
|
} StickState;
|
||||||
|
|
||||||
|
void InitDefaults(StickState* p)
|
||||||
|
{
|
||||||
|
p->rawpos = (vector){0.0, 0.0};
|
||||||
|
p->compos = (vector){0.0, 0.0};
|
||||||
|
|
||||||
|
p->recalc = true;
|
||||||
|
p->preaccel = 0.0;
|
||||||
|
p->postacel = 0.0;
|
||||||
|
p->accelpow = 1.25;
|
||||||
|
p->deadzone = 0.125;
|
||||||
|
|
||||||
|
p->digiangle = sqrt(2.0) - 1.0;
|
||||||
|
p->digideadzone = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawAnalogue(const SDL_Rect* win, StickState* p)
|
||||||
|
{
|
||||||
|
if (p->recalc)
|
||||||
|
{
|
||||||
|
p->compos = RadialDeadzone(p->rawpos, p->deadzone, 0.99);
|
||||||
|
p->preaccel = sqrt(p->compos.x * p->compos.x + p->compos.y * p->compos.y);
|
||||||
|
p->compos = ApplyAcceleration(p->compos, p->accelpow);
|
||||||
|
p->postacel = sqrt(p->compos.x * p->compos.x + p->compos.y * p->compos.y);
|
||||||
|
|
||||||
|
p->recalc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect rect;
|
||||||
|
double size = (double)(win->w > win->h ? win->h : win->w) * DISPLAY_SCALE;
|
||||||
|
|
||||||
|
// range rect
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
||||||
|
rect.w = rect.h = (int)round(size);
|
||||||
|
rect.x = win->x + (win->w - rect.w) / 2;
|
||||||
|
rect.y = win->y + (win->h - rect.h) / 2;
|
||||||
|
SDL_RenderDrawRect(rend, &rect);
|
||||||
|
|
||||||
|
const int ox = win->x + win->w / 2;
|
||||||
|
const int oy = win->y + win->h / 2;
|
||||||
|
|
||||||
|
// acceleration curve
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x4F, 0x4F, 0x4F, 0xFF);
|
||||||
|
const int accelsamp = (int)(sqrt(size) * 4.20);
|
||||||
|
const double step = 1.0 / (double)accelsamp;
|
||||||
|
double y1 = AccelCurve(0.0, p->accelpow);
|
||||||
|
for (int i = 1; i <= accelsamp; ++i)
|
||||||
|
{
|
||||||
|
double y2 = AccelCurve(step * i, p->accelpow);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
win->x + (int)(step * (i - 1) * size) + (win->w - (int)round(size)) / 2,
|
||||||
|
win->y + (int)((1.0 - y1) * size) + (win->h - (int)round(size)) / 2,
|
||||||
|
win->x + (int)(step * i * size) + (win->w - (int)round(size)) / 2,
|
||||||
|
win->y + (int)((1.0 - y2) * size) + (win->h - (int)round(size)) / 2);
|
||||||
|
y1 = y2;
|
||||||
|
}
|
||||||
|
const int tickerx = (int)((p->preaccel - 0.5) * size);
|
||||||
|
const int tickery = (int)((0.5 - p->postacel) * size);
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x2F, 0x3F, 0x1F, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox + tickerx,
|
||||||
|
win->y + (win->h - (int)round(size)) / 2,
|
||||||
|
ox + tickerx,
|
||||||
|
win->y + (win->h + (int)round(size)) / 2);
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x2F, 0x5F, 0x2F, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
win->x + (win->w - (int)round(size)) / 2,
|
||||||
|
oy + tickery,
|
||||||
|
win->x + (win->w + (int)round(size)) / 2,
|
||||||
|
oy + tickery);
|
||||||
|
|
||||||
|
// guide circle
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x4F, 0x4F, 0x4F, 0xFF);
|
||||||
|
DrawCircle(
|
||||||
|
ox, oy,
|
||||||
|
(int)round(size) / 2, (int)(sqrt(size) * 8.0));
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
||||||
|
DrawCircle(
|
||||||
|
ox, oy,
|
||||||
|
(int)round(p->deadzone * size) / 2, (int)(sqrt(size) * 2.0));
|
||||||
|
|
||||||
|
// 0,0 line axis'
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x2F, 0x2F, 0x2F, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
win->x,
|
||||||
|
oy,
|
||||||
|
win->x + win->w,
|
||||||
|
oy);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox,
|
||||||
|
win->y,
|
||||||
|
ox,
|
||||||
|
win->y + win->h);
|
||||||
|
|
||||||
|
// compensated position
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x1F, 0xFF, 0x1F, 0xFF);
|
||||||
|
DrawCircle(
|
||||||
|
ox + (int)round(p->compos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->compos.y * size / 2.0),
|
||||||
|
8, 16);
|
||||||
|
SDL_RenderDrawPoint(rend,
|
||||||
|
ox + (int)round(p->compos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->compos.y * size / 2.0));
|
||||||
|
|
||||||
|
// raw position
|
||||||
|
SDL_SetRenderDrawColor(rend, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0) - 4,
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0),
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0) + 4,
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0));
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0) - 4,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0) + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawDigital(const SDL_Rect* win, StickState* p)
|
||||||
|
{
|
||||||
|
if (p->recalc)
|
||||||
|
{
|
||||||
|
p->compos = DigitalEight(p->rawpos, p->digiangle, p->digideadzone);
|
||||||
|
p->recalc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect rect;
|
||||||
|
const double size = (double)(win->w > win->h ? win->h : win->w) * DISPLAY_SCALE;
|
||||||
|
|
||||||
|
// range rect
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
||||||
|
rect.w = rect.h = (int)round(size);
|
||||||
|
rect.x = win->x + (win->w - rect.w) / 2;
|
||||||
|
rect.y = win->y + (win->h - rect.h) / 2;
|
||||||
|
SDL_RenderDrawRect(rend, &rect);
|
||||||
|
|
||||||
|
// window centre
|
||||||
|
const int ox = win->x + win->w / 2;
|
||||||
|
const int oy = win->y + win->h / 2;
|
||||||
|
|
||||||
|
// guide circle
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x4F, 0x4F, 0x4F, 0xFF);
|
||||||
|
DrawCircle(ox, oy,
|
||||||
|
(int)round(size) / 2, (int)(sqrt(size) * 8.0));
|
||||||
|
|
||||||
|
// 0,0 line axis'
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x2F, 0x2F, 0x2F, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
win->x,
|
||||||
|
oy,
|
||||||
|
win->x + win->w,
|
||||||
|
oy);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox,
|
||||||
|
win->y,
|
||||||
|
ox,
|
||||||
|
win->y + win->h);
|
||||||
|
|
||||||
|
// calcuate points for the zone previews
|
||||||
|
const double outerinvmag = 1.0 / sqrt(1.0 + p->digiangle * p->digiangle);
|
||||||
|
const int outh = (int)round((size * outerinvmag) / 2.0);
|
||||||
|
const int outq = (int)round((size * outerinvmag) / 2.0 * p->digiangle);
|
||||||
|
const int innh = (int)round(p->digideadzone * size / 2.0);
|
||||||
|
const int innq = (int)round(p->digideadzone * size / 2.0 * p->digiangle);
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
||||||
|
|
||||||
|
// angles preview
|
||||||
|
SDL_RenderDrawLine(rend, ox - outq, oy - outh, ox - innq, oy - innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox + outq, oy - outh, ox + innq, oy - innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox + outh, oy - outq, ox + innh, oy - innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox + outh, oy + outq, ox + innh, oy + innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox + outq, oy + outh, ox + innq, oy + innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox - outq, oy + outh, ox - innq, oy + innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox - outh, oy + outq, ox - innh, oy + innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox - outh, oy - outq, ox - innh, oy - innq);
|
||||||
|
|
||||||
|
// deadzone octagon
|
||||||
|
SDL_RenderDrawLine(rend, ox - innq, oy - innh, ox + innq, oy - innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox + innq, oy - innh, ox + innh, oy - innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox + innh, oy - innq, ox + innh, oy - innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox + innh, oy - innq, ox + innh, oy + innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox + innh, oy + innq, ox + innq, oy + innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox + innq, oy + innh, ox - innq, oy + innh);
|
||||||
|
SDL_RenderDrawLine(rend, ox - innq, oy + innh, ox - innh, oy + innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox - innh, oy + innq, ox - innh, oy - innq);
|
||||||
|
SDL_RenderDrawLine(rend, ox - innh, oy - innq, ox - innq, oy - innh);
|
||||||
|
|
||||||
|
// compensated position
|
||||||
|
SDL_SetRenderDrawColor(rend, 0x1F, 0xFF, 0x1F, 0xFF);
|
||||||
|
DrawCircle(
|
||||||
|
ox + (int)round(p->compos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->compos.y * size / 2.0),
|
||||||
|
8, 16);
|
||||||
|
SDL_RenderDrawPoint(rend,
|
||||||
|
ox + (int)round(p->compos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->compos.y * size / 2.0));
|
||||||
|
|
||||||
|
// raw position
|
||||||
|
SDL_SetRenderDrawColor(rend, 0xFF, 0xFF, 0xFF, 0xFF);
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0) - 4,
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0),
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0) + 4,
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0));
|
||||||
|
SDL_RenderDrawLine(rend,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0) - 4,
|
||||||
|
ox + (int)round(p->rawpos.x * size / 2.0),
|
||||||
|
oy + (int)round(p->rawpos.y * size / 2.0) + 4);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -134,22 +339,27 @@ int main(int argc, char** argv)
|
|||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
const int winpos = SDL_WINDOWPOS_CENTERED;
|
const int winpos = SDL_WINDOWPOS_CENTERED;
|
||||||
|
const int winflg = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
int winw = WINDOW_WIDTH;
|
int winw = WINDOW_WIDTH;
|
||||||
int winh = WINDOW_HEIGHT;
|
int winh = WINDOW_HEIGHT;
|
||||||
window = SDL_CreateWindow(CAPTIION, winpos, winpos, winw, winh, SDL_WINDOW_RESIZABLE);
|
window = SDL_CreateWindow(CAPTION, winpos, winpos, winw, winh, winflg);
|
||||||
if (window == NULL)
|
if (window == NULL)
|
||||||
{
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
rend = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC);
|
const int rendflags = SDL_RENDERER_PRESENTVSYNC;
|
||||||
|
rend = SDL_CreateRenderer(window, -1, rendflags);
|
||||||
if (rend == NULL)
|
if (rend == NULL)
|
||||||
{
|
{
|
||||||
res = -1;
|
res = -1;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rw, rh;
|
||||||
|
SDL_GetRendererOutputSize(rend, &rw, &rh);
|
||||||
|
|
||||||
if ((res = SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt")) != -1)
|
if ((res = SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt")) != -1)
|
||||||
printf("read %d mappings from gamecontrollerdb.txt\n", res);
|
printf("read %d mappings from gamecontrollerdb.txt\n", res);
|
||||||
for (int i = 0; i < SDL_NumJoysticks(); ++i)
|
for (int i = 0; i < SDL_NumJoysticks(); ++i)
|
||||||
@ -162,28 +372,26 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vector plrpos = {10.0, 10.0};
|
vector plrpos = {10.0, 10.0};
|
||||||
vector rawpos = {0.0, 0.0};
|
StickState stickl, stickr;
|
||||||
vector compos = {0.0, 0.0};
|
InitDefaults(&stickl);
|
||||||
|
InitDefaults(&stickr);
|
||||||
double preaccel = 0.0, postacel = 0.0;
|
|
||||||
double accelpow = 1.25;
|
|
||||||
double deadzone = 0.125;
|
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
bool recalcs = true;
|
|
||||||
bool repaint = true;
|
bool repaint = true;
|
||||||
bool avatare = false;
|
bool showavatar = false;
|
||||||
uint32_t tickslast = SDL_GetTicks();
|
uint32_t tickslast = SDL_GetTicks();
|
||||||
|
int side = 0;
|
||||||
|
|
||||||
while (running)
|
while (running)
|
||||||
{
|
{
|
||||||
|
//FIXME: probably doesn't matter but this isn't very precise
|
||||||
const uint32_t ticks = SDL_GetTicks();
|
const uint32_t ticks = SDL_GetTicks();
|
||||||
double framedelta = (double)(ticks - tickslast);
|
const double framedelta = (double)(ticks - tickslast);
|
||||||
tickslast = ticks;
|
tickslast = ticks;
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
bool onevent = false;
|
bool onevent = false;
|
||||||
if (!avatare || (compos.x == 0.0 && compos.y == 0.0))
|
if (!showavatar || (stickl.compos.x == 0.0 && stickl.compos.y == 0.0))
|
||||||
{
|
{
|
||||||
onevent = SDL_WaitEvent(&event) != 0;
|
onevent = SDL_WaitEvent(&event) != 0;
|
||||||
}
|
}
|
||||||
@ -205,7 +413,15 @@ int main(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
else if (event.key.keysym.sym == SDLK_e)
|
else if (event.key.keysym.sym == SDLK_e)
|
||||||
{
|
{
|
||||||
avatare = !avatare;
|
showavatar = !showavatar;
|
||||||
|
repaint = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (SDL_CONTROLLERBUTTONDOWN):
|
||||||
|
if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK)
|
||||||
|
{
|
||||||
|
showavatar = !showavatar;
|
||||||
repaint = true;
|
repaint = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -219,6 +435,7 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
winw = event.window.data1;
|
winw = event.window.data1;
|
||||||
winh = event.window.data2;
|
winh = event.window.data2;
|
||||||
|
SDL_GetRendererOutputSize(rend, &rw, &rh);
|
||||||
repaint = true;
|
repaint = true;
|
||||||
}
|
}
|
||||||
else if (event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
else if (event.window.event == SDL_WINDOWEVENT_EXPOSED)
|
||||||
@ -230,31 +447,67 @@ int main(int argc, char** argv)
|
|||||||
case (SDL_CONTROLLERAXISMOTION):
|
case (SDL_CONTROLLERAXISMOTION):
|
||||||
if (event.caxis.which == joyid)
|
if (event.caxis.which == joyid)
|
||||||
{
|
{
|
||||||
if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX)
|
if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX)
|
||||||
{
|
{
|
||||||
rawpos.x = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
stickl.rawpos.x = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
||||||
repaint = recalcs = true;
|
repaint = stickl.recalc = true;
|
||||||
|
}
|
||||||
|
else if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY)
|
||||||
|
{
|
||||||
|
stickl.rawpos.y = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
||||||
|
repaint = stickl.recalc = true;
|
||||||
|
}
|
||||||
|
else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX)
|
||||||
|
{
|
||||||
|
stickr.rawpos.x = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
||||||
|
repaint = stickr.recalc = true;
|
||||||
}
|
}
|
||||||
else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
|
else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
|
||||||
{
|
{
|
||||||
rawpos.y = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
stickr.rawpos.y = (vec_t)event.caxis.value / (vec_t)0x7FFF;
|
||||||
repaint = recalcs = true;
|
repaint = stickr.recalc = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (SDL_MOUSEBUTTONDOWN):
|
||||||
|
if (event.button.state & (SDL_BUTTON_LMASK | SDL_BUTTON_RMASK ))
|
||||||
|
{
|
||||||
|
side = (event.button.x > winw / 2) ? 1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case (SDL_MOUSEMOTION):
|
case (SDL_MOUSEMOTION):
|
||||||
if (event.motion.state & SDL_BUTTON_LMASK)
|
if (event.motion.state & SDL_BUTTON_LMASK)
|
||||||
{
|
{
|
||||||
rawpos.x = ((double)event.motion.x - winw / 2.0) / (winh * DISPLAY_SCALE / 2.0);
|
const double hwinw = winw / 2.0;
|
||||||
rawpos.y = ((double)event.motion.y - winh / 2.0) / (winh * DISPLAY_SCALE / 2.0);
|
const double dispscale = 1.0 / (((hwinw > winh) ? winh : hwinw) * DISPLAY_SCALE / 2.0);
|
||||||
repaint = recalcs = true;
|
const vector newpos = {
|
||||||
|
CLAMP(((double)event.motion.x - hwinw / 2.0 - hwinw * side) * dispscale, -1.0, 1.0),
|
||||||
|
CLAMP(((double)event.motion.y - winh / 2.0) * dispscale, -1.0, 1.0) };
|
||||||
|
|
||||||
|
StickState* stick = side ? &stickr : &stickl;
|
||||||
|
stick->rawpos = newpos;
|
||||||
|
repaint = stick->recalc = true;
|
||||||
}
|
}
|
||||||
else if (event.motion.state & SDL_BUTTON_RMASK)
|
else if (event.motion.state & SDL_BUTTON_RMASK)
|
||||||
{
|
{
|
||||||
double scale = 1.0 - ((double)event.motion.y / (double)winh);
|
const double hwinw = winw / 2.0;
|
||||||
//accelpow = scale * scale * scale * 32;
|
const double valx = SATURATE(1.0 - (double)event.motion.x / (double)hwinw);
|
||||||
accelpow = pow(scale * 3, 1.0 + scale * 3);
|
const double valy = SATURATE(1.0 - (double)event.motion.y / (double)winh);
|
||||||
repaint = recalcs = true;
|
|
||||||
|
if (side == 0)
|
||||||
|
{
|
||||||
|
stickl.digiangle = valx;
|
||||||
|
stickl.digideadzone = valy;
|
||||||
|
repaint = stickl.recalc = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//p2.accelpow = valy * valy * valy * 32;
|
||||||
|
stickr.accelpow = pow(valy * 3, 1.0 + valy * 3);
|
||||||
|
repaint = stickr.recalc = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case (SDL_CONTROLLERDEVICEADDED):
|
case (SDL_CONTROLLERDEVICEADDED):
|
||||||
@ -277,102 +530,32 @@ int main(int argc, char** argv)
|
|||||||
while (SDL_PollEvent(&event) > 0);
|
while (SDL_PollEvent(&event) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recalcs)
|
|
||||||
{
|
|
||||||
compos = RadialDeadzone(rawpos, deadzone, 0.99);
|
|
||||||
//compos = DigitalEight(rawpos, 0.5);
|
|
||||||
preaccel = sqrt(compos.x * compos.x + compos.y * compos.y);
|
|
||||||
compos = ApplyAcceleration(compos, accelpow);
|
|
||||||
postacel = sqrt(compos.x * compos.x + compos.y * compos.y);
|
|
||||||
recalcs = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repaint)
|
if (repaint)
|
||||||
{
|
{
|
||||||
SDL_Rect rect;
|
|
||||||
double size = (double)(winw > winh ? winh : winw) * DISPLAY_SCALE;
|
|
||||||
|
|
||||||
// background
|
// background
|
||||||
SDL_SetRenderDrawColor(rend, 0x1F, 0x1F, 0x1F, 0xFF);
|
SDL_SetRenderDrawColor(rend, 0x1F, 0x1F, 0x1F, 0xFF);
|
||||||
SDL_RenderClear(rend);
|
SDL_RenderClear(rend);
|
||||||
|
|
||||||
|
const int hrw = rw / 2;
|
||||||
|
DrawDigital(&(SDL_Rect){ 0, 0, hrw, rh }, &stickl);
|
||||||
|
DrawAnalogue(&(SDL_Rect){hrw, 0, hrw, rh}, &stickr);
|
||||||
|
|
||||||
// test player thingo
|
// test player thingo
|
||||||
if (avatare)
|
if (showavatar)
|
||||||
{
|
{
|
||||||
plrpos = VecAdd(plrpos, VecScale(compos, framedelta * 0.5));
|
SDL_Rect rect;
|
||||||
plrpos.x = pfmod(plrpos.x, winw);
|
|
||||||
plrpos.y = pfmod(plrpos.y, winh);
|
plrpos = VecAdd(plrpos, VecScale(stickl.compos, framedelta * 0.5));
|
||||||
|
plrpos.x = pfmod(plrpos.x, rw);
|
||||||
|
plrpos.y = pfmod(plrpos.y, rh);
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(rend, 0xFF, 0x00, 0x00, 0xFF);
|
SDL_SetRenderDrawColor(rend, 0xFF, 0x00, 0x00, 0xFF);
|
||||||
rect.w = rect.h = 32;
|
rect.w = rect.h = 32;
|
||||||
rect.x = (int)plrpos.x - rect.w / 2;
|
rect.x = (int)plrpos.x - rect.w / 2;
|
||||||
rect.y = (int)plrpos.y - rect.h / 2;
|
rect.y = (int)plrpos.y - rect.h / 2;
|
||||||
SDL_RenderDrawRect(rend, &rect);
|
SDL_RenderDrawRect(rend, &rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// range rect
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
|
||||||
rect.w = rect.h = (int)round(size);
|
|
||||||
rect.x = (winw - rect.w) / 2;
|
|
||||||
rect.y = (winh - rect.h) / 2;
|
|
||||||
SDL_RenderDrawRect(rend, &rect);
|
|
||||||
|
|
||||||
// acceleration curve
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x4F, 0x4F, 0x4F, 0xFF);
|
|
||||||
const int accelsamp = (int)(sqrt(size) * 4.20);
|
|
||||||
double step = 1.0 / (double)accelsamp;
|
|
||||||
double y1 = AccelCurve(0.0, accelpow);
|
|
||||||
for (int i = 1; i <= accelsamp; ++i)
|
|
||||||
{
|
|
||||||
double y2 = AccelCurve(step * i, accelpow);
|
|
||||||
SDL_RenderDrawLine(rend,
|
|
||||||
(int)(step * (i - 1) * size) + (winw - (int)round(size)) / 2,
|
|
||||||
(int)((1.0 - y1) * size) + (winh - (int)round(size)) / 2,
|
|
||||||
(int)(step * i * size) + (winw - (int)round(size)) / 2,
|
|
||||||
(int)((1.0 - y2) * size) + (winh - (int)round(size)) / 2);
|
|
||||||
y1 = y2;
|
|
||||||
}
|
|
||||||
int tickerx = (int)((preaccel - 0.5) * size);
|
|
||||||
int tickery = (int)((0.5 - postacel) * size);
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x2F, 0x3F, 0x1F, 0xFF);
|
|
||||||
SDL_RenderDrawLine(rend,
|
|
||||||
winw / 2 + tickerx,
|
|
||||||
(winh - (int)round(size)) / 2,
|
|
||||||
winw / 2 + tickerx,
|
|
||||||
(winh + (int)round(size)) / 2);
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x2F, 0x5F, 0x2F, 0xFF);
|
|
||||||
SDL_RenderDrawLine(rend,
|
|
||||||
(winw - (int)round(size)) / 2,
|
|
||||||
winh / 2 + tickery,
|
|
||||||
(winw + (int)round(size)) / 2,
|
|
||||||
winh / 2 + tickery);
|
|
||||||
|
|
||||||
// guide circle
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x4F, 0x4F, 0x4F, 0xFF);
|
|
||||||
DrawCircle(winw / 2, winh / 2, (int)round(size) / 2, (int)(sqrt(size) * 8.0));
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x3F, 0x3F, 0x3F, 0xFF);
|
|
||||||
DrawCircle(winw / 2, winh / 2, (int)round(deadzone * size) / 2, (int)(sqrt(size) * 2.0));
|
|
||||||
|
|
||||||
// 0,0 line axis'
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x2F, 0x2F, 0x2F, 0xFF);
|
|
||||||
SDL_RenderDrawLine(rend, 0, winh / 2, winw, winh / 2);
|
|
||||||
SDL_RenderDrawLine(rend, winw / 2, 0, winw / 2, winh);
|
|
||||||
|
|
||||||
// compensated position
|
|
||||||
SDL_SetRenderDrawColor(rend, 0x1F, 0xFF, 0x1F, 0xFF);
|
|
||||||
DrawCircle(
|
|
||||||
winw / 2 + (int)round(compos.x * size / 2.0),
|
|
||||||
winh / 2 + (int)round(compos.y * size / 2.0),
|
|
||||||
4, 8);
|
|
||||||
|
|
||||||
// raw position
|
|
||||||
SDL_SetRenderDrawColor(rend, 0xFF, 0xFF, 0xFF, 0xFF);
|
|
||||||
DrawCircle(
|
|
||||||
winw / 2 + (int)round(rawpos.x * size / 2.0),
|
|
||||||
winh / 2 + (int)round(rawpos.y * size / 2.0),
|
|
||||||
8, 16);
|
|
||||||
|
|
||||||
SDL_RenderPresent(rend);
|
SDL_RenderPresent(rend);
|
||||||
repaint = false;
|
repaint = false;
|
||||||
}
|
}
|
||||||
|
7
maths.c
7
maths.c
@ -1,5 +1,8 @@
|
|||||||
#include "vector.h"
|
#include "maths.h"
|
||||||
|
|
||||||
static inline vector VecAdd(vector l, vector r);
|
static inline vector VecAdd(vector l, vector r);
|
||||||
|
|
||||||
static inline vector VecScale(vector v, vec_t x);
|
static inline vector VecScale(vector v, vec_t x);
|
||||||
|
|
||||||
|
static inline double pfmod(double x, double d);
|
||||||
|
|
||||||
|
double AccelCurve(double x, double y);
|
||||||
|
26
maths.h
26
maths.h
@ -1,5 +1,15 @@
|
|||||||
#ifndef VECTOR_H
|
#ifndef MATHS_H
|
||||||
#define VECTOR_H
|
#define MATHS_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define PI 3.141592653589793238462643383279502884L
|
||||||
|
#define TAU 6.283185307179586476925286766559005768L
|
||||||
|
|
||||||
|
#define MAX(LHS, RHS) ((LHS > RHS) ? (LHS) : (RHS))
|
||||||
|
#define MIN(LHS, RHS) ((LHS < RHS) ? (LHS) : (RHS))
|
||||||
|
#define CLAMP(X, A, B) (MIN(B, MAX(A, X)))
|
||||||
|
#define SATURATE(X) (CLAMP(X, 0, 1))
|
||||||
|
|
||||||
typedef double vec_t;
|
typedef double vec_t;
|
||||||
typedef struct {vec_t x, y;} vector;
|
typedef struct {vec_t x, y;} vector;
|
||||||
@ -14,4 +24,14 @@ static inline vector VecScale(vector v, vec_t x)
|
|||||||
return (vector){v.x * x, v.y * x};
|
return (vector){v.x * x, v.y * x};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//VECTOR_H
|
static inline double pfmod(double x, double d)
|
||||||
|
{
|
||||||
|
return fmod(fmod(x, d) + d, (d));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double AccelCurve(double x, double y)
|
||||||
|
{
|
||||||
|
return (x * (x + y)) / (1.0 + y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif//MATHS_H
|
||||||
|
Reference in New Issue
Block a user