slightly better?
[vrfileman] / src / fs.cc
index b65db45..c7df966 100644 (file)
--- a/src/fs.cc
+++ b/src/fs.cc
@@ -4,6 +4,7 @@
 #include <errno.h>
 #include <string>
 #include <map>
+#include <algorithm>
 #include <unistd.h>
 #include <dirent.h>
 #include <sys/stat.h>
 #include "gmath/gmath.h"
 #include "opengl.h"
 #include "app.h"
+#include "drawtext.h"
+#include "sdr.h"
+
+static void draw_node_name(FSNode *node, float angle, float ypos, float dist, bool full);
 
 static IconRenderer *iconrend;
 
@@ -19,14 +24,59 @@ static std::map<std::string, FSNode*> node_cache;
 static FSNode *cur_node;
 static int start_child;
 
-bool init_fs()
+static dtx_font *fat_font;
+#define FAT_FONT_SZ    32
+static unsigned int glow_link_sdr;
+static unsigned int chrome_font_sdr, glow_font_sdr;
+
+
+bool init_fs(const char *path)
 {
        iconrend = new ShapesIcons;
        if(!iconrend->init()) {
                return false;
        }
 
-       cur_node = get_fsnode(0);
+       if(!(fat_font = dtx_open_font_glyphmap("data/fat.glyphmap")) ||
+                       dtx_get_glyphmap_ptsize(dtx_get_glyphmap(fat_font, 0)) != FAT_FONT_SZ) {
+
+               dtx_set(DTX_PADDING, 64);
+
+               if(!(fat_font = dtx_open_font("data/fat.font", 0))) {
+                       fprintf(stderr, "failed to open font file data/fat.font\n");
+                       return false;
+               }
+               dtx_prepare_range(fat_font, FAT_FONT_SZ * 8, 32, 127);
+               dtx_calc_font_distfield(fat_font, 1, 8);
+               dtx_save_glyphmap("data/fat.glyphmap", dtx_get_glyphmap(fat_font, 0));
+       }
+       dtx_use_font(fat_font, FAT_FONT_SZ);
+
+       struct dtx_glyphmap *fat_gmap = dtx_get_glyphmap(fat_font, 0);
+       Vec2 pixsz;
+       pixsz.x = 1.0 / dtx_get_glyphmap_width(fat_gmap);
+       pixsz.y = 1.0 / dtx_get_glyphmap_height(fat_gmap);
+
+       if(!(chrome_font_sdr = create_program_load("sdr/chrome_font.v.glsl", "sdr/chrome_font.p.glsl"))) {
+               return false;
+       }
+       set_uniform_float(chrome_font_sdr, "height", dtx_line_height());
+       set_uniform_float(chrome_font_sdr, "smoothness", 0.01);
+       set_uniform_float2(chrome_font_sdr, "pix_sz", pixsz.x, pixsz.y);
+
+       if(!(glow_font_sdr = create_program_load("sdr/dfont.v.glsl", "sdr/glow_font.p.glsl"))) {
+               return false;
+       }
+       set_uniform_float(glow_font_sdr, "smoothness", 0.01);
+       set_uniform_float2(glow_font_sdr, "pix_sz", pixsz.x, pixsz.y);
+
+       if(!(glow_link_sdr = create_program_load("sdr/glink.v.glsl", "sdr/glink.p.glsl"))) {
+               return false;
+       }
+
+       if(!(cur_node = get_fsnode(path))) {
+               return false;
+       }
        cur_node->expand();
        return true;
 }
@@ -39,46 +89,131 @@ void cleanup_fs()
                delete node;
        }
        node_cache.clear();
+       dtx_close_font(fat_font);
        delete iconrend;
 }
 
