Browse Source

Update nanovg. Refactor window. Add Timer to dsp.

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
117553a6c9
6 changed files with 148 additions and 145 deletions
  1. +1
    -1
      dep/nanovg
  2. +18
    -0
      include/dsp/digital.hpp
  3. +8
    -0
      include/engine/Param.hpp
  4. +4
    -0
      include/window.hpp
  5. +2
    -0
      src/main.cpp
  6. +115
    -144
      src/window.cpp

+ 1
- 1
dep/nanovg

@@ -1 +1 @@
Subproject commit 98e551351d020087b01ae0b1d3d2d1593e3ad01f
Subproject commit f4069e6a1ad5da430fb0a9c57476d5ddc2ff89b2

+ 18
- 0
include/dsp/digital.hpp View File

@@ -103,5 +103,23 @@ struct PulseGenerator {
};


struct Timer {
float time;

Timer() {
reset();
}

void reset() {
time = 0.f;
}

float process(float deltaTime) {
time += deltaTime;
return time;
}
};


} // namespace dsp
} // namespace rack

+ 8
- 0
include/engine/Param.hpp View File

@@ -22,11 +22,19 @@ struct Param {
float maxValue = 1.f;
float defaultValue = 0.f;

/** The name of the parameter in sentence capitalization
e.g. "Frequency", "Pulse width", "Alternative mode"
*/
std::string label;
/** The numerical unit of measurement
Use a space before non-abbreviations to separate the numerical value.
e.g. " semitones", "Hz", "%", "V"
*/
std::string unit;
/** Set to 0 for linear, nonzero for exponential */
float displayBase = 0.f;
float displayMultiplier = 1.f;
/** An optional one-sentence description of the parameter */
std::string description;
ParamQuantityFactory *paramQuantityFactory = NULL;



+ 4
- 0
include/window.hpp View File

@@ -96,4 +96,8 @@ struct Window {
};


void windowInit();
void windowDestroy();


} // namespace rack

+ 2
- 0
src/main.cpp View File

