X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=vrfileman;a=blobdiff_plain;f=src%2Ffs.cc;h=c7df966e18a5dd6fc6d5f6ebe6c84565549f60e4;hp=c85040a0347c0fb7995e8d326b076aadf25f8219;hb=5e07bfd4d034dc3d974c8db008c6446e62838d39;hpb=172da567dcbb634b13069e5c12ae8b6a9b3a29dc diff --git a/src/fs.cc b/src/fs.cc index c85040a..c7df966 100644 --- a/src/fs.cc +++ b/src/fs.cc @@ -1,99 +1,406 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include #include "fs.h" #include "icon.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; -bool init_fs() +static std::map node_cache; +static FSNode *cur_node; +static int start_child; + +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; } + 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; } void cleanup_fs() { + std::map::iterator it = node_cache.begin(); + while(it != node_cache.end()) { + FSNode *node = it++->second; + delete node; + } + node_cache.clear(); + dtx_close_font(fat_font); delete iconrend; } +static float icon_angle(int col, int ncols, float max_angle = 0.0f) +{ + 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() { - FSNode test; - test.type = FSNODE_DIR; + 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 xform; - xform.rotate(time_sec, 0, 0); - xform.rotate(0, 0, time_sec * 0.5); - xform.translate(0, 2, -5); + int max_ncols = std::max(1, umax * 12); glPushMatrix(); - glMultMatrixf(xform[0]); + 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); - iconrend->draw(&test); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + 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; ichildren[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; ichildren[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; ichildren[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; ichildren[idx]; + + 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(node); + glPopMatrix(); + + if(++col >= ncols) { + col = 0; + ++row; + } + } + + // then draw the file labels + glUseProgram(chrome_font_sdr); + col = 0; + row = 0; + for(int i=0; ichildren[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(); } -// ---- FSNode implementation ---- -FSNode::FSNode() +static void draw_node_name(FSNode *node, float angle, float ypos, float dist, bool full) { - type = FSNODE_UNKNOWN; - abs_path = name = suffix = 0; -} + dtx_use_font(fat_font, FAT_FONT_SZ); + int line_height = dtx_line_height(); -FSNode::~FSNode() -{ - if(abs_path) { - delete [] abs_path; + int nlines = full ? node->name_lines.size() : 1; + for(int i=0; iname_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(); } } -void FSNode::set_path(const char *s) +#define MAX_NAME_SZ 16 + +FSNode *get_fsnode(const char *path) { - int len = strlen(s); - if(!len) return; + char *abspath = make_abs_path(path); - delete [] abs_path; + FSNode *node = node_cache[abspath]; + if(!node) { + node = new FSNode; + node->path = path; - const char *slash = s + len - 1; - while(slash > s && *slash != '/') { - --slash; - } - if(name == s) { // no slashes found - char buf[1024]; - if(!getcwd(buf, sizeof buf)) { - abort(); + 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()); + delete node; + return 0; + } + node->size = st.st_size; + + switch(st.st_mode & S_IFMT) { + case S_IFREG: + node->type = FSTYPE_FILE; + break; + + case S_IFDIR: + node->type = FSTYPE_DIR; + break; + + case S_IFBLK: + case S_IFCHR: + node->type = FSTYPE_DEV; + break; + + default: + node->type = FSTYPE_UNKNOWN; } + node_cache[abspath] = node; + } - int dirlen = strlen(buf); - abs_path = new char[len + dirlen + 2]; - sprintf(abs_path, "%s/%s", buf, s); + return node; +} - name = abs_path + dirlen + 1; - suffix = abs_path + len + dirlen - 1; - } else { - abs_path = new char[len + 1]; - memcpy(abs_path, s, len + 1); +FSNode *get_fsnode(const char *dir, const char *name) +{ + if(!dir) { + return get_fsnode(name); + } + if(!name || *name == '/') { + return 0; + } + + int len = strlen(dir) + 1 + strlen(name); + char *buf = new char[len + 1]; + sprintf(buf, "%s/%s", dir, name); + FSNode *res = get_fsnode(buf); + delete [] buf; + return res; +} + +// ---- FSNode implementation ---- +FSNode::FSNode() +{ + type = FSTYPE_UNKNOWN; + size = 0; + parent = 0; + nfiles = ndirs = 0; +} - name = abs_path + (slash - s); - suffix = abs_path + len - 1; +bool FSNode::expand() +{ + if(type != FSTYPE_DIR) { + return false; } - while(suffix > name && *suffix != '.') { - --suffix; + DIR *dir = opendir(path); + if(!dir) { + fprintf(stderr, "failed to open dir: %s: %s\n", path.get_path(), strerror(errno)); + return false; } - if(suffix == name) { - suffix = 0; + + struct dirent *dent; + while((dent = readdir(dir))) { + if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { + continue; + } + + FSNode *node = get_fsnode(path, dent->d_name); + 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()); + + parent = get_fsnode(path.get_parent()); + return true; }