-static Vec3 icon_pos(int row, int col, int ncols, float row_spacing, float radius)
+static float icon_angle(int col, int ncols, float max_angle = 0.0f)
 {
-       float angle = 2.0 * M_PI * (float)col / (float)ncols;
-       float x = sin(angle) * radius;
-       float z = -cos(angle) * radius;
-       float y = (float)row * row_spacing;
-       return Vec3(x, y, z);
+       if(max_angle > 0) {
+               return max_angle * ((float)col / (float)(ncols - 1) - 0.5);
+       }
+       return 2.0 * M_PI * (float)col / (float)ncols;
 }
 
 void draw_fs()
 {
-       static const int ncols = 8;
-       static const float row_spacing = 2.0;
-       static const float radius = 5;
+       static const float row_spacing = 0.25;
+       static const float radius = 0.6;
+       static const float umax = 0.42;
+       static const float max_icon_angle = M_PI * 2.0 * umax;
 
-       Mat4 base_xform;
-       base_xform.rotate(time_sec, 0, 0);
-       base_xform.rotate(0, 0, time_sec * 0.5);
-       base_xform.translate(0, 2, 0);
+       int max_ncols = std::max<int>(1, umax * 12);
+
+       glPushMatrix();
+       glTranslatef(0, cam_height, 0);
+
+       Mat4 rot_xform;
+       rot_xform.rotate(time_sec, 0, 0);
+       rot_xform.rotate(0, 0, time_sec * 0.5);
 
-       glUseProgram(0);
        glDisable(GL_TEXTURE_2D);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-       int first = start_child % ncols;
        int nchildren = (int)cur_node->children.size();
+       int ncols = std::min(cur_node->nfiles, max_ncols);
+
+       int first = start_child % ncols;
        int col = 0, row = 0;
+       int num_dirs = 0;
+
+       // count directories ...
+       for(int i=0; i<nchildren; i++) {
+               FSNode *node = cur_node->children[i];
+               if(node->type == FSTYPE_DIR) {
+                       ++num_dirs;
+               }
+       }
+
+       // draw the directory link lines
+       glUseProgram(glow_link_sdr);
+       set_uniform_float(glow_link_sdr, "tsec", time_sec);
+       glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+       for(int i=0; i<nchildren; i++) {
+               FSNode *node = cur_node->children[i];
+
+               if(node->type != FSTYPE_DIR) {
+                       continue;
+               }
+
+               float angle = (float)col++ / (float)(num_dirs - 1) * max_icon_angle - max_icon_angle * 0.5;
+
+               Mat4 xform;
+               xform.rotate_y(angle);
+               xform.translate(0, -0.3, 0);
+
+               glPushMatrix();
+               glMultMatrixf(xform[0]);
+               glDepthMask(0);
+
+               set_uniform_float(glow_link_sdr, "phase", col * 42.0);
+
+               glBegin(GL_QUADS);
+               glColor3f(0.2, 0.3, 0.8);
+               glTexCoord2f(0, 0);
+               glVertex3f(-0.2, 0, 0.05);
+               glTexCoord2f(1, 0);
+               glVertex3f(0.2, 0, 0.05);
+               glTexCoord2f(1, 1);
+               glVertex3f(0.2, 0, -5.0);
+               glTexCoord2f(0, 1);
+               glVertex3f(-0.2, 0, -5.0);
+               glColor3f(1, 1, 1);
+               glEnd();
+               glPopMatrix();
+
+               glDepthMask(1);
+       }
+
+       // draw the directory labels
+       glUseProgram(glow_font_sdr);
+       col = 0;
+       for(int i=0; i<nchildren; i++) {
+               FSNode *node = cur_node->children[i];
+
+               if(node->type != FSTYPE_DIR) {
+                       continue;
+               }
 
+               float angle = (float)col++ / (float)(num_dirs - 1) * max_icon_angle - max_icon_angle * 0.5;
+
+               draw_node_name(node, angle, -0.3, radius, false);
+       }
+
+       // then draw file icons
+       glDisable(GL_BLEND);
+       glUseProgram(0);
+       col = 0;
        for(int i=0; i<nchildren; i++) {
                int idx = (i + first) % nchildren;
-               Vec3 pos = icon_pos(row, col, ncols, row_spacing, radius);
+               FSNode *node = cur_node->children[idx];
 
-               Mat4 xform = base_xform;
-               xform.translate(pos);
+               if(node->type == FSTYPE_DIR) {
+                       ++num_dirs;
+                       continue;
+               }
+
+               float angle = icon_angle(col, ncols, max_icon_angle);
+
+               Mat4 xform = rot_xform;
+               xform.translate(0, row * row_spacing, -radius);
+               xform.rotate_y(angle);
 
                glPushMatrix();
                glMultMatrixf(xform[0]);
-               iconrend->draw(cur_node->children[idx]);
+               iconrend->draw(node);
                glPopMatrix();
 
                if(++col >= ncols) {
@@ -86,8 +221,62 @@ void draw_fs()
                        ++row;
                }
        }
+
+       // then draw the file labels
+       glUseProgram(chrome_font_sdr);
+       col = 0;
+       row = 0;
+       for(int i=0; i<nchildren; i++) {
+               int idx = (i + first) % nchildren;
+               FSNode *node = cur_node->children[idx];
+
+               if(node->type == FSTYPE_DIR) {
+                       ++num_dirs;
+                       continue;
+               }
+
+               float angle = icon_angle(col, ncols, max_icon_angle);
+
+               draw_node_name(node, angle, row * row_spacing - 0.1, radius, false);
+
+               if(++col >= ncols) {
+                       col = 0;
+                       ++row;
+               }
+       }
+
+       glPopMatrix();
 }
 
