Dear developers, The following patch adds the possibility (with the default parameters it have no effect) to remove distortion on the borders of the screen by defining a border width, if the stylus is in the border (according to its width) the position of the cursor is corrected by a polynomial of degree 3. The four coefficients of the polynomial must also be given in parameter. Therefore there is 4(topx topy bottomx bottomy) x (1(width)+4(polynomial coefficients)) = 20 floating point values in the parameter.
To find the appropriate parameters I am creating a calibration tool, it calibrate the center of the screen then it calibrate the borders. git link : https://github.com/antigol/wacom-distortion The calibration tool is still in development but it seems to work. Yours faithfully, Mario Geiger
diff --git include/wacom-properties.h include/wacom-properties.h index b845083..54e7793 100644 --- include/wacom-properties.h +++ include/wacom-properties.h @@ -27,6 +27,9 @@ /* 32 bit, 4 values, top x, top y, bottom x, bottom y */ #define WACOM_PROP_TABLET_AREA "Wacom Tablet Area" +/* 32 bit, 4x5=20 values, 4x[border width, polynomial coefficient x^3, x^2, x, 1] */ +#define WACOM_PROP_TABLET_DISTORTION "Wacom Border Distortion" + /* 8 bit, 1 value, [0 - 3] (NONE, CW, CCW, HALF) */ #define WACOM_PROP_ROTATION "Wacom Rotation" diff --git src/wcmCommon.c src/wcmCommon.c index 9408f42..f8be62e 100644 --- src/wcmCommon.c +++ src/wcmCommon.c @@ -438,6 +438,21 @@ static void sendCommonEvents(InputInfoPtr pInfo, const WacomDeviceState* ds, sendWheelStripEvents(pInfo, ds, first_val, num_vals, valuators); } +static double wcmBorderDistortionCorrection(double coord, float border, float* polynomial) +{ + if (coord < border) { + double x = coord; + coord = polynomial[0]; + coord *= x; + coord += polynomial[1]; // I wonder if double+float is slower than double+double + coord *= x; + coord += polynomial[2]; + coord *= x; + coord += polynomial[3]; + } + return coord; +} + /* rotate x and y before post X inout events */ void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y) { @@ -446,19 +461,36 @@ void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y) DeviceIntPtr dev = pInfo->dev; AxisInfoPtr axis_x, axis_y; int tmp_coord; + double f; /* scale into on topX/topY area */ axis_x = &dev->valuator->axes[0]; axis_y = &dev->valuator->axes[1]; /* Don't try to scale relative axes */ - if (axis_x->max_value > axis_x->min_value) - *x = xf86ScaleAxis(*x, axis_x->max_value, axis_x->min_value, - priv->bottomX, priv->topX); - - if (axis_y->max_value > axis_y->min_value) - *y = xf86ScaleAxis(*y, axis_y->max_value, axis_y->min_value, - priv->bottomY, priv->topY); + if (axis_x->max_value > axis_x->min_value) { + f = (*x - priv->topX) / (double)(priv->bottomX - priv->topX); + f = wcmBorderDistortionCorrection(f, priv->distortion_topX_border, priv->distortion_topX_poly); + f = 1.0 - f; + f = wcmBorderDistortionCorrection(f, priv->distortion_bottomX_border, priv->distortion_bottomX_poly); + f = 1.0 - f; + + *x = round(f * (axis_x->max_value - axis_x->min_value) + axis_x->min_value); + if (*x < axis_x->min_value) *x = axis_x->min_value; + if (*x > axis_x->max_value) *x = axis_x->max_value; + } + + if (axis_y->max_value > axis_y->min_value) { + f = (*y - priv->topY) / (double)(priv->bottomY - priv->topY); + f = wcmBorderDistortionCorrection(f, priv->distortion_topY_border, priv->distortion_topY_poly); + f = 1.0 - f; + f = wcmBorderDistortionCorrection(f, priv->distortion_bottomY_border, priv->distortion_bottomY_poly); + f = 1.0 - f; + + *y = round(f * (axis_y->max_value - axis_y->min_value) + axis_y->min_value); + if (*y < axis_y->min_value) *y = axis_y->min_value; + if (*y > axis_y->max_value) *y = axis_y->max_value; + } /* coordinates are now in the axis rage we advertise for the device */ diff --git src/wcmXCommand.c src/wcmXCommand.c index 346ff61..ec0d81c 100644 --- src/wcmXCommand.c +++ src/wcmXCommand.c @@ -33,6 +33,12 @@ #define XI_PROP_PRODUCT_ID "Device Product ID" #endif +#ifndef XATOM_FLOAT +#define XATOM_FLOAT "FLOAT" +#endif + +static Atom float_type; + static void wcmBindToSerial(InputInfoPtr pInfo, unsigned int serial); /***************************************************************************** @@ -82,6 +88,7 @@ int wcmDevSwitchMode(ClientPtr client, DeviceIntPtr dev, int mode) static Atom prop_devnode; static Atom prop_rotation; static Atom prop_tablet_area; +static Atom prop_distortion; static Atom prop_pressurecurve; static Atom prop_serials; static Atom prop_serial_binding; @@ -204,11 +211,23 @@ static Atom InitWcmAtom(DeviceIntPtr dev, const char *name, Atom type, int forma return atom; } +static Atom InitFloatAtom(DeviceIntPtr dev, const char *name, int nvalues, float *values) +{ + Atom atom; + + atom = MakeAtom(name, strlen(name), TRUE); + XIChangeDeviceProperty(dev, atom, float_type, 32, + PropModeReplace, nvalues, values, FALSE); + XISetDevicePropertyDeletable(dev, atom, FALSE); + return atom; +} + void InitWcmDeviceProperties(InputInfoPtr pInfo) { WacomDevicePtr priv = (WacomDevicePtr) pInfo->private; WacomCommonPtr common = priv->common; int values[WCM_MAX_BUTTONS]; + float fvalues[20]; int i; DBG(10, priv, "\n"); @@ -227,6 +246,23 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo) prop_tablet_area = InitWcmAtom(pInfo->dev, WACOM_PROP_TABLET_AREA, XA_INTEGER, 32, 4, values); } + if (!IsPad(priv)) { + float_type = XIGetKnownProperty(XATOM_FLOAT); + if (!float_type) float_type = MakeAtom(XATOM_FLOAT, strlen(XATOM_FLOAT), TRUE); + + if (float_type) { + // topX, topY, bottomX, bottomY + for (i = 0; i < 4; ++i) { + fvalues[i*5+0] = 0.0; // border + fvalues[i*5+1] = 0.0; // x^3 + fvalues[i*5+2] = 0.0; // x^2 + fvalues[i*5+3] = 1.0; // x + fvalues[i*5+4] = 0.0; // 1 + } + prop_distortion = InitFloatAtom(pInfo->dev, WACOM_PROP_TABLET_DISTORTION, 20, fvalues); + } + } + values[0] = common->wcmRotate; if (!IsPad(priv)) { prop_rotation = InitWcmAtom(pInfo->dev, WACOM_PROP_ROTATION, XA_INTEGER, 8, 1, values); @@ -683,6 +719,15 @@ int wcmDeleteProperty(DeviceIntPtr dev, Atom property) return (i >= 0) ? BadAccess : Success; } +static void setDistortionProperty(float* values, float *border, float *polynomial) +{ + *border = values[0]; // border width relatively to the screen dimension + polynomial[0] = values[1]; // x^3 coefficient of the polynomial + polynomial[1] = values[2]; // x^2 coefficient + polynomial[2] = values[3]; // x coefficient + polynomial[3] = values[4]; // constant coefficient +} + int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, BOOL checkonly) { @@ -717,6 +762,20 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop, priv->bottomX = values[2]; priv->bottomY = values[3]; } + } else if (property == prop_distortion) + { + float *values = (float*)prop->data; + + if (prop->size != 20 || prop->format != 32 || prop->type != float_type) + return BadValue; + + if (!checkonly) + { + setDistortionProperty(values, &priv->distortion_topX_border, priv->distortion_topX_poly); + setDistortionProperty(values+5, &priv->distortion_topY_border, priv->distortion_topY_poly); + setDistortionProperty(values+10, &priv->distortion_bottomX_border, priv->distortion_bottomX_poly); + setDistortionProperty(values+15, &priv->distortion_bottomY_border, priv->distortion_bottomY_poly); + } } else if (property == prop_pressurecurve) { INT32 *pcurve; diff --git src/xf86WacomDefs.h src/xf86WacomDefs.h index 1575960..2d76514 100644 --- src/xf86WacomDefs.h +++ src/xf86WacomDefs.h @@ -262,6 +262,16 @@ struct _WacomDeviceRec unsigned int cur_serial; /* current serial in prox */ int cur_device_id; /* current device ID in prox */ + /* distortion */ + float distortion_topX_border; + float distortion_topY_border; + float distortion_bottomX_border; + float distortion_bottomY_border; + float distortion_topX_poly[4]; + float distortion_topY_poly[4]; + float distortion_bottomX_poly[4]; + float distortion_bottomY_poly[4]; + /* button mapping information * * 'button' variables are indexed by physical button number (0..nbuttons)
------------------------------------------------------------------------------
_______________________________________________ Linuxwacom-devel mailing list Linuxwacom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel