aboutsummaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp605
1 files changed, 583 insertions, 22 deletions
diff --git a/main.cpp b/main.cpp
index 5f76a74..17c6597 100644
--- a/main.cpp
+++ b/main.cpp
@@ -8,12 +8,34 @@
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
+#undef GLAD_GL_IMPLEMENTATION
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_SQRT sqrt
+#define NK_SIN sinf
+#define NK_COS cosf
+// #define NK_STRTOD strtod
+// #define NK_DTOA dtoa
#define NK_IMPLEMENTATION
#include "nuklear.h"
+// device (NK) implementation details
+static const int MAX_VERTEX_MEMORY = 512 * 1024;
+static const int MAX_ELEMENT_MEMORY = 128 * 1024;
+
+#ifdef __APPLE__
+ #define NK_SHADER_VERSION "#version 150\n"
+#else
+ #define NK_SHADER_VERSION "#version 300 es\n"
+#endif
+
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
@@ -36,6 +58,275 @@ static const int RNG_SEED = 123;
static const int WINDOW_WIDTH = 1200;
static const int WINDOW_HEIGHT = 800;
+struct media {
+ struct nk_font *font_14;
+ struct nk_font *font_18;
+ struct nk_font *font_20;
+ struct nk_font *font_22;
+
+ struct nk_image unchecked;
+ struct nk_image checked;
+ struct nk_image rocket;
+ struct nk_image cloud;
+ struct nk_image pen;
+ struct nk_image play;
+ struct nk_image pause;
+ struct nk_image stop;
+ struct nk_image prev;
+ struct nk_image next;
+ struct nk_image tools;
+ struct nk_image dir;
+ struct nk_image copy;
+ struct nk_image convert;
+ struct nk_image del;
+ struct nk_image edit;
+ struct nk_image images[9];
+ struct nk_image menu[6];
+};
+struct nk_glfw_vertex {
+ float position[2];
+ float uv[2];
+ nk_byte col[4];
+};
+
+struct device {
+ struct nk_buffer cmds;
+ struct nk_draw_null_texture tex_null;
+ GLuint vbo, vao, ebo;
+ GLuint prog;
+ GLuint vert_shdr;
+ GLuint frag_shdr;
+ GLint attrib_pos;
+ GLint attrib_uv;
+ GLint attrib_col;
+ GLint uniform_tex;
+ GLint uniform_proj;
+ GLuint font_tex;
+};
+
+static void
+ui_header(struct nk_context *ctx, struct media *media, const char *title)
+{
+ nk_style_set_font(ctx, &media->font_18->handle);
+ nk_layout_row_dynamic(ctx, 20, 1);
+ nk_label(ctx, title, NK_TEXT_LEFT);
+}
+
+static void
+ui_widget(struct nk_context *ctx, struct media *media, float height)
+{
+ static const float ratio[] = {0.15f, 0.85f};
+ nk_style_set_font(ctx, &media->font_22->handle);
+ nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);
+ nk_spacing(ctx, 1);
+}
+
+static void
+device_init(struct device *dev)
+{
+ GLint status;
+ static const GLchar *vertex_shader =
+ NK_SHADER_VERSION
+ "uniform mat4 ProjMtx;\n"
+ "in vec2 Position;\n"
+ "in vec2 TexCoord;\n"
+ "in vec4 Color;\n"
+ "out vec2 Frag_UV;\n"
+ "out vec4 Frag_Color;\n"
+ "void main() {\n"
+ " Frag_UV = TexCoord;\n"
+ " Frag_Color = Color;\n"
+ " gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\n"
+ "}\n";
+ static const GLchar *fragment_shader =
+ NK_SHADER_VERSION
+ "precision mediump float;\n"
+ "uniform sampler2D Texture;\n"
+ "in vec2 Frag_UV;\n"
+ "in vec4 Frag_Color;\n"
+ "out vec4 Out_Color;\n"
+ "void main(){\n"
+ " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
+ "}\n";
+
+ nk_buffer_init_default(&dev->cmds);
+ dev->prog = glCreateProgram();
+ dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);
+ dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);
+ glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);
+ glCompileShader(dev->vert_shdr);
+ glCompileShader(dev->frag_shdr);
+ glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);
+ assert(status == GL_TRUE);
+ glAttachShader(dev->prog, dev->vert_shdr);
+ glAttachShader(dev->prog, dev->frag_shdr);
+ glLinkProgram(dev->prog);
+ glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);
+ assert(status == GL_TRUE);
+
+ dev->uniform_tex = glGetUniformLocation(dev->prog, "Texture");
+ dev->uniform_proj = glGetUniformLocation(dev->prog, "ProjMtx");
+ dev->attrib_pos = glGetAttribLocation(dev->prog, "Position");
+ dev->attrib_uv = glGetAttribLocation(dev->prog, "TexCoord");
+ dev->attrib_col = glGetAttribLocation(dev->prog, "Color");
+
+ {
+ /* buffer setup */
+ GLsizei vs = sizeof(struct nk_glfw_vertex);
+ size_t vp = offsetof(struct nk_glfw_vertex, position);
+ size_t vt = offsetof(struct nk_glfw_vertex, uv);
+ size_t vc = offsetof(struct nk_glfw_vertex, col);
+
+ glGenBuffers(1, &dev->vbo);
+ glGenBuffers(1, &dev->ebo);
+ glGenVertexArrays(1, &dev->vao);
+
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glEnableVertexAttribArray((GLuint)dev->attrib_pos);
+ glEnableVertexAttribArray((GLuint)dev->attrib_uv);
+ glEnableVertexAttribArray((GLuint)dev->attrib_col);
+
+ glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);
+ glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);
+ glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+static void
+device_upload_atlas(struct device *dev, const void *image, int width, int height)
+{
+ glGenTextures(1, &dev->font_tex);
+ glBindTexture(GL_TEXTURE_2D, dev->font_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, image);
+}
+
+static void
+device_shutdown(struct device *dev)
+{
+ glDetachShader(dev->prog, dev->vert_shdr);
+ glDetachShader(dev->prog, dev->frag_shdr);
+ glDeleteShader(dev->vert_shdr);
+ glDeleteShader(dev->frag_shdr);
+ glDeleteProgram(dev->prog);
+ glDeleteTextures(1, &dev->font_tex);
+ glDeleteBuffers(1, &dev->vbo);
+ glDeleteBuffers(1, &dev->ebo);
+ nk_buffer_free(&dev->cmds);
+}
+
+static void
+device_draw(struct device *dev, struct nk_context *ctx, int width, int height,
+ struct nk_vec2 scale, enum nk_anti_aliasing AA)
+{
+ GLfloat ortho[4][4] = {
+ {2.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f,-2.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f,-1.0f, 0.0f},
+ {-1.0f,1.0f, 0.0f, 1.0f},
+ };
+ ortho[0][0] /= (GLfloat)width;
+ ortho[1][1] /= (GLfloat)height;
+
+ /* setup global state */
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_SCISSOR_TEST);
+ glActiveTexture(GL_TEXTURE0);
+
+ /* setup program */
+ glUseProgram(dev->prog);
+ glUniform1i(dev->uniform_tex, 0);
+ glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);
+ {
+ /* convert from command queue into draw list and draw to screen */
+ const struct nk_draw_command *cmd;
+ void *vertices, *elements;
+ const nk_draw_index *offset = NULL;
+
+ /* allocate vertex and element buffer */
+ glBindVertexArray(dev->vao);
+ glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);
+
+ glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);
+
+ /* load draw vertices & elements directly into vertex + element buffer */
+ vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ {
+ /* fill convert configuration */
+ struct nk_convert_config config;
+ static const struct nk_draw_vertex_layout_element vertex_layout[] = {
+ {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},
+ {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},
+ {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},
+ {NK_VERTEX_LAYOUT_END}
+ };
+ NK_MEMSET(&config, 0, sizeof(config));
+ config.vertex_layout = vertex_layout;
+ config.vertex_size = sizeof(struct nk_glfw_vertex);
+ config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);
+ config.tex_null = dev->tex_null;
+ config.circle_segment_count = 22;
+ config.curve_segment_count = 22;
+ config.arc_segment_count = 22;
+ config.global_alpha = 1.0f;
+ config.shape_AA = AA;
+ config.line_AA = AA;
+
+ /* setup buffers to load vertices and elements */
+ {struct nk_buffer vbuf, ebuf;
+ nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);
+ nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);
+ nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ /* iterate over and execute each draw command */
+ nk_draw_foreach(cmd, ctx, &dev->cmds)
+ {
+ if (!cmd->elem_count) continue;
+ glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
+ glScissor(
+ (GLint)(cmd->clip_rect.x * scale.x),
+ (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),
+ (GLint)(cmd->clip_rect.w * scale.x),
+ (GLint)(cmd->clip_rect.h * scale.y));
+ glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
+ offset += cmd->elem_count;
+ }
+ nk_clear(ctx);
+ nk_buffer_clear(&dev->cmds);
+ }
+
+ /* default OpenGL state */
+ glUseProgram(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+}
+
class Main
{
public:
@@ -90,12 +381,27 @@ public:
}
enum ColorScaleType {
- ColorScaleCategorical,
+ ColorScaleCategorical = 0,
ColorScaleContinuous,
ColorScaleDivergent,
ColorScaleRainbow
};
+ static constexpr const char *colormapItemNames[] = {
+ "Categorical",
+ "Continuous",
+ "Divergent",
+ "Rainbow",
+ nullptr,
+ };
+
+ static constexpr const char *metricItemNames[] = {
+ "Aggregate error",
+ "Ctrl. Pt. influence",
+ "Stress",
+ nullptr,
+ };
+
void setCPColorScale(ColorScaleType colorScaleType) {
float min = 0.0f;
float max = 1.0f;
@@ -106,10 +412,10 @@ public:
colorScaleCPs = getColorScale(colorScaleType);
colorScaleCPs->setExtents(min, max);
- cpPlot->setColorScale(colorScaleCPs);
- cpBarChart->setColorScale(colorScaleCPs);
+ // cpBarChart->setColorScale(colorScaleCPs);
cpColormap->setColorScale(colorScaleCPs);
// bundlePlot->setColorScale(colorScaleCPs);
+ cpPlot->update();
}
void setRPColorScale(ColorScaleType colorScaleType) {
@@ -123,10 +429,10 @@ public:
colorScaleRPs = getColorScale(colorScaleType);
colorScaleRPs->setExtents(min, max);
- rpPlot->setColorScale(colorScaleRPs);
- splat->setColorScale(colorScaleRPs);
- rpBarChart->setColorScale(colorScaleRPs);
+ // rpBarChart->setColorScale(colorScaleRPs);
rpColormap->setColorScale(colorScaleRPs);
+ rpPlot->update();
+ splat->update();
}
// Pointers to visual components whose values are set in the main() function
@@ -238,6 +544,31 @@ private:
std::string m_indicesSavePath, m_cpSavePath;
};
+static void checkGLError(const char *msg) {
+ GLenum error = glGetError();
+ std::cout << msg << " ";
+ switch (error) {
+ case GL_NO_ERROR:
+ std::cout << "GL_NO_ERROR" << std::endl;
+ break;
+ case GL_INVALID_ENUM:
+ std::cout << "GL_INVALID_ENUM" << std::endl;
+ break;
+ case GL_INVALID_VALUE:
+ std::cout << "GL_INVALID_VALUE" << std::endl;
+ break;
+ case GL_INVALID_OPERATION:
+ std::cout << "GL_INVALID_OPERATION" << std::endl;
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ std::cout << "GL_INVALID_FRAMEBUFFER_OPERATION" << std::endl;
+ break;
+ case GL_OUT_OF_MEMORY:
+ std::cout << "GL_OUT_OF_MEMORY" << std::endl;
+ break;
+ }
+}
+
arma::uvec extractCPs(const arma::mat &X)
{
int numCPs = (int) (3 * sqrt(X.n_rows));
@@ -247,7 +578,7 @@ arma::uvec extractCPs(const arma::mat &X)
return indices.subvec(0, numCPs-1);
}
-arma::mat standardize(const arma::mat &X)
+arma::mat standardise(const arma::mat &X)
{
arma::mat stdX = X;
for (arma::uword j = 0; j < X.n_cols; j++) {
@@ -284,9 +615,9 @@ int main(int argc, char *argv[])
int display_width = 0, display_height = 0;
// GUI
- // struct device device;
- // struct nk_font_atlas atlas;
- // struct media media;
+ struct device device;
+ struct nk_font_atlas atlas;
+ struct media media;
struct nk_context ctx;
NK_UNUSED(argc);
@@ -303,13 +634,13 @@ int main(int argc, char *argv[])
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
-#endif
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GL_TRUE);
+#endif
glfwWindowHint(GLFW_RED_BITS, 8);
glfwWindowHint(GLFW_GREEN_BITS, 8);
glfwWindowHint(GLFW_BLUE_BITS, 8);
glfwWindowHint(GLFW_ALPHA_BITS, 8);
- glfwWindowHint(GLFW_SAMPLES, 8);
+ glfwWindowHint(GLFW_SAMPLES, 4);
win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "pm", NULL, NULL);
if (!win) {
@@ -342,15 +673,16 @@ int main(int argc, char *argv[])
exit(1);
}
+ glEnable(GL_MULTISAMPLE);
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
Main &m = Main::instance();
- if (!m.loadDataset("wdbc-std.tbl")) {
+ if (argc != 2 || !m.loadDataset(argv[1])) {
std::cerr << "Could not load data." << std::endl;
return 1;
}
- const arma::mat &X = standardize(m.X());
+ const arma::mat &X = standardise(m.X());
arma::arma_rng::set_seed(RNG_SEED);
arma::uvec cpIndices;
@@ -371,7 +703,7 @@ int main(int argc, char *argv[])
// TODO: maybe put this inside m->setCP() method; for now, will be outside
// for more flexibility
- Ys = arma::normalise(Ys);
+ // Ys = arma::normalise(Ys);
// Sort indices (some operations become easier later)
arma::uvec cpSortedIndices = arma::sort_index(cpIndices);
@@ -385,13 +717,23 @@ int main(int argc, char *argv[])
ProjectionHistory history(X, cpIndices);
// Visual components
+ Colormap cpColormap, rpColormap;
Scatterplot cpPlot, rpPlot;
VoronoiSplat splat;
- Colormap cpColormap, rpColormap;
+ cpPlot.setSize(512, 512);
+ rpPlot.setSize(512, 512);
+ rpPlot.setGlyphSize(3.0f);
+ rpPlot.setColormap(rpColormap.texture());
+ splat.setSize(512, 512);
+ splat.setColormap(rpColormap.texture());
BarChart cpBarChart, rpBarChart;
m.cpPlot = &cpPlot;
m.rpPlot = &rpPlot;
m.splat = &splat;
+ m.cpColormap = &cpColormap;
+ m.rpColormap = &rpColormap;
+ m.cpBarChart = &cpBarChart;
+ m.rpBarChart = &rpBarChart;
auto setCP = std::bind(&Main::setCP, &m, std::placeholders::_1);
cpPlot.xyChanged.connect(setCP);
@@ -571,8 +913,8 @@ int main(int argc, char *argv[])
std::max(m.colorScaleRPs->max(), (float) v.max()));
}
- m.splat->setColorScale(m.colorScaleRPs);
m.rpColormap->setColorScale(m.colorScaleRPs);
+ // rpPlot.setColorData(v);
});
history.cpValuesChanged.connect([&](const arma::vec &v, bool rescale) {
if (!m.colorScaleCPs || v.n_elem == 0) {
@@ -629,12 +971,40 @@ int main(int argc, char *argv[])
// m->rpBarChart->setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
m.setCPColorScale(Main::ColorScaleRainbow);
+ enum Main::ColorScaleType cpColorScaleType = Main::ColorScaleRainbow;
m.setRPColorScale(Main::ColorScaleRainbow);
+ enum Main::ColorScaleType rpColorScaleType = Main::ColorScaleRainbow;
// This sets the initial CP configuration, triggering all the necessary
// signals to set up the helper objects and visual components
manipulationHandler.setCP(Ys);
+
+ // GUI init
+ device_init(&device);
+ {
+ const void *image;
+ int w, h;
+ struct nk_font_config cfg = nk_font_config(0);
+ cfg.oversample_h = 3;
+ cfg.oversample_v = 2;
+ nk_font_atlas_init_default(&atlas);
+ nk_font_atlas_begin(&atlas);
+ media.font_14 = nk_font_atlas_add_from_file(&atlas, "assets/Roboto-Regular.ttf", 14.0f, &cfg);
+ media.font_18 = nk_font_atlas_add_from_file(&atlas, "assets/Roboto-Regular.ttf", 18.0f, &cfg);
+ media.font_20 = nk_font_atlas_add_from_file(&atlas, "assets/Roboto-Regular.ttf", 20.0f, &cfg);
+ media.font_22 = nk_font_atlas_add_from_file(&atlas, "assets/Roboto-Regular.ttf", 22.0f, &cfg);
+ image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+ device_upload_atlas(&device, image, w, h);
+ nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.tex_null);
+ }
+ nk_init_default(&ctx, &media.font_14->handle);
+
+ struct nk_image cpPlot_img = nk_image_id((int) cpPlot.texture());
+ struct nk_image rpPlot_img = nk_image_id((int) rpPlot.texture());
+ struct nk_image splat_img = nk_image_id((int) splat.texture());
+ struct nk_image cpColormap_img = nk_image_id((int) cpColormap.texture());
+ struct nk_image rpColormap_img = nk_image_id((int) rpColormap.texture());
while (!glfwWindowShouldClose(win)) {
struct nk_vec2 scale;
glfwGetWindowSize(win, &width, &height);
@@ -673,19 +1043,210 @@ int main(int argc, char *argv[])
int int_x = static_cast<int>(x);
int int_y = static_cast<int>(y);
nk_input_motion(&ctx, int_x, int_y);
- nk_input_button(&ctx, NK_BUTTON_LEFT, int_x, int_y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
- nk_input_button(&ctx, NK_BUTTON_MIDDLE, int_x, int_y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
- nk_input_button(&ctx, NK_BUTTON_RIGHT, int_x, int_y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_LEFT, int_x, int_y,
+ glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_MIDDLE, int_x, int_y,
+ glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);
+ nk_input_button(&ctx, NK_BUTTON_RIGHT, int_x, int_y,
+ glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);
nk_input_end(&ctx);
}
+ nk_style_set_font(&ctx, &media.font_20->handle);
+ if (nk_begin(&ctx, "Control points", nk_rect(550, 20, 350, 300),
+ NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
+ ui_header(&ctx, &media, "Glyphs");
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float glyphSize = cpPlot.glyphSize();
+ nk_property_float(&ctx, "Size:", 1.0f, &glyphSize, 20.0f, 1.0f, 0.1f);
+ if (glyphSize != cpPlot.glyphSize()) {
+ cpPlot.setGlyphSize(glyphSize);
+ }
+
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float opacity = 1.0f;
+ nk_property_float(&ctx, "Opacity:", 0.0f, &opacity, 1.0f, 0.1f, 0.01f);
+ // TODO
+
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ nk_spacer(&ctx);
+
+ ui_header(&ctx, &media, "Colors");
+ nk_layout_row_begin(&ctx, NK_DYNAMIC, 30, 2);
+ nk_layout_row_push(&ctx, 0.3f);
+ nk_label(&ctx, "Scale:", NK_TEXT_RIGHT);
+ nk_layout_row_push(&ctx, 0.7f);
+ if (nk_combo_begin_label(&ctx, Main::colormapItemNames[cpColorScaleType],
+ nk_vec2(nk_widget_width(&ctx), 200))) {
+ nk_layout_row_dynamic(&ctx, 25, 1);
+ size_t i = 0;
+ for (const char * const *name = &Main::colormapItemNames[0];
+ *name != nullptr; name++) {
+ if (nk_combo_item_label(&ctx, *name, NK_TEXT_LEFT)) {
+ enum Main::ColorScaleType type = static_cast<Main::ColorScaleType>(i);
+ if (type != cpColorScaleType) {
+ m.setCPColorScale(type);
+ cpColorScaleType = type;
+ }
+ }
+ i++;
+ }
+ nk_combo_end(&ctx);
+ }
+ nk_layout_row_end(&ctx);
+
+ nk_layout_row_begin(&ctx, NK_DYNAMIC, 30, 2);
+ nk_layout_row_push(&ctx, 0.3f);
+ nk_label(&ctx, "Map to:", NK_TEXT_RIGHT);
+ nk_layout_row_push(&ctx, 0.7f);
+ if (nk_combo_begin_label(&ctx, Main::metricItemNames[0],
+ nk_vec2(nk_widget_width(&ctx), 200))) {
+ nk_layout_row_dynamic(&ctx, 25, 1);
+ size_t i = 0;
+ for (const char * const *name = &Main::metricItemNames[0];
+ *name != nullptr; name++) {
+ if (nk_combo_item_label(&ctx, *name, NK_TEXT_LEFT)) {
+ // TODO
+ }
+ i++;
+ }
+ nk_combo_end(&ctx);
+ }
+ nk_layout_row_end(&ctx);
+ }
+ nk_end(&ctx);
+
+ if (nk_begin(&ctx, "Regular points", nk_rect(550, 340, 350, 400),
+ NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
+ ui_header(&ctx, &media, "Splat");
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float alpha = splat.alpha();
+ nk_property_float(&ctx, "Blur (alpha):", 5.0f, &alpha, 50.0f, 1.0f, 0.1f);
+ if (alpha != splat.alpha()) {
+ splat.setAlpha(alpha);
+ }
+
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float beta = splat.beta();
+ nk_property_float(&ctx, "Radius (beta):", 5.0f, &beta, 50.0f, 1.0f, 0.1f);
+ if (beta != splat.beta()) {
+ splat.setBeta(beta);
+ }
+
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ nk_spacer(&ctx);
+
+ ui_header(&ctx, &media, "Glyphs");
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float glyphSize = rpPlot.glyphSize();
+ nk_property_float(&ctx, "Size:", 1.0f, &glyphSize, 20.0f, 1.0f, 0.1f);
+ if (glyphSize != rpPlot.glyphSize()) {
+ rpPlot.setGlyphSize(glyphSize);
+ }
+
+ nk_layout_row_dynamic(&ctx, 30, 1);
+ float opacity = 1.0f;
+ nk_property_float(&ctx, "Opacity:", 0.0f, &opacity, 1.0f, 0.1f, 0.01f);
+ // TODO
+
+ nk_layout_row_dynamic(&ctx, 20, 1);
+ nk_spacer(&ctx);
+
+ ui_header(&ctx, &media, "Colors");
+ nk_layout_row_begin(&ctx, NK_DYNAMIC, 30, 2);
+ nk_layout_row_push(&ctx, 0.3f);
+ nk_label(&ctx, "Scale:", NK_TEXT_RIGHT);
+ nk_layout_row_push(&ctx, 0.7f);
+ if (nk_combo_begin_label(&ctx, Main::colormapItemNames[rpColorScaleType],
+ nk_vec2(nk_widget_width(&ctx), 200))) {
+ nk_layout_row_dynamic(&ctx, 25, 1);
+ size_t i = 0;
+ for (const char * const *name = &Main::colormapItemNames[0];
+ *name != nullptr; name++) {
+ if (nk_combo_item_label(&ctx, *name, NK_TEXT_LEFT)) {
+ enum Main::ColorScaleType type = static_cast<Main::ColorScaleType>(i);
+ if (type != rpColorScaleType) {
+ m.setRPColorScale(type);
+ rpColorScaleType = type;
+ }
+ }
+ i++;
+ }
+ nk_combo_end(&ctx);
+ }
+ nk_layout_row_end(&ctx);
+
+ nk_layout_row_begin(&ctx, NK_DYNAMIC, 30, 2);
+ nk_layout_row_push(&ctx, 0.3f);
+ nk_label(&ctx, "Map to:", NK_TEXT_RIGHT);
+ nk_layout_row_push(&ctx, 0.7f);
+ if (nk_combo_begin_label(&ctx, Main::metricItemNames[0],
+ nk_vec2(nk_widget_width(&ctx), 200))) {
+ nk_layout_row_dynamic(&ctx, 25, 1);
+ size_t i = 0;
+ for (const char * const *name = &Main::metricItemNames[0];
+ *name != nullptr; name++) {
+ if (nk_combo_item_label(&ctx, *name, NK_TEXT_LEFT)) {
+ // TODO
+ }
+ i++;
+ }
+ nk_combo_end(&ctx);
+ }
+ nk_layout_row_end(&ctx);
+ }
+ nk_end(&ctx);
+
+ if (nk_begin(&ctx, "Scatterplot", nk_rect(20, 20, splat.width(), splat.height()),
+ NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR)) {
+ struct nk_command_buffer *canvas = nk_window_get_canvas(&ctx);
+ struct nk_rect region{0.0f, 0.0f,
+ static_cast<float>(splat.width()),
+ static_cast<float>(splat.height())};
+
+ // Render components to their textures
+ splat.draw();
+ rpPlot.draw();
+ cpPlot.draw();
+
+ // Add white background rect and draw textures on top
+ nk_layout_space_begin(&ctx, NK_STATIC, region.h, 4);
+ nk_layout_space_push(&ctx, region);
+ nk_fill_rect(canvas, region, 0.0f, nk_rgba(255, 255, 255, 255));
+ nk_layout_space_push(&ctx, region);
+ nk_image(&ctx, splat_img);
+ nk_layout_space_push(&ctx, region);
+ nk_image(&ctx, rpPlot_img);
+ nk_layout_space_push(&ctx, region);
+ nk_image(&ctx, cpPlot_img);
+ nk_layout_space_end(&ctx);
+ }
+ nk_end(&ctx);
+
+ if (nk_begin(&ctx, "Colormap", nk_rect(20, 40 + splat.height(), splat.width(), 120),
+ NK_WINDOW_BORDER | NK_WINDOW_TITLE | NK_WINDOW_NO_SCROLLBAR)) {
+ // nk_widget(&bounds, &ctx);
+ ui_header(&ctx, &media, "Control points");
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_image(&ctx, cpColormap_img);
+
+ ui_header(&ctx, &media, "Regular points");
+ nk_layout_row_dynamic(&ctx, 10, 1);
+ nk_image(&ctx, rpColormap_img);
+ }
+ nk_end(&ctx);
+
glViewport(0, 0, display_width, display_height);
- glClear(GL_COLOR_BUFFER_BIT);
+ // glDisable(GL_BLEND);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
- // device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);
+
glfwSwapBuffers(win);
+ // nk_clear(&ctx);
}
+ nk_font_atlas_clear(&atlas);
nk_free(&ctx);
glfwTerminate();
return 0;