+static void draw_node_name(FSNode *node, float angle, float ypos, float dist, bool full)
+{
+       dtx_use_font(fat_font, FAT_FONT_SZ);
+       int line_height = dtx_line_height();
+
+       int nlines = full ? node->name_lines.size() : 1;
+       for(int i=0; i<nlines; i++) {
+               const char *name = full ? node->name_lines[i].c_str() : node->short_name.c_str();
+               glPushMatrix();
+               Mat4 xform;
+               xform.translate(-dtx_string_width(name) / 2.0, -line_height * i, 0);
+               if(node->type == FSTYPE_DIR) {
+                       xform.rotate_z(deg_to_rad(90));
+                       xform.rotate_x(deg_to_rad(-90));
+                       xform.scale(0.0017);
+               } else {
+                       xform.scale(0.0012);
+               }
+               xform.translate(0, ypos, -dist);
+               xform.rotate_y(angle);
+               glMultMatrixf(xform[0]);
+
+               dtx_string(name);
+               glPopMatrix();
+       }
+}
+
+#define MAX_NAME_SZ    16
+
 FSNode *get_fsnode(const char *path)
 {
        char *abspath = make_abs_path(path);
@@ -97,6 +286,30 @@ FSNode *get_fsnode(const char *path)
                node = new FSNode;
                node->path = path;
 
+               const char *name = node->path.get_name();
+               if(name) {
+                       const char *ptr = name;
+                       while(*ptr) {
+                               if(ptr - name >= MAX_NAME_SZ) {
+                                       int len = ptr - name;
+                                       std::string s = std::string(name, len);
+                                       if(node->short_name.empty()) {
+                                               node->short_name = s;
+                                               node->short_name[len - 1] = node->short_name[len - 2] = '.';
+                                       }
+                                       node->name_lines.push_back(s);
+                                       name = ptr;
+                               }
+                               ++ptr;
+                       }
+                       if(*name) {
+                               if(node->short_name.empty()) {
+                                       node->short_name = name;
+                               }
+                               node->name_lines.push_back(name);
+                       }
+               }
+
                struct stat st;
                if(stat(node->path, &st) == -1) {
                        fprintf(stderr, "failed to stat: %s\n", node->path.get_path());
@@ -151,6 +364,7 @@ FSNode::FSNode()
        type = FSTYPE_UNKNOWN;
        size = 0;
        parent = 0;
+       nfiles = ndirs = 0;
 }
 
 bool FSNode::expand()
@@ -175,6 +389,15 @@ bool FSNode::expand()
                if(!node) continue;
 
                children.push_back(node);
+               switch(node->type) {
+               case FSTYPE_FILE:
+                       ++nfiles;
+                       break;
+               case FSTYPE_DIR:
+                       ++ndirs;
+               default:
+                       break;
+               }
        }
        printf("expanded %d children\n", (int)children.size());