13 #include "gmath/gmath.h"
19 static void draw_node_name(FSNode *node, float angle, float ypos, float dist, bool full);
21 static IconRenderer *iconrend;
23 static std::map<std::string, FSNode*> node_cache;
24 static FSNode *cur_node;
25 static int start_child;
27 static dtx_font *fat_font;
28 #define FAT_FONT_SZ 32
29 static unsigned int glow_link_sdr;
30 static unsigned int chrome_font_sdr, glow_font_sdr;
33 bool init_fs(const char *path)
35 iconrend = new ShapesIcons;
36 if(!iconrend->init()) {
40 if(!(fat_font = dtx_open_font_glyphmap("data/fat.glyphmap")) ||
41 dtx_get_glyphmap_ptsize(dtx_get_glyphmap(fat_font, 0)) != FAT_FONT_SZ) {
43 dtx_set(DTX_PADDING, 64);
45 if(!(fat_font = dtx_open_font("data/fat.font", 0))) {
46 fprintf(stderr, "failed to open font file data/fat.font\n");
49 dtx_prepare_range(fat_font, FAT_FONT_SZ * 8, 32, 127);
50 dtx_calc_font_distfield(fat_font, 1, 8);
51 dtx_save_glyphmap("data/fat.glyphmap", dtx_get_glyphmap(fat_font, 0));
53 dtx_use_font(fat_font, FAT_FONT_SZ);
55 struct dtx_glyphmap *fat_gmap = dtx_get_glyphmap(fat_font, 0);
57 pixsz.x = 1.0 / dtx_get_glyphmap_width(fat_gmap);
58 pixsz.y = 1.0 / dtx_get_glyphmap_height(fat_gmap);
60 if(!(chrome_font_sdr = create_program_load("sdr/chrome_font.v.glsl", "sdr/chrome_font.p.glsl"))) {
63 set_uniform_float(chrome_font_sdr, "height", dtx_line_height());
64 set_uniform_float(chrome_font_sdr, "smoothness", 0.01);
65 set_uniform_float2(chrome_font_sdr, "pix_sz", pixsz.x, pixsz.y);
67 if(!(glow_font_sdr = create_program_load("sdr/dfont.v.glsl", "sdr/glow_font.p.glsl"))) {
70 set_uniform_float(glow_font_sdr, "smoothness", 0.01);
71 set_uniform_float2(glow_font_sdr, "pix_sz", pixsz.x, pixsz.y);
73 if(!(glow_link_sdr = create_program_load("sdr/glink.v.glsl", "sdr/glink.p.glsl"))) {
77 if(!(cur_node = get_fsnode(path))) {
86 std::map<std::string, FSNode*>::iterator it = node_cache.begin();
87 while(it != node_cache.end()) {
88 FSNode *node = it++->second;
92 dtx_close_font(fat_font);
96 static float icon_angle(int col, int ncols, float max_angle = 0.0f)
99 return max_angle * ((float)col / (float)(ncols - 1) - 0.5);
101 return 2.0 * M_PI * (float)col / (float)ncols;
106 static const float row_spacing = 0.25;
107 static const float radius = 0.6;
108 static const float umax = 0.42;
109 static const float max_icon_angle = M_PI * 2.0 * umax;
110 static const float first_row_y = -row_spacing;
112 int max_ncols = std::max<int>(1, umax * 12);
115 glTranslatef(0, cam_height, 0);
118 rot_xform.rotate(time_sec, 0, 0);
119 rot_xform.rotate(0, 0, time_sec * 0.5);
121 glDisable(GL_TEXTURE_2D);
123 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
125 int nchildren = (int)cur_node->children.size();
126 int ncols = std::max(std::min(cur_node->nfiles, max_ncols), 1);
128 int first = start_child % ncols;
129 int col = 0, row = 0;
132 // count directories ...
133 for(int i=0; i<nchildren; i++) {
134 FSNode *node = cur_node->children[i];
135 if(node->type == FSTYPE_DIR) {
140 // draw the directory link lines
141 glUseProgram(glow_link_sdr);
142 set_uniform_float(glow_link_sdr, "tsec", time_sec);
143 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
145 for(int i=0; i<nchildren; i++) {
146 FSNode *node = cur_node->children[i];
148 if(node->type != FSTYPE_DIR) {
152 float angle = (float)col++ / (float)(num_dirs - 1) * max_icon_angle - max_icon_angle * 0.5;
155 xform.rotate_y(angle);
156 xform.translate(0, -0.6, 0);
159 glMultMatrixf(xform[0]);
162 set_uniform_float(glow_link_sdr, "phase", col * 42.0);
165 glColor3f(0.2, 0.3, 0.8);
167 glVertex3f(-0.2, 0, 0.05);
169 glVertex3f(0.2, 0, 0.05);
171 glVertex3f(0.2, 0, -10.0);
173 glVertex3f(-0.2, 0, -10.0);
181 // draw the directory labels
182 glUseProgram(glow_font_sdr);
184 for(int i=0; i<nchildren; i++) {
185 FSNode *node = cur_node->children[i];
187 if(node->type != FSTYPE_DIR) {
191 float angle = (float)col++ / (float)(num_dirs - 1) * max_icon_angle - max_icon_angle * 0.5;
193 draw_node_name(node, angle, -0.6, radius * 1.2, false);
196 // then draw file icons
201 for(int i=0; i<nchildren; i++) {
202 int idx = (i + first) % nchildren;
203 FSNode *node = cur_node->children[idx];
205 if(node->type == FSTYPE_DIR) {
210 float angle = icon_angle(col, ncols, max_icon_angle);
212 Mat4 xform = rot_xform;
213 xform.translate(0, row * row_spacing + first_row_y, -radius);
214 xform.rotate_y(angle);
217 glMultMatrixf(xform[0]);
218 iconrend->draw(node);
228 // then draw the file labels
229 glUseProgram(chrome_font_sdr);
232 for(int i=0; i<nchildren; i++) {
233 int idx = (i + first) % nchildren;
234 FSNode *node = cur_node->children[idx];
236 if(node->type == FSTYPE_DIR) {
241 float angle = icon_angle(col, ncols, max_icon_angle);
243 draw_node_name(node, angle, row * row_spacing + first_row_y - 0.08, radius, false);
254 static void draw_node_name(FSNode *node, float angle, float ypos, float dist, bool full)
256 dtx_use_font(fat_font, FAT_FONT_SZ);
257 int line_height = dtx_line_height();
259 int nlines = full ? node->name_lines.size() : 1;
260 for(int i=0; i<nlines; i++) {
261 const char *name = full ? node->name_lines[i].c_str() : node->short_name.c_str();
264 xform.translate(-dtx_string_width(name) / 2.0, -line_height * i - line_height * 0.5, 0);
265 if(node->type == FSTYPE_DIR) {
266 xform.rotate_z(deg_to_rad(90));
267 xform.rotate_x(deg_to_rad(-90));
272 xform.translate(0, ypos, -dist);
273 xform.rotate_y(angle);
274 glMultMatrixf(xform[0]);
281 #define MAX_NAME_SZ 16
283 FSNode *get_fsnode(const char *path)
285 char *abspath = make_abs_path(path);
287 FSNode *node = node_cache[abspath];
292 const char *name = node->path.get_name();
294 const char *ptr = name;
296 if(ptr - name >= MAX_NAME_SZ) {
297 int len = ptr - name;
298 std::string s = std::string(name, len);
299 if(node->short_name.empty()) {
300 node->short_name = s;
301 node->short_name[len - 1] = node->short_name[len - 2] = '.';
303 node->name_lines.push_back(s);
309 if(node->short_name.empty()) {
310 node->short_name = name;
312 node->name_lines.push_back(name);
317 if(stat(node->path, &st) == -1) {
318 fprintf(stderr, "failed to stat: %s\n", node->path.get_path());
322 node->size = st.st_size;
324 switch(st.st_mode & S_IFMT) {
326 node->type = FSTYPE_FILE;
330 node->type = FSTYPE_DIR;
335 node->type = FSTYPE_DEV;
339 node->type = FSTYPE_UNKNOWN;
341 node_cache[abspath] = node;
347 FSNode *get_fsnode(const char *dir, const char *name)
350 return get_fsnode(name);
352 if(!name || *name == '/') {
356 int len = strlen(dir) + 1 + strlen(name);
357 char *buf = new char[len + 1];
358 sprintf(buf, "%s/%s", dir, name);
359 FSNode *res = get_fsnode(buf);
364 // ---- FSNode implementation ----
367 type = FSTYPE_UNKNOWN;
373 bool FSNode::expand()
375 if(type != FSTYPE_DIR) {
379 DIR *dir = opendir(path);
381 fprintf(stderr, "failed to open dir: %s: %s\n", path.get_path(), strerror(errno));
386 while((dent = readdir(dir))) {
387 if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
391 FSNode *node = get_fsnode(path, dent->d_name);
394 children.push_back(node);
405 printf("expanded %d children\n", (int)children.size());
407 parent = get_fsnode(path.get_parent());