@@ -78,6 +78,7 @@ int main(int argc, char *argv[]) {
gamepad::init();
ui::init();
plugin::init(devMode);
windowInit();
INFO("Initialized environment");

// Initialize app
@@ -120,6 +121,7 @@ int main(int argc, char *argv[]) {
INFO("Cleaned up app");

// Destroy environment
windowDestroy();
plugin::destroy();
ui::destroy();
bridgeDestroy();


+ 115
- 144
src/window.cpp View File

@@ -35,12 +35,74 @@
namespace rack {


struct MouseButtonArguments {
GLFWwindow *win;
int button;
int action;
int mods;
};
static std::map<std::string, std::weak_ptr<Font>> fontCache;
static std::map<std::string, std::weak_ptr<Image>> imageCache;
static std::map<std::string, std::weak_ptr<SVG>> svgCache;


Font::Font(const std::string &filename) {
handle = nvgCreateFont(app()->window->vg, filename.c_str(), filename.c_str());
if (handle >= 0) {
INFO("Loaded font %s", filename.c_str());
}
else {
WARN("Failed to load font %s", filename.c_str());
}
}

Font::~Font() {
// There is no NanoVG deleteFont() function yet, so do nothing
}

std::shared_ptr<Font> Font::load(const std::string &filename) {
auto sp = fontCache[filename].lock();
if (!sp)
fontCache[filename] = sp = std::make_shared<Font>(filename);
return sp;
}

Image::Image(const std::string &filename) {
handle = nvgCreateImage(app()->window->vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (handle > 0) {
INFO("Loaded image %s", filename.c_str());
}
else {
WARN("Failed to load image %s", filename.c_str());
}
}

Image::~Image() {
// TODO What if handle is invalid?
nvgDeleteImage(app()->window->vg, handle);
}

std::shared_ptr<Image> Image::load(const std::string &filename) {
auto sp = imageCache[filename].lock();
if (!sp)
imageCache[filename] = sp = std::make_shared<Image>(filename);
return sp;
}

SVG::SVG(const std::string &filename) {
handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI);
if (handle) {
INFO("Loaded SVG %s", filename.c_str());
}
else {
WARN("Failed to load SVG %s", filename.c_str());
}
}

SVG::~SVG() {
nsvgDelete(handle);
}

std::shared_ptr<SVG> SVG::load(const std::string &filename) {
auto sp = svgCache[filename].lock();
if (!sp)
svgCache[filename] = sp = std::make_shared<SVG>(filename);
return sp;
}


struct Window::Internal {
@@ -50,8 +112,6 @@ struct Window::Internal {
int lastWindowY = 0;
int lastWindowWidth = 0;
int lastWindowHeight = 0;

std::queue<MouseButtonArguments> mouseButtonQueue;
};


@@ -74,21 +134,6 @@ static void mouseButtonCallback(GLFWwindow *win, int button, int action, int mod
app()->event->handleButton(window->mousePos, button, action, mods);
}

static void Window_mouseButtonStickyPop(Window *window) {
if (!window->internal->mouseButtonQueue.empty()) {
MouseButtonArguments args = window->internal->mouseButtonQueue.front();
window->internal->mouseButtonQueue.pop();
mouseButtonCallback(args.win, args.button, args.action, args.mods);
}
}

static void mouseButtonStickyCallback(GLFWwindow *win, int button, int action, int mods) {
Window *window = (Window*) glfwGetWindowUserPointer(win);
// Defer multiple clicks per frame to future frames
MouseButtonArguments args = {win, button, action, mods};
window->internal->mouseButtonQueue.push(args);
}

static void cursorPosCallback(GLFWwindow *win, double xpos, double ypos) {
Window *window = (Window*) glfwGetWindowUserPointer(win);
math::Vec mousePos = math::Vec(xpos, ypos).div(window->pixelRatio / window->windowRatio).round();
@@ -168,21 +213,12 @@ static void errorCallback(int error, const char *description) {

Window::Window() {
internal = new Internal;

int err;

// Set up GLFW
glfwSetErrorCallback(errorCallback);
err = glfwInit();
if (err != GLFW_TRUE) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize GLFW.");
exit(1);
}

#if defined NANOVG_GL2
#if NANOVG_GL2
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#elif defined NANOVG_GL3
#elif NANOVG_GL3
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
@@ -191,7 +227,7 @@ Window::Window() {
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
internal->lastWindowTitle = "";
win = glfwCreateWindow(640, 480, internal->lastWindowTitle.c_str(), NULL, NULL);
win = glfwCreateWindow(800, 600, internal->lastWindowTitle.c_str(), NULL, NULL);

if (!win) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Cannot open window with OpenGL 2.0 renderer. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed.");
@@ -205,7 +241,7 @@ Window::Window() {
glfwSwapInterval(1);

glfwSetWindowSizeCallback(win, windowSizeCallback);
glfwSetMouseButtonCallback(win, mouseButtonStickyCallback);
glfwSetMouseButtonCallback(win, mouseButtonCallback);
// Call this ourselves, but on every frame instead of only when the mouse moves
// glfwSetCursorPosCallback(win, cursorPosCallback);
glfwSetCursorEnterCallback(win, cursorEnterCallback);
@@ -225,7 +261,7 @@ Window::Window() {
// GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
glGetError();

glfwSetWindowSizeLimits(win, 640, 480, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwSetWindowSizeLimits(win, 800, 600, GLFW_DONT_CARE, GLFW_DONT_CARE);

// Set up NanoVG
int nvgFlags = NVG_ANTIALIAS;
@@ -266,30 +302,9 @@ Window::~Window() {
#endif

glfwDestroyWindow(win);
glfwTerminate();
delete internal;
}

static void Window_renderGui(Window *window) {
int width, height;
glfwGetFramebufferSize(window->win, &width, &height);

bndSetFont(window->uiFont->handle);

// Update and render
nvgBeginFrame(window->vg, width, height, window->pixelRatio);

nvgReset(window->vg);
nvgScale(window->vg, window->pixelRatio, window->pixelRatio);
app()->event->rootWidget->draw(window->vg);

glViewport(0, 0, width, height);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
nvgEndFrame(window->vg);
glfwSwapBuffers(window->win);
}

void Window::run() {
uiFont = Font::load(asset::system("res/fonts/DejaVuSans.ttf"));

@@ -300,12 +315,12 @@ void Window::run() {

// Poll events
glfwPollEvents();
// Call cursorPosCallback every frame, not just when the mouse moves
{
double xpos, ypos;
glfwGetCursorPos(win, &xpos, &ypos);
cursorPosCallback(win, xpos, ypos);
}
Window_mouseButtonStickyPop(this);
gamepad::step();

// Set window title
@@ -322,23 +337,26 @@ void Window::run() {
internal->lastWindowTitle = windowTitle;
}

bndSetFont(uiFont->handle);

// Get desired scaling
float newPixelRatio;
glfwGetWindowContentScale(win, &newPixelRatio, NULL);
newPixelRatio = std::round(newPixelRatio);
if (newPixelRatio != pixelRatio) {
float pixelRatio;
glfwGetWindowContentScale(win, &pixelRatio, NULL);
pixelRatio = std::round(pixelRatio);
if (pixelRatio != this->pixelRatio) {
app()->event->handleZoom();
pixelRatio = newPixelRatio;
this->pixelRatio = pixelRatio;
}

// Get framebuffer/window ratio
int width, height;
glfwGetFramebufferSize(win, &width, &height);
int windowWidth, windowHeight;
glfwGetWindowSize(win, &windowWidth, &windowHeight);
windowRatio = (float)width / windowWidth;
int fbWidth, fbHeight;
glfwGetFramebufferSize(win, &fbWidth, &fbHeight);
int winWidth, winHeight;
glfwGetWindowSize(win, &winWidth, &winHeight);
windowRatio = (float)fbWidth / winWidth;

app()->event->rootWidget->box.size = math::Vec(width, height).div(pixelRatio);
// Resize scene
app()->event->rootWidget->box.size = math::Vec(fbWidth, fbHeight).div(pixelRatio);

// Step scene
app()->event->rootWidget->step();
@@ -346,13 +364,28 @@ void Window::run() {
// Render
bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED);
if (visible) {
Window_renderGui(this);
// In case glfwPollEvents() worked with another OpenGL context
glfwMakeContextCurrent(win);
glViewport(0, 0, fbWidth, fbHeight);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// Update and render
nvgBeginFrame(vg, winWidth, winHeight, pixelRatio);

// nvgReset(vg);
// nvgScale(vg, pixelRatio, pixelRatio);

app()->event->rootWidget->draw(vg);

nvgEndFrame(vg);
glfwSwapBuffers(win);
}

// Limit framerate manually if vsync isn't working
double endTime = glfwGetTime();
double frameTime = endTime - startTime;
double minTime = 1.0 / 90.0;
double minTime = 1 / 120.0;
if (frameTime < minTime) {
std::this_thread::sleep_for(std::chrono::duration<double>(minTime - frameTime));
}
@@ -441,84 +474,22 @@ bool Window::isFullScreen() {
}


////////////////////
// resources
////////////////////

Font::Font(const std::string &filename) {
handle = nvgCreateFont(app()->window->vg, filename.c_str(), filename.c_str());
if (handle >= 0) {
INFO("Loaded font %s", filename.c_str());
}
else {
WARN("Failed to load font %s", filename.c_str());
}
}

Font::~Font() {
// There is no NanoVG deleteFont() function yet, so do nothing
}

std::shared_ptr<Font> Font::load(const std::string &filename) {
static std::map<std::string, std::weak_ptr<Font>> cache;
auto sp = cache[filename].lock();
if (!sp)
cache[filename] = sp = std::make_shared<Font>(filename);
return sp;
}

////////////////////
// Image
////////////////////

Image::Image(const std::string &filename) {
handle = nvgCreateImage(app()->window->vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY);
if (handle > 0) {
INFO("Loaded image %s", filename.c_str());
}
else {
WARN("Failed to load image %s", filename.c_str());
}
}

Image::~Image() {
// TODO What if handle is invalid?
nvgDeleteImage(app()->window->vg, handle);
}

std::shared_ptr<Image> Image::load(const std::string &filename) {
static std::map<std::string, std::weak_ptr<Image>> cache;
auto sp = cache[filename].lock();
if (!sp)
cache[filename] = sp = std::make_shared<Image>(filename);
return sp;
}

////////////////////
// SVG
////////////////////
void windowInit() {
int err;

SVG::SVG(const std::string &filename) {
handle = nsvgParseFromFile(filename.c_str(), "px", SVG_DPI);
if (handle) {
INFO("Loaded SVG %s", filename.c_str());
}
else {
WARN("Failed to load SVG %s", filename.c_str());
// Set up GLFW
glfwSetErrorCallback(errorCallback);
err = glfwInit();
if (err != GLFW_TRUE) {
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Could not initialize GLFW.");
exit(1);
}
}

SVG::~SVG() {
nsvgDelete(handle);
void windowDestroy() {
glfwTerminate();
}

std::shared_ptr<SVG> SVG::load(const std::string &filename) {
static std::map<std::string, std::weak_ptr<SVG>> cache;
auto sp = cache[filename].lock();
if (!sp)
cache[filename] = sp = std::make_shared<SVG>(filename);
return sp;
}


} // namespace rack

Loading…
Cancel
Save