Copy interface for Shepard tone synth.
This commit is contained in:
parent
b5a8b01804
commit
474dce4da9
|
@ -1,2 +1,3 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
add_subdirectory(yaw-tab)
|
||||
add_subdirectory(yaw-tab)
|
||||
add_subdirectory(yaw-shepard)
|
|
@ -0,0 +1,22 @@
|
|||
dpf_add_plugin(yaw-tab
|
||||
TARGETS vst2
|
||||
FILES_DSP
|
||||
dsp.cpp
|
||||
FILES_UI
|
||||
wtutil.cpp
|
||||
wintab.cpp
|
||||
rtstylus.cpp
|
||||
ui.cpp)
|
||||
|
||||
target_include_directories(yaw-tab PUBLIC
|
||||
"."
|
||||
"../../lib/wintab"
|
||||
)
|
||||
target_compile_definitions(yaw-tab PUBLIC YAW_USE_WINTAB)
|
||||
|
||||
set_target_properties(yaw-tab PROPERTIES VS_DOTNET_REFERENCES "System")
|
||||
set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/clr")
|
||||
set_target_properties(yaw-tab PROPERTIES COMPILE_FLAGS "/Zc:twoPhase-")
|
||||
|
||||
# default compiler flags from CMAKE conflict with managed code compliation, probably a better way of doing this.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
|
||||
#define DISTRHO_PLUGIN_INFO_H_INCLUDED
|
||||
|
||||
#define DISTRHO_PLUGIN_BRAND "yaw-audio"
|
||||
#define DISTRHO_PLUGIN_NAME "yaw-tab"
|
||||
#define DISTRHO_PLUGIN_URI "https://yaw.man/plugins/yaw-tab"
|
||||
|
||||
#define DISTRHO_PLUGIN_HAS_UI 1
|
||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1
|
||||
#define DISTRHO_PLUGIN_NUM_INPUTS 0
|
||||
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2
|
||||
#define DISTRHO_UI_USE_NANOVG 1
|
||||
|
||||
// only checking if supported, not actually used
|
||||
#define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 1
|
||||
|
||||
#ifdef __MOD_DEVICES__
|
||||
#define DISTRHO_PLUGIN_USES_MODGUI 1
|
||||
#endif
|
||||
|
||||
enum Parameters {
|
||||
ktpax = 0,
|
||||
ktpay,
|
||||
ktpaz,
|
||||
ktpap,
|
||||
kParameterButtonA,
|
||||
kParameterButtonB,
|
||||
kParameterTime,
|
||||
kParameterCount
|
||||
};
|
||||
|
||||
#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED
|
|
@ -0,0 +1,135 @@
|
|||
#include "DistrhoPlugin.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
class TabPlugin : public Plugin
|
||||
{
|
||||
public:
|
||||
TabPlugin()
|
||||
: Plugin(kParameterCount, 0, 0),
|
||||
sampleRate(getSampleRate())
|
||||
{
|
||||
// clear all parameters
|
||||
std::memset(fParameters, 0, sizeof(float) * kParameterCount);
|
||||
|
||||
}
|
||||
|
||||
protected:
|
||||
const char* getLabel() const override { return "yaw-tab"; }
|
||||
const char* getDescription() const override { return "Drawing tablet synth UI"; }
|
||||
const char* getMaker() const override { return "yaw-audio"; }
|
||||
const char* getHomePage() const override { return "https://yaw.man/plugins/yaw-tab"; }
|
||||
const char* getLicense() const override { return "ISC"; }
|
||||
uint32_t getVersion() const override { return d_version(1, 0, 0); }
|
||||
int64_t getUniqueId() const override { return d_cconst('y', 'w', 't', 'b'); }
|
||||
|
||||
|
||||
void initParameter(uint32_t index, Parameter& parameter) override
|
||||
{
|
||||
parameter.hints = kParameterIsAutomable;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case ktpax:
|
||||
parameter.name = "x";
|
||||
parameter.symbol = "x";
|
||||
break;
|
||||
case ktpay:
|
||||
parameter.name = "y";
|
||||
parameter.symbol = "y";
|
||||
break;
|
||||
case ktpaz:
|
||||
parameter.name = "z";
|
||||
parameter.symbol = "z";
|
||||
break;
|
||||
case ktpap:
|
||||
parameter.name = "p";
|
||||
parameter.symbol = "p";
|
||||
break;
|
||||
case kParameterButtonA:
|
||||
parameter.name = "Button A";
|
||||
parameter.symbol = "A";
|
||||
parameter.hints |= kParameterIsBoolean;
|
||||
break;
|
||||
case kParameterButtonB:
|
||||
parameter.name = "Button B";
|
||||
parameter.symbol = "B";
|
||||
parameter.hints |= kParameterIsBoolean;
|
||||
break;
|
||||
case kParameterTime:
|
||||
parameter.name = "t";
|
||||
parameter.symbol = "t";
|
||||
parameter.hints = kParameterIsOutput;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sampleRateChanged(double newRate) override
|
||||
{
|
||||
sampleRate = newRate;
|
||||
}
|
||||
|
||||
float getParameterValue(uint32_t index) const override
|
||||
{
|
||||
return fParameters[index];
|
||||
}
|
||||
|
||||
void setParameterValue(uint32_t idx, float val) override
|
||||
{
|
||||
fParameters[idx] = val;
|
||||
switch (idx) {
|
||||
case ktpax:
|
||||
period = 0.02f * val * static_cast<float>(sampleRate);
|
||||
break;
|
||||
case ktpay:
|
||||
break;
|
||||
case ktpaz:
|
||||
break;
|
||||
case ktpap:
|
||||
volume = val;
|
||||
break;
|
||||
case kParameterButtonA:
|
||||
break;
|
||||
case kParameterButtonB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void run(const float** inputs, float** outputs, uint32_t frames) override
|
||||
{
|
||||
|
||||
for (uint32_t i = 0; i < frames; ++i) {
|
||||
counter++;
|
||||
if (counter > period) {
|
||||
outputs[0][i] = outputs[1][i] = volume;
|
||||
counter = 0;
|
||||
}
|
||||
else {
|
||||
outputs[0][i] = outputs[1][i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
parity = !parity;
|
||||
fParameters[kParameterTime] += parity ? 1 : -1;
|
||||
}
|
||||
|
||||
private:
|
||||
float fParameters[kParameterCount];
|
||||
float period = 0.f;
|
||||
float counter = 0.f;
|
||||
float volume = 0.f;
|
||||
double sampleRate;
|
||||
bool parity = false;
|
||||
|
||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TabPlugin)
|
||||
};
|
||||
|
||||
Plugin* createPlugin()
|
||||
{
|
||||
return new TabPlugin();
|
||||
}
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
|
@ -0,0 +1,23 @@
|
|||
#ifdef YAW_USE_OTD
|
||||
// text_write.cpp
|
||||
// compile with: /clr
|
||||
using namespace System;
|
||||
using namespace System::IO;
|
||||
|
||||
int func()
|
||||
{
|
||||
String^ fileName = "textfile.txt";
|
||||
|
||||
StreamWriter^ sw = gcnew StreamWriter(fileName);
|
||||
sw->WriteLine("A text file is born!");
|
||||
sw->Write("You can use WriteLine");
|
||||
sw->WriteLine("...or just Write");
|
||||
sw->WriteLine("and do {0} output too.", "formatted");
|
||||
sw->WriteLine("You can also send non-text objects:");
|
||||
sw->WriteLine(DateTime::Now);
|
||||
sw->Close();
|
||||
Console::WriteLine("a new file ('{0}') has been written", fileName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
//Interface to supported tablet APIs.
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#ifdef YAW_USE_WINTAB
|
||||
#include <Windows.h>
|
||||
#include "MSGPACK.H"
|
||||
#include "wintab.h"
|
||||
typedef unsigned long ButtonMask;
|
||||
#endif
|
||||
|
||||
|
||||
struct Packet {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float p;
|
||||
ButtonMask buttons;
|
||||
bool operator==(const Packet& p)
|
||||
{ return
|
||||
this->x == p.x &&
|
||||
this->y == p.y &&
|
||||
this->z == p.z &&
|
||||
this->p == p.p &&
|
||||
this->buttons == p.buttons;
|
||||
};
|
||||
bool operator!=(const Packet& p) { return !(*this == p); }
|
||||
};
|
||||
|
||||
class Tablet {
|
||||
public:
|
||||
Tablet(uintptr_t handle);
|
||||
~Tablet();
|
||||
bool GetPacket( Packet &pkt );
|
||||
bool initialized;
|
||||
std::string errormsg = "";
|
||||
Packet ext = { 0 };
|
||||
|
||||
private:
|
||||
#ifdef YAW_USE_WINTAB
|
||||
void NewContext(HWND hwnd);
|
||||
HCTX hctx = NULL;
|
||||
#endif
|
||||
};
|
|
@ -0,0 +1,246 @@
|
|||
#include "ui.h"
|
||||
#ifdef DEBUG
|
||||
#include <format>
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
ButtonMappingWidget::ButtonMappingWidget(
|
||||
Widget *parent,
|
||||
float initialSize,
|
||||
float initialX,
|
||||
float initialY,
|
||||
Parameters associatedParameter,
|
||||
ButtonEventHandler::Callback *const callback) : x(initialX),
|
||||
y(initialY),
|
||||
size(initialSize),
|
||||
param(associatedParameter),
|
||||
isClicked(false),
|
||||
isPenPressed(false),
|
||||
mask(0),
|
||||
NanoSubWidget(parent),
|
||||
ButtonEventHandler(this)
|
||||
{
|
||||
setSize(Size<uint>(static_cast<uint>(size), static_cast<uint>(size)));
|
||||
setAbsolutePos((int)x, (int)y);
|
||||
ButtonEventHandler::setCallback(callback);
|
||||
}
|
||||
|
||||
void ButtonMappingWidget::onNanoDisplay()
|
||||
{
|
||||
beginPath();
|
||||
strokeColor(200, 200, 200);
|
||||
fillColor(0.5f, 0.5f, 0.5f, 0.5f * (isClicked + isPenPressed));
|
||||
roundedRect(0.f, 0.f, size, size, 0.25f * size);
|
||||
stroke();
|
||||
fill();
|
||||
closePath();
|
||||
}
|
||||
|
||||
bool ButtonMappingWidget::onMouse(const MouseEvent &ev)
|
||||
{
|
||||
isClicked = ev.press && contains(ev.pos);
|
||||
return ButtonEventHandler::mouseEvent(ev);
|
||||
}
|
||||
|
||||
static constexpr uint kInitialWidth = 800;
|
||||
static constexpr uint kInitialHeight = 600;
|
||||
|
||||
TabUI::TabUI()
|
||||
: UI(kInitialWidth, kInitialHeight),
|
||||
tab(getWindow().getNativeWindowHandle()),
|
||||
AButtonWidget(this, 75.f, kInitialWidth - 100, kInitialHeight - 100, kParameterButtonA, this),
|
||||
BButtonWidget(this, 75.f, kInitialWidth - 100, kInitialHeight - 200, kParameterButtonB, this)
|
||||
{
|
||||
|
||||
#ifdef DGL_NO_SHARED_RESOURCES
|
||||
createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
|
||||
#else
|
||||
loadSharedResources();
|
||||
#endif
|
||||
|
||||
if (!tab.initialized)
|
||||
return;
|
||||
float tabletAspectRatio = tab.ext.x ? tab.ext.y / tab.ext.x : 1.f;
|
||||
setGeometryConstraints(400, static_cast<uint>(300 * tabletAspectRatio), true, false);
|
||||
}
|
||||
|
||||
void TabUI::getTabletData()
|
||||
{
|
||||
if (!tab.initialized || !tab.GetPacket(pkt))
|
||||
return;
|
||||
if (pkt == lastPkt)
|
||||
return;
|
||||
if (pkt.x != lastPkt.x)
|
||||
setParameterValue(ktpax, pkt.x);
|
||||
if (pkt.y != lastPkt.y)
|
||||
setParameterValue(ktpay, pkt.y);
|
||||
if (pkt.z != lastPkt.z)
|
||||
setParameterValue(ktpaz, pkt.z);
|
||||
if (pkt.p != lastPkt.p)
|
||||
setParameterValue(ktpap, pkt.p);
|
||||
if (pkt.buttons != lastPkt.buttons)
|
||||
setButtonsValue(pkt.buttons);
|
||||
lastPkt = pkt;
|
||||
}
|
||||
|
||||
void TabUI::setButtonsValue(unsigned long buttonMask)
|
||||
{
|
||||
if (AButtonWidget.matchesMask(buttonMask))
|
||||
setParameterValue(kParameterButtonA, 1.f);
|
||||
else
|
||||
setParameterValue(kParameterButtonA, 0.f);
|
||||
|
||||
if (BButtonWidget.matchesMask(buttonMask))
|
||||
setParameterValue(kParameterButtonB, 1.f);
|
||||
else
|
||||
setParameterValue(kParameterButtonB, 0.f);
|
||||
}
|
||||
|
||||
void TabUI::buttonClicked(SubWidget *const widget, int)
|
||||
{
|
||||
if (widget == &AButtonWidget)
|
||||
AButtonWidget.setMask(pkt.buttons);
|
||||
if (widget == &BButtonWidget)
|
||||
BButtonWidget.setMask(pkt.buttons);
|
||||
}
|
||||
|
||||
void TabUI::parameterChanged(uint32_t index, float value)
|
||||
{
|
||||
|
||||
if (index != kParameterTime && index < kParameterCount)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case (ktpax):
|
||||
pkt.x = value;
|
||||
case (ktpay):
|
||||
pkt.y = value;
|
||||
case (ktpaz):
|
||||
pkt.z = value;
|
||||
case (ktpap):
|
||||
pkt.p = value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
getTabletData();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void TabUI::uiIdle()
|
||||
{
|
||||
getTabletData();
|
||||
repaint();
|
||||
}
|
||||
|
||||
bool TabUI::onMouse(const MouseEvent &ev)
|
||||
{
|
||||
getTabletData();
|
||||
repaint();
|
||||
return false; // Allow event to propagate.
|
||||
}
|
||||
|
||||
void TabUI::onResize(const ResizeEvent &ev)
|
||||
{
|
||||
int x = static_cast<int>(ev.size.getWidth());
|
||||
int y = static_cast<int>(ev.size.getHeight());
|
||||
AButtonWidget.setAbsolutePos(x - 100, y - 100);
|
||||
BButtonWidget.setAbsolutePos(x - 100, y - 200);
|
||||
return UI::onResize(ev);
|
||||
}
|
||||
|
||||
bool TabUI::onScroll(const ScrollEvent &ev)
|
||||
{
|
||||
double add;
|
||||
const uint x = getWidth();
|
||||
const uint y = getHeight();
|
||||
|
||||
add = (ev.delta.getY() > 0) ? 20 : -20;
|
||||
|
||||
float tabletAspectRatio;
|
||||
if (tab.initialized)
|
||||
tabletAspectRatio = tab.ext.y / tab.ext.x;
|
||||
else
|
||||
tabletAspectRatio = 1.f;
|
||||
setSize(static_cast<uint>(x + add + 0.5), static_cast<uint>(tabletAspectRatio * (x + add + 0.5)));
|
||||
return true;
|
||||
}
|
||||
|
||||
void TabUI::onNanoDisplay()
|
||||
{
|
||||
fontSize(15.0f);
|
||||
textLineHeight(1.f);
|
||||
|
||||
// Report tablet errors.
|
||||
#ifdef DEBUG
|
||||
if (!tab.initialized)
|
||||
{
|
||||
const std::string err = std::vformat("Tablet not supported:\n{}",
|
||||
std::make_format_args(tab.errormsg));
|
||||
beginPath();
|
||||
fillColor(200, 200, 200);
|
||||
textBox(0.f, 15.f, 250.f, err.c_str(), nullptr);
|
||||
closePath();
|
||||
return;
|
||||
}
|
||||
|
||||
// Numerical feedback.
|
||||
beginPath();
|
||||
fillColor(200, 200, 200);
|
||||
textBox(0.f, 15.f, 250.f,
|
||||
std::format("x: {:.3f}\ny: {:.3f}\nz: {:.3f}\np: {:.3f}\nb: {}",
|
||||
pkt.x, pkt.y, pkt.z, pkt.p, pkt.buttons)
|
||||
.c_str(),
|
||||
nullptr);
|
||||
closePath();
|
||||
#endif
|
||||
|
||||
// Pen position and pressure.
|
||||
drawCircle(pkt.x, pkt.y, pkt.z, pkt.p);
|
||||
}
|
||||
|
||||
void TabUI::drawCircle(float x, float y, float z, float p)
|
||||
{
|
||||
|
||||
static constexpr float circleRadius = 25.f;
|
||||
x *= getWidth();
|
||||
y = (1.f - y) * getHeight();
|
||||
z = 1.f - z;
|
||||
|
||||
beginPath();
|
||||
strokeColor(1.f, 1.f, 1.f, 0.5f);
|
||||
moveTo(x - z * circleRadius, y);
|
||||
lineTo(x + z * circleRadius, y);
|
||||
stroke();
|
||||
closePath();
|
||||
|
||||
beginPath();
|
||||
strokeColor(1.f, 1.f, 1.f, 0.5f);
|
||||
moveTo(x, y - z * circleRadius);
|
||||
lineTo(x, y + z * circleRadius);
|
||||
stroke();
|
||||
closePath();
|
||||
|
||||
beginPath();
|
||||
fillColor(1.f, 1.f, 1.f, p);
|
||||
strokeColor(255, 255, 255, 255);
|
||||
circle(x, y, circleRadius);
|
||||
fill();
|
||||
stroke();
|
||||
closePath();
|
||||
|
||||
beginPath();
|
||||
strokeColor(1.f, 1.f, 1.f, z);
|
||||
circle(x, y, z * circleRadius);
|
||||
stroke();
|
||||
closePath();
|
||||
}
|
||||
|
||||
UI *createUI()
|
||||
{
|
||||
return new TabUI();
|
||||
}
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
|
@ -0,0 +1,69 @@
|
|||
#include "DistrhoUI.hpp"
|
||||
#include "tablet.h"
|
||||
#ifdef DEBUG
|
||||
#include <format>
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
class ButtonMappingWidget : public NanoSubWidget,
|
||||
public ButtonEventHandler
|
||||
{
|
||||
public:
|
||||
explicit ButtonMappingWidget(
|
||||
Widget *parent,
|
||||
float initialSize,
|
||||
float initialX,
|
||||
float initialY,
|
||||
Parameters associatedParameter,
|
||||
ButtonEventHandler::Callback *const callback);
|
||||
void onNanoDisplay() override;
|
||||
bool onMouse(const MouseEvent &ev) override;
|
||||
void setMask(const ButtonMask m) { mask = m; };
|
||||
bool matchesMask(const ButtonMask m) { return isPenPressed = (m && mask == m); };
|
||||
|
||||
bool isClicked;
|
||||
bool isPenPressed;
|
||||
|
||||
private:
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float size = 0;
|
||||
const Parameters param;
|
||||
ButtonMask mask;
|
||||
};
|
||||
|
||||
class TabUI : public UI,
|
||||
public ButtonEventHandler::Callback
|
||||
{
|
||||
public:
|
||||
explicit TabUI();
|
||||
|
||||
void buttonClicked(SubWidget *const widget, int) override;
|
||||
void parameterChanged(uint32_t index, float value) override;
|
||||
|
||||
void uiIdle() override;
|
||||
bool onMouse(const MouseEvent &ev) override;
|
||||
bool onScroll(const ScrollEvent &ev) override;
|
||||
void onResize(const ResizeEvent &ev) override;
|
||||
void onNanoDisplay() override;
|
||||
|
||||
private:
|
||||
void getTabletData();
|
||||
void setButtonsValue(unsigned long buttonMask);
|
||||
void drawCircle(float x, float y, float z, float p);
|
||||
|
||||
// Tablet context handler
|
||||
Tablet tab;
|
||||
Packet pkt = {0};
|
||||
Packet lastPkt = {0};
|
||||
|
||||
// Button mapping widgets
|
||||
ButtonMappingWidget AButtonWidget;
|
||||
ButtonMappingWidget BButtonWidget;
|
||||
|
||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TabUI)
|
||||
};
|
||||
|
||||
END_NAMESPACE_DISTRHO
|
|
@ -0,0 +1,81 @@
|
|||
#ifdef YAW_USE_WINTAB
|
||||
#include "tablet.h"
|
||||
#define PACKETDATA (PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE)
|
||||
//#define PACKETMODE
|
||||
#include "pktdef.h"
|
||||
#include "wtutil.h"
|
||||
|
||||
Tablet::Tablet(uintptr_t handle)
|
||||
{
|
||||
HWND hwnd = reinterpret_cast<HWND>(handle);
|
||||
if (!hwnd) { return; }
|
||||
|
||||
if (!LoadWintab() || !gpWTInfoA(0, 0, NULL)) {
|
||||
errormsg = "Wintab not installed.";
|
||||
return;
|
||||
}
|
||||
|
||||
NewContext(hwnd);
|
||||
}
|
||||
|
||||
Tablet::~Tablet() {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
UnloadWintab();
|
||||
}
|
||||
|
||||
bool Tablet::GetPacket( Packet& packet ) {
|
||||
//Serial number of newest packet.
|
||||
UINT oldest, newest;
|
||||
//This function returns false when it fails
|
||||
//which may happen with a full or empty queue.
|
||||
if (!gpWTQueuePacketsEx(hctx, &oldest, &newest)) {
|
||||
//Queue may be full, flush it all just in case.
|
||||
gpWTPacketsGet(hctx, gpWTQueueSizeGet(hctx), nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Store newest packet in pkt, flush older packets.
|
||||
PACKET pkt;
|
||||
bool newData = gpWTPacket(hctx, newest, &pkt);
|
||||
if (!newData) return false;
|
||||
packet.x = static_cast<float>(pkt.pkX) / ext.x;
|
||||
packet.y = static_cast<float>(pkt.pkY) / ext.y;
|
||||
packet.z = static_cast<float>(pkt.pkZ) / ext.z;
|
||||
packet.p = static_cast<float>(pkt.pkNormalPressure) / ext.p;
|
||||
packet.buttons = pkt.pkButtons;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tablet::NewContext(HWND hwnd) {
|
||||
if (hctx) { gpWTClose(hctx); }
|
||||
LOGCONTEXT ctx = {};
|
||||
AXIS TabletX = { 0 };
|
||||
AXIS TabletY = { 0 };
|
||||
AXIS TabletZ = { 0 };
|
||||
AXIS TabletPressure = { 0 };
|
||||
gpWTInfoA(WTI_DEFCONTEXT, 0, &ctx);
|
||||
ctx.lcOptions |= CXO_MESSAGES; //TODO: checker çela
|
||||
ctx.lcPktData = PACKETDATA;
|
||||
ctx.lcPktMode = 0;
|
||||
|
||||
//Tablet extents.
|
||||
gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);
|
||||
gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &TabletPressure);
|
||||
|
||||
ext.x = static_cast<float>(TabletX.axMax);
|
||||
ext.y = static_cast<float>(TabletY.axMax);
|
||||
ext.z = static_cast<float>(TabletZ.axMax);
|
||||
ext.p = static_cast<float>(TabletPressure.axMax);
|
||||
|
||||
hctx = gpWTOpenA(hwnd, &ctx, TRUE);
|
||||
|
||||
if (!hctx)
|
||||
{
|
||||
errormsg = "Could not open Wintab context.";
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,143 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESCRIPTION
|
||||
// Some general-purpose functions for the WinTab demos.
|
||||
//
|
||||
// COPYRIGHT
|
||||
// Copyright (c) 2014-2020 Wacom Co., Ltd.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <string>
|
||||
#include "wtutil.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
HINSTANCE ghWintab = nullptr;
|
||||
|
||||
WTINFOA gpWTInfoA = nullptr;
|
||||
WTOPENA gpWTOpenA = nullptr;
|
||||
WTGETA gpWTGetA = nullptr;
|
||||
WTSETA gpWTSetA = nullptr;
|
||||
WTCLOSE gpWTClose = nullptr;
|
||||
WTPACKET gpWTPacket = nullptr;
|
||||
WTENABLE gpWTEnable = nullptr;
|
||||
WTOVERLAP gpWTOverlap = nullptr;
|
||||
WTSAVE gpWTSave = nullptr;
|
||||
WTCONFIG gpWTConfig = nullptr;
|
||||
WTRESTORE gpWTRestore = nullptr;
|
||||
WTEXTSET gpWTExtSet = nullptr;
|
||||
WTEXTGET gpWTExtGet = nullptr;
|
||||
WTQUEUESIZESET gpWTQueueSizeSet = nullptr;
|
||||
WTDATAPEEK gpWTDataPeek = nullptr;
|
||||
WTPACKETSGET gpWTPacketsGet = nullptr;
|
||||
WTMGROPEN gpWTMgrOpen = nullptr;
|
||||
WTMGRCLOSE gpWTMgrClose = nullptr;
|
||||
WTMGRDEFCONTEXT gpWTMgrDefContext = nullptr;
|
||||
WTMGRDEFCONTEXTEX gpWTMgrDefContextEx = nullptr;
|
||||
|
||||
// TODO - add more wintab32 function pointers as needed
|
||||
WTQPACKETSEX gpWTQueuePacketsEx = nullptr;
|
||||
WTQSIZEGET gpWTQueueSizeGet = nullptr;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose
|
||||
// Find wintab32.dll and load it.
|
||||
// Find the exported functions we need from it.
|
||||
//
|
||||
// Returns
|
||||
// TRUE on success.
|
||||
// FALSE on failure.
|
||||
//
|
||||
BOOL LoadWintab(void)
|
||||
{
|
||||
// load the wintab32 dll
|
||||
ghWintab = LoadLibraryA("Wintab32.dll");
|
||||
|
||||
if (!ghWintab)
|
||||
{
|
||||
const DWORD err = GetLastError();
|
||||
ShowError("Could not load Wintab32.dll: " + std::to_string(err));
|
||||
return FALSE;
|
||||
}
|
||||
// Explicitly find the exported Wintab functions in which we are interested.
|
||||
// We are using the ASCII, not unicode versions (where applicable).
|
||||
gpWTOpenA = (WTOPENA)GetProcAddress(ghWintab, "WTOpenA");
|
||||
gpWTInfoA = (WTINFOA)GetProcAddress(ghWintab, "WTInfoA");
|
||||
gpWTGetA = (WTGETA)GetProcAddress(ghWintab, "WTGetA");
|
||||
gpWTSetA = (WTSETA)GetProcAddress(ghWintab, "WTSetA");
|
||||
gpWTPacket = (WTPACKET)GetProcAddress(ghWintab, "WTPacket");
|
||||
gpWTClose = (WTCLOSE)GetProcAddress(ghWintab, "WTClose");
|
||||
gpWTEnable = (WTENABLE)GetProcAddress(ghWintab, "WTEnable");
|
||||
gpWTOverlap = (WTOVERLAP)GetProcAddress(ghWintab, "WTOverlap");
|
||||
gpWTSave = (WTSAVE)GetProcAddress(ghWintab, "WTSave");
|
||||
gpWTConfig = (WTCONFIG)GetProcAddress(ghWintab, "WTConfig");
|
||||
gpWTRestore = (WTRESTORE)GetProcAddress(ghWintab, "WTRestore");
|
||||
gpWTExtSet = (WTEXTSET)GetProcAddress(ghWintab, "WTExtSet");
|
||||
gpWTExtGet = (WTEXTGET)GetProcAddress(ghWintab, "WTExtGet");
|
||||
gpWTQueueSizeSet = (WTQUEUESIZESET)GetProcAddress(ghWintab, "WTQueueSizeSet");
|
||||
gpWTDataPeek = (WTDATAPEEK)GetProcAddress(ghWintab, "WTDataPeek");
|
||||
gpWTPacketsGet = (WTPACKETSGET)GetProcAddress(ghWintab, "WTPacketsGet");
|
||||
gpWTMgrOpen = (WTMGROPEN)GetProcAddress(ghWintab, "WTMgrOpen");
|
||||
gpWTMgrClose = (WTMGRCLOSE)GetProcAddress(ghWintab, "WTMgrClose");
|
||||
gpWTMgrDefContext = (WTMGRDEFCONTEXT)GetProcAddress(ghWintab, "WTMgrDefContext");
|
||||
gpWTMgrDefContextEx = (WTMGRDEFCONTEXTEX)GetProcAddress(ghWintab, "WTMgrDefContextEx");
|
||||
gpWTQueuePacketsEx = (WTQPACKETSEX)GetProcAddress(ghWintab, "WTQueuePacketsEx");
|
||||
gpWTQueueSizeGet = (WTQSIZEGET)GetProcAddress(ghWintab, "WTQueueSizeGet");
|
||||
|
||||
// TODO - don't forget to NULL out pointers in UnloadWintab().
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose
|
||||
// Uninitializes use of wintab32.dll
|
||||
//
|
||||
// Returns
|
||||
// Nothing.
|
||||
//
|
||||
void UnloadWintab(void)
|
||||
{
|
||||
if (ghWintab)
|
||||
{
|
||||
FreeLibrary(ghWintab);
|
||||
ghWintab = nullptr;
|
||||
}
|
||||
gpWTOpenA = nullptr;
|
||||
gpWTClose = nullptr;
|
||||
gpWTInfoA = nullptr;
|
||||
gpWTPacket = nullptr;
|
||||
gpWTEnable = nullptr;
|
||||
gpWTOverlap = nullptr;
|
||||
gpWTSave = nullptr;
|
||||
gpWTConfig = nullptr;
|
||||
gpWTGetA = nullptr;
|
||||
gpWTSetA = nullptr;
|
||||
gpWTRestore = nullptr;
|
||||
gpWTExtSet = nullptr;
|
||||
gpWTExtGet = nullptr;
|
||||
gpWTQueueSizeSet = nullptr;
|
||||
gpWTDataPeek = nullptr;
|
||||
gpWTPacketsGet = nullptr;
|
||||
gpWTMgrOpen = nullptr;
|
||||
gpWTMgrClose = nullptr;
|
||||
gpWTMgrDefContext = nullptr;
|
||||
gpWTMgrDefContextEx = nullptr;
|
||||
gpWTQueuePacketsEx = nullptr;
|
||||
gpWTQueueSizeGet = nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Purpose
|
||||
// Display error to user.
|
||||
//
|
||||
void ShowError(const std::string &pszErrorMessage_I)
|
||||
{
|
||||
//TODO: post error message to buffer in Tablet class
|
||||
//which in turn can post to TabUI
|
||||
//MessageBoxA(NULL, pszErrorMessage_I.c_str(), "Error", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESCRIPTION
|
||||
// Defines for the general-purpose functions for the WinTab demos.
|
||||
//
|
||||
// COPYRIGHT
|
||||
// Copyright (c) 2014-2020 Wacom Co., Ltd.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <wintab.h> // NOTE: get from wactab header package
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Ignore warnings about using unsafe string functions.
|
||||
#pragma warning( disable : 4996 )
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function pointers to Wintab functions exported from wintab32.dll.
|
||||
using WTINFOA = UINT (API*)(UINT, UINT, LPVOID);
|
||||
using WTOPENA = HCTX (API*)(HWND, LPLOGCONTEXTA, BOOL);
|
||||
using WTGETA = BOOL (API*)(HCTX, LPLOGCONTEXT);
|
||||
using WTSETA = BOOL (API*)(HCTX, LPLOGCONTEXT);
|
||||
using WTCLOSE = BOOL (API*)(HCTX);
|
||||
using WTENABLE = BOOL (API*)(HCTX, BOOL);
|
||||
using WTPACKET = BOOL (API*)(HCTX, UINT, LPVOID);
|
||||
using WTOVERLAP = BOOL (API*)(HCTX, BOOL);
|
||||
using WTSAVE = BOOL (API*)(HCTX, LPVOID);
|
||||
using WTCONFIG = BOOL (API*)(HCTX, HWND);
|
||||
using WTRESTORE = HCTX (API*)(HWND, LPVOID, BOOL);
|
||||
using WTEXTSET = BOOL (API*)(HCTX, UINT, LPVOID);
|
||||
using WTEXTGET = BOOL (API*)(HCTX, UINT, LPVOID);
|
||||
using WTQUEUESIZESET = BOOL (API*)(HCTX, int);
|
||||
using WTDATAPEEK = int (API*)(HCTX, UINT, UINT, int, LPVOID, LPINT);
|
||||
using WTPACKETSGET = int (API*)(HCTX, int, LPVOID);
|
||||
using WTMGROPEN = HMGR (API*)(HWND, UINT);
|
||||
using WTMGRCLOSE = BOOL (API*)(HMGR);
|
||||
using WTMGRDEFCONTEXT = HCTX (API*)(HMGR, BOOL);
|
||||
using WTMGRDEFCONTEXTEX = HCTX (API*)(HMGR, UINT, BOOL);
|
||||
|
||||
// TODO - add more wintab32 function defs as needed
|
||||
using WTQPACKETSEX = BOOL(API*)(HCTX, UINT FAR*, UINT FAR*);
|
||||
using WTQSIZEGET = int (API*)(HCTX);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Loaded Wintab32 API functions.
|
||||
extern HINSTANCE ghWintab;
|
||||
|
||||
extern WTINFOA gpWTInfoA;
|
||||
extern WTOPENA gpWTOpenA;
|
||||
extern WTGETA gpWTGetA;
|
||||
extern WTSETA gpWTSetA;
|
||||
extern WTCLOSE gpWTClose;
|
||||
extern WTPACKET gpWTPacket;
|
||||
extern WTENABLE gpWTEnable;
|
||||
extern WTOVERLAP gpWTOverlap;
|
||||
extern WTSAVE gpWTSave;
|
||||
extern WTCONFIG gpWTConfig;
|
||||
extern WTRESTORE gpWTRestore;
|
||||
extern WTEXTSET gpWTExtSet;
|
||||
extern WTEXTGET gpWTExtGet;
|
||||
extern WTQUEUESIZESET gpWTQueueSizeSet;
|
||||
extern WTDATAPEEK gpWTDataPeek;
|
||||
extern WTPACKETSGET gpWTPacketsGet;
|
||||
extern WTMGROPEN gpWTMgrOpen;
|
||||
extern WTMGRCLOSE gpWTMgrClose;
|
||||
extern WTMGRDEFCONTEXT gpWTMgrDefContext;
|
||||
extern WTMGRDEFCONTEXTEX gpWTMgrDefContextEx;
|
||||
|
||||
// TODO - add more wintab32 function pointers as needed
|
||||
extern WTQPACKETSEX gpWTQueuePacketsEx;
|
||||
extern WTQSIZEGET gpWTQueueSizeGet;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL LoadWintab(void);
|
||||
void UnloadWintab(void);
|
||||
|
||||
void ShowError(const std::string &pszErrorMessage_I);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue