void buffer_enabled(vx_gtk_buffer_manager_t * man, vx_code_input_stream_t * cins) { int layer_id = cins->read_uint32(cins); const char * name = cins->read_str(cins); uint8_t enabled = cins->read_uint8(cins); int update = 0; pthread_mutex_lock(&man->mutex); { /* char * alloc_name = strdup(name); */ layer_info_t * linfo = NULL; zhash_get(man->layers, &layer_id, &linfo); if (linfo == NULL) { pthread_mutex_unlock(&man->mutex); return; // XXXX assert? } buffer_info_t * buffer = NULL; if (zhash_get(linfo->buffers, &name, &buffer)) { buffer->enabled = enabled; update = 1; } } pthread_mutex_unlock(&man->mutex); if (update == 1) queue_update_view(man); }
static void process_layer(state_t * state, vx_code_input_stream_t * cins) { // update (or create) the layer_info_t int layer_id = cins->read_uint32(cins); int world_id = cins->read_uint32(cins); int draw_order = cins->read_uint32(cins); int bg_color = cins->read_uint32(cins); layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &layer_id, &linfo); if (linfo == NULL) { linfo = calloc(1,sizeof(layer_info_t)); linfo->cam_mgr = default_cam_mgr_create(); linfo->event_handler = default_event_handler_create(linfo->cam_mgr, UI_ANIMATE_MS); linfo->vp_mgr = vx_viewport_mgr_create(); zhash_put(state->layer_info_map, &layer_id, &linfo, NULL, NULL); } linfo->layer_id = layer_id; linfo->draw_order = draw_order; bg_color+=world_id; // XXX unused variable }
static void zhash_set_test() { size_t size, ii; char **keys, **vals; struct ZHashTable *hash_table; size = 100; hash_table = zcreate_hash_table(); keys = malloc(size * sizeof(char *)); vals = malloc(size * sizeof(char *)); for (ii = 0; ii < size; ii++) { keys[ii] = random_string(); vals[ii] = random_string(); zhash_set(hash_table, keys[ii], (void *) vals[ii]); } assert(hash_table->size_index == 2); assert(hash_table->entry_count == size); for (ii = 0; ii < size; ii++) { assert(strcmp(zhash_get(hash_table, keys[ii]), vals[ii]) == 0); } for (ii = 0; ii < size; ii++) { free(keys[ii]); free(vals[ii]); } free(keys); free(vals); zfree_hash_table(hash_table); }
int vx_gtk_display_dispatch_key(vx_display_t * disp, vx_key_event_t *event) { assert(disp->impl_type == VX_GTK_DISPLAY_IMPL); state_t * state = disp->impl; // Process key shortcuts for the display pthread_mutex_lock(&state->mutex); int mouse_pressed_layer_id = state->mouse_pressed_layer_id; //local copy // Also dispatch to the relevant layers camera manager { layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &mouse_pressed_layer_id, &linfo); if (linfo != NULL) // sometimes there could be no layers linfo->event_handler->key_event(linfo->event_handler, NULL, event); } pthread_mutex_unlock(&state->mutex); pthread_mutex_lock(&state->listener_mutex); // notify all listeners of this event for (int i = 0; i < zarray_size(state->listeners); i++) { vx_display_listener_t * l = NULL; zarray_get(state->listeners, i, &l); l->event_dispatch_key(l, state->mouse_pressed_layer_id, event); } pthread_mutex_unlock(&state->listener_mutex); return 1; // gobble all events }
vx_buffer_t * vx_world_get_buffer(vx_world_t * world, const char * name) { vx_buffer_t * buffer = NULL; pthread_mutex_lock(&world->buffer_mutex); zhash_get(world->buffer_map, &name, &buffer); if (buffer == NULL) { buffer = calloc(1, sizeof(vx_buffer_t)); buffer->name = strdup(name); buffer->world = world; buffer->draw_order = 0; buffer->back_objs = zarray_create(sizeof(vx_object_t*)); buffer->pending_objs = zarray_create(sizeof(vx_object_t*)); buffer->front_objs = zarray_create(sizeof(vx_object_t*)); buffer->front_resc = zhash_create(sizeof(uint64_t), sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals); buffer->front_codes = vx_code_output_stream_create(128); pthread_mutex_init(&buffer->mutex, NULL); vx_buffer_t * oldBuffer= NULL; zhash_put(buffer->world->buffer_map, &buffer->name, &buffer, NULL, &oldBuffer); assert(oldBuffer == NULL); } pthread_mutex_unlock(&world->buffer_mutex); return buffer; }
void process_buffer(vx_gtk_buffer_manager_t * man, vx_code_input_stream_t * cins) { int world_id = cins->read_uint32(cins); const char * name = cins->read_str(cins); int draw_order = cins->read_uint32(cins); // find a matching layer: int update = 0; pthread_mutex_lock(&man->mutex); { layer_info_t * linfo = NULL; int layer_id = 0; zhash_iterator_t itr; zhash_iterator_init(man->layers, &itr); while(zhash_iterator_next(&itr, &layer_id, &linfo)) { if (linfo->world_id == world_id) { break; } } if (linfo == NULL) { // XXX Assert? pthread_mutex_unlock(&man->mutex); return; } // Now ensure there's a buffer_info_t in this layer. buffer_info_t * buffer = NULL; int success = zhash_get(linfo->buffers, &name, &buffer); // buffer doesn't exist yet? if (!success) { buffer = calloc(1, sizeof(buffer_info_t)); buffer->layer_id = linfo->layer_id; buffer->name = strdup(name); buffer->enabled = 1; buffer->draw_order = draw_order; buffer->man = man; zhash_put(linfo->buffers, &buffer->name, &buffer, NULL, NULL); update = 1; } // draw order changed? if (success && draw_order != buffer->draw_order) { assert(buffer != NULL); buffer->draw_order = draw_order; update = 1; } } pthread_mutex_unlock(&man->mutex); if (update == 1) queue_update_view(man); }
const char * getopt_get_string (getopt_t *gopt, const char *lname) { getopt_option_t *goo = NULL; zhash_get (gopt->lopts, &lname, &goo); // could return null, but this would be the only // method that doesn't assert on a missing key assert (goo != NULL); return goo->svalue; }
int getopt_was_specified (getopt_t *getopt, const char *lname) { getopt_option_t *goo = NULL; zhash_get (getopt->lopts, &lname, &goo); if (goo == NULL) return 0; return goo->was_specified; }
// gcc -Wall -Wextra hello.c ../src/zhash.c // prints "hello world" to stdout int main () { struct ZHashTable *hash_table; hash_table = zcreate_hash_table(); zhash_set(hash_table, "hello", (void *) "world"); if (zhash_exists(hash_table, "hello")) { printf("hello %s\n", (char *) zhash_get(hash_table, "hello")); } if (zhash_exists(hash_table, "goodbye")) { printf("goodbye %s\n", (char *) zhash_get(hash_table, "goodbye")); } zfree_hash_table(hash_table); return 0; }
// returns the layer under the specified x,y. Must be externally synchronized static int pick_layer(render_info_t * rinfo, float x, float y) { int layer_under_mouse_id = 0; for (int i = 0; i < zarray_size(rinfo->layers); i++) { layer_info_t * linfo = NULL; zarray_get(rinfo->layers, i, &linfo); int * viewport = NULL; zhash_get(rinfo->layer_positions, &linfo->layer_id, &viewport); if (check_viewport_bounds(x, y, viewport)) layer_under_mouse_id = linfo->layer_id; // highest ranked layer that matches will be it } return layer_under_mouse_id; }
static void zhash_exists_test() { struct ZHashTable *hash_table; hash_table = zcreate_hash_table(); zhash_set(hash_table, "hello", (void *) "world"); zhash_set(hash_table, "nothing", NULL); assert(zhash_exists(hash_table, "hello") == true); assert(zhash_exists(hash_table, "nothing") == true); assert(zhash_get(hash_table, "nothing") == NULL); assert(zhash_exists(hash_table, "nope") == false); zfree_hash_table(hash_table); }
static void process_viewport_rel(state_t * state, vx_code_input_stream_t * cins) { int layer_id = cins->read_uint32(cins); float rel[] = {cins->read_float(cins), cins->read_float(cins), cins->read_float(cins), cins->read_float(cins)}; int animate_ms = cins->read_uint32(cins); uint64_t mtime_goal = vx_mtime() + animate_ms; layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &layer_id, &linfo); if (linfo == NULL) return; vx_viewport_mgr_set_rel(linfo->vp_mgr,rel, mtime_goal); }
void process_layer(vx_gtk_buffer_manager_t * man, vx_code_input_stream_t * cins) { int layer_id = cins->read_uint32(cins); int world_id = cins->read_uint32(cins); int draw_order = cins->read_uint32(cins); /* int bg_color = cins->read_uint32(cins); */ int update = 0; pthread_mutex_lock(&man->mutex); { layer_info_t * linfo = NULL; int success = zhash_get(man->layers, &layer_id, &linfo); if (!success) { linfo = calloc(1,sizeof(layer_info_t)); linfo->layer_id = layer_id; linfo->world_id = world_id; linfo->buffers = zhash_create(sizeof(char*), sizeof(buffer_info_t*), zhash_str_hash, zhash_str_equals); zhash_put(man->layers, &layer_id, &linfo, NULL, NULL); update = 1; } if (success && draw_order != linfo->draw_order) { assert(linfo != NULL); linfo->draw_order = draw_order; update = 1; } assert(linfo->world_id == world_id); } pthread_mutex_unlock(&man->mutex); if (update == 1) queue_update_view(man); }
static void process_viewport_abs(state_t * state, vx_code_input_stream_t * cins) { int layer_id = cins->read_uint32(cins); int align_code = cins->read_uint32(cins); int offx = cins->read_uint32(cins); int offy = cins->read_uint32(cins); int width = cins->read_uint32(cins); int height = cins->read_uint32(cins); int animate_ms = cins->read_uint32(cins); uint64_t mtime_goal = vx_mtime() + animate_ms; layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &layer_id, &linfo); if (linfo == NULL) return; vx_viewport_mgr_set_abs(linfo->vp_mgr, align_code, offx, offy, width, height, mtime_goal); }
// returns 1 if no error int getopt_parse (getopt_t *gopt, int argc, char *argv[], int showErrors) { int okay = 1; zarray_t *toks = zarray_create (sizeof(char*)); // take the input stream and chop it up into tokens for (int i = 1; i < argc; i++) { char *arg = strdup (argv[i]); if (arg[0] != '-') { // if this isn't an option, put the whole thing in the args list. zarray_add (toks, &arg); } else { // this is an option. It could be a flag (like -v), or an option // with arguments (--file=foobar.txt). char *eq = strstr (arg, "="); // no equal sign? Push the whole thing. if (eq == NULL) { zarray_add (toks, &arg); } else { // there was an equal sign. Push the part // before and after the equal sign char *val = strdup (&eq[1]); eq[0] = 0; zarray_add (toks, &arg); // if the part after the equal sign is // enclosed by quotation marks, strip them. if (val[0]=='\"') { int last = strlen (val) - 1; if (val[last]=='\"') val[last] = 0; char *valclean = strdup (&val[1]); zarray_add (toks, &valclean); free (val); } else zarray_add (toks, &val); } } } // now loop over the elements and evaluate the arguments unsigned int i = 0; char *tok = NULL; while (i < zarray_size (toks)) { // rather than free statement throughout this while loop if (tok != NULL) free (tok); zarray_get (toks, i, &tok); if (0==strncmp (tok,"--", 2)) { char *optname = &tok[2]; getopt_option_t *goo = NULL; zhash_get (gopt->lopts, &optname, &goo); if (goo == NULL) { okay = 0; if (showErrors) printf ("Unknown option --%s\n", optname); i++; continue; } goo->was_specified = 1; if (goo->type == GOO_BOOL_TYPE) { if ((i+1) < zarray_size (toks)) { char *val = NULL; zarray_get (toks, i+1, &val); if (0==strcmp (val,"true")) { i+=2; getopt_modify_string (&goo->svalue, val); continue; } if (0==strcmp (val,"false")) { i+=2; getopt_modify_string (&goo->svalue, val); continue; } } getopt_modify_string (&goo->svalue, strdup("true")); i++; continue; } if (goo->type == GOO_STRING_TYPE) { // TODO: check whether next argument is an option, denoting missing argument if ((i+1) < zarray_size (toks)) { char *val = NULL; zarray_get (toks, i+1, &val); i+=2; getopt_modify_string (&goo->svalue, val); continue; } okay = 0; if (showErrors) printf ("Option %s requires a string argument.\n",optname); } } if (0==strncmp (tok,"-",1) && strncmp (tok,"--",2)) { int len = strlen (tok); int pos; for (pos = 1; pos < len; pos++) { char sopt[2]; sopt[0] = tok[pos]; sopt[1] = 0; char *sopt_ptr = (char*) &sopt; getopt_option_t *goo = NULL; zhash_get (gopt->sopts, &sopt_ptr, &goo); if (goo==NULL) { // is the argument a numerical literal that happens to be negative? if (pos==1 && isdigit (tok[pos])) { zarray_add (gopt->extraargs, &tok); tok = NULL; break; } else { okay = 0; if (showErrors) printf ("Unknown option -%c\n", tok[pos]); i++; continue; } } goo->was_specified = 1; if (goo->type == GOO_BOOL_TYPE) { getopt_modify_string (&goo->svalue, strdup("true")); continue; } if (goo->type == GOO_STRING_TYPE) { if ((i+1) < zarray_size (toks)) { char *val = NULL; zarray_get (toks, i+1, &val); // TODO: allow negative numerical values for short-name options ? if (val[0]=='-') { okay = 0; if (showErrors) printf ("Ran out of arguments for option block %s\n", tok); } i++; getopt_modify_string (&goo->svalue, val); continue; } okay = 0; if (showErrors) printf ("Option -%c requires a string argument.\n", tok[pos]); } } i++; continue; } // it's not an option-- it's an argument. zarray_add (gopt->extraargs, &tok); tok = NULL; i++; } if (tok != NULL) free (tok); zarray_destroy (toks); return okay; }
vx_object_t * vxo_objmtl(const char * obj_filename) { int texture_flag = 0; FILE * fp_obj = fopen(obj_filename, "r"); if (fp_obj == NULL) return NULL; #define LNSZ 1024 char line_buffer[LNSZ]; // Store 3D vertices by value zarray_t * vertices = zarray_create(sizeof(float)*3); zarray_t * textures = zarray_create(sizeof(float)*3); zarray_t * normals = zarray_create(sizeof(float)*3); wav_group_t * cur_group = NULL; zarray_t * group_list = zarray_create(sizeof(wav_group_t*)); zhash_t * mtl_map = NULL; // created on reading mtllib entry //zhash_t * obj_map = zhash_create(sizeof(char*), sizeof(vx_object_t*), zhash_str_hash, zhash_str_equals); // Read in the entire file, save vertices, and indices for later processing. while (1) { int eof = fgets(line_buffer, LNSZ, fp_obj) == NULL; char * line = str_trim(line_buffer); // If possible, batch process the last group if (str_starts_with(line, "g ") || eof) { if (cur_group != NULL) { assert(cur_group->group_idx != NULL); zarray_add(group_list, &cur_group); cur_group = NULL; } } if (eof) break; if (str_starts_with(line, "#") || strlen(line) == 0 || !strcmp(line,"\r")) continue; if (str_starts_with(line, "g ")) { assert(mtl_map != NULL); char obj_name[LNSZ]; sscanf(line, "g %s", obj_name); cur_group = calloc(1, sizeof(wav_group_t)); cur_group->group_idx = zarray_create(sizeof(tri_idx_t)); } else if (str_starts_with(line, "v ")) { float vertex[3]; sscanf(line, "v %f %f %f", &vertex[0], &vertex[1], &vertex[2]); zarray_add(vertices, &vertex); } else if (str_starts_with(line, "vn ")) { float normal[3]; sscanf(line, "vn %f %f %f", &normal[0], &normal[1], &normal[2]); zarray_add(normals, &normal); } else if (str_starts_with(line, "vt ")) { texture_flag = 1; float texture[3]; sscanf(line, "vt %f %f %f", &texture[0], &texture[1], &texture[2]); zarray_add(textures, &texture); } else if (str_starts_with(line, "f ")) { tri_idx_t idxs; if (texture_flag) { sscanf(line, "f %d/%d/%d %d/%d/%d %d/%d/%d", &idxs.vIdxs[0], &idxs.tIdxs[0], &idxs.nIdxs[0], &idxs.vIdxs[1], &idxs.tIdxs[1], &idxs.nIdxs[1], &idxs.vIdxs[2], &idxs.tIdxs[2], &idxs.nIdxs[2]); } else { sscanf(line, "f %d//%d %d//%d %d//%d", &idxs.vIdxs[0], &idxs.nIdxs[0], &idxs.vIdxs[1], &idxs.nIdxs[1], &idxs.vIdxs[2], &idxs.nIdxs[2]); } zarray_add(cur_group->group_idx, &idxs); } else if (str_starts_with(line, "usemtl ")) { char *mname = calloc(1, sizeof(char)*1024); sscanf(line, "usemtl %s", mname); zhash_get(mtl_map, &mname, &cur_group->material); free(mname); } else if (str_starts_with(line, "s ")) { // No idea what to do with smoothing instructions } else if (str_starts_with(line, "mtllib ")) { char * cur_path = strdup(obj_filename); const char * dir_name = dirname(cur_path); char mtl_basename[LNSZ]; sscanf(line, "mtllib %s", mtl_basename); char mtl_filename[LNSZ]; sprintf(mtl_filename,"%s/%s", dir_name, mtl_basename); mtl_map = load_materials(mtl_filename); if (mtl_map == NULL) { zarray_destroy(vertices); zarray_destroy(normals); return NULL; // XXX cleanup! } free(cur_path); } else { printf("Did not parse: %s\n", line); for (int i = 0; i < strlen(line); i++) { printf("0x%x ", (int)line[i]); } printf("\n"); } } if (1) // useful to enable when compensating for model scale print_bounds(vertices); // Process the model sections in two passes -- first add all the // objects which are not transparent. Then render transparent // objects after vx_object_t * vchain = vxo_chain_create(); zarray_t * sorted_groups = zarray_create(sizeof(wav_group_t*)); for (int i = 0, sz = zarray_size(group_list); i < sz; i++) { wav_group_t * group = NULL; zarray_get(group_list, i, &group); // add to front if solid if (group->material.d == 1.0f) { zarray_insert(sorted_groups, 0, &group); } else { // add to back if transparent zarray_add(sorted_groups, &group); } } int total_triangles = 0; for (int i = 0, sz = zarray_size(sorted_groups); i < sz; i++) { wav_group_t * group = NULL; zarray_get(sorted_groups, i, &group); int ntri = zarray_size(group->group_idx); vx_resc_t * vert_resc = vx_resc_createf(ntri*9); vx_resc_t * norm_resc = vx_resc_createf(ntri*9); for (int j = 0; j < ntri; j++) { tri_idx_t idxs; zarray_get(group->group_idx, j, &idxs); for (int i = 0; i < 3; i++) { zarray_get(vertices, idxs.vIdxs[i]-1, &((float*)vert_resc->res)[9*j + i*3]); zarray_get(normals, idxs.nIdxs[i]-1, &((float*)norm_resc->res)[9*j + i*3]); } } vx_style_t * sty = vxo_mesh_style_fancy(group->material.Ka, group->material.Kd, group->material.Ks, group->material.d, group->material.Ns, group->material.illum); vxo_chain_add(vchain, vxo_mesh(vert_resc, ntri*3, norm_resc, GL_TRIANGLES, sty)); total_triangles += ntri; } //Cleanup: // 1. Materials, names are by reference, but materials are by value zhash_vmap_keys(mtl_map, free); zhash_destroy(mtl_map); // 2. Geometry zarray_destroy(vertices); // stored by value zarray_destroy(normals); // stored by value // 2b wav_group_t are stored by reference zarray_vmap(group_list, wav_group_destroy); zarray_destroy(group_list); zarray_destroy(sorted_groups); // duplicate list, so don't need to free fclose(fp_obj); return vchain; }
void hsv_find_balls_blob_detector(image_u32_t* im, frame_t frame, metrics_t met, zarray_t* blobs_out) { assert(frame.xy0.x < frame.xy1.x && frame.xy0.y < frame.xy1.y); assert(frame.xy0.x >= 0 && frame.xy0.y >= 0 && frame.xy1.x < im->width && frame.xy1.y < im->height); assert(frame.ex0.x < frame.ex1.x && frame.ex0.y < frame.ex1.y); assert(frame.ex0.x >= 0 && frame.ex0.y >= 0 && frame.ex1.x < im->width && frame.ex1.y < im->height); // Int to node zhash_t* node_map = zhash_create(sizeof(uint32_t), sizeof(node_t*), zhash_uint32_hash, zhash_uint32_equals); for(int i = frame.xy0.y; i < frame.xy1.y; i++) { for(int j = frame.xy0.x; j < frame.xy1.x; j++) { if((i < frame.ex0.y || i > frame.ex1.y) || (j < frame.ex0.x || j > frame.ex1.x)) { uint32_t idx_im = i * im->stride + j; // Indframe.ex relative to image // Pixel color data uint32_t abgr = im->buf[idx_im]; hsv_t hsv = {0,0,0}; rgb_to_hsv(abgr, &hsv); hsv_t error = {fabs(hsv.hue - met.hsv.hue), fabs(hsv.sat - met.hsv.sat), fabs(hsv.val - met.hsv.val)}; // 'Acceptable' if((error.hue < met.error.hue) && (error.sat < met.error.sat) && (error.val < met.error.val)) { // Create new node, set itself up as a parent node_t* n = calloc(1, sizeof(node_t)); n->id = idx_im; n->parent_id = idx_im; n->parent_node = n; n->num_children = 0; node_t* tmp_node; uint32_t tmp_idx; // Add node to node map if(zhash_put(node_map, &idx_im, &n, &tmp_idx, &tmp_node)==1) { assert(0); } //Check if apart of another blob, or starting a new blob // if apart of another, point to the parent, if a new blob, point to self //Check neighbours if(!met.lines) { // only check this if don't want lines for tape detection if(j > frame.xy0.x) { tmp_idx = idx_im - 1; // is Left neighbour similar color if(zhash_get(node_map, &tmp_idx, &tmp_node) == 1) { node_t* neighbour = tmp_node; connect(n, neighbour); } } } if(i > frame.xy0.y) { tmp_idx = idx_im - im->stride; // is Bottom neighbor similar color if(tmp_idx > 0 && zhash_get(node_map, &tmp_idx, &tmp_node) == 1) { node_t* neighbour = tmp_node; connect(neighbour,n); } } } } } } //count number of children for each parent, go through node_map // if a node is not a parent, add 1 to it's parent->num_children and delete from hash // if is a parent do nothing zarray_t* vals = zhash_values(node_map); for(int i = 0; i < zarray_size(vals); i++) { node_t* node; zarray_get(vals, i, &node); resolve_r(node); if(node->parent_id != node->id) { node->parent_node->num_children++; // key should exist, if it doesn't find out why assert(zhash_remove(node_map, &node->id, NULL, NULL)); } } // search parent only hash and add to blobs out conditionally vals = zhash_values(node_map); for(int i = 0; i < zarray_size(vals); i++) { node_t* node; zarray_get(vals, i, &node); if(node->num_children > met.min_size) { loc_t pos; pos.x = node->parent_id%im->stride; pos.y = node->parent_id/im->stride; zarray_add(blobs_out, &pos); // printf("parent %d\n", node->id); } } zarray_destroy(vals); zhash_vmap_values(node_map, free); zhash_destroy(node_map); }
zarray_t *apriltag_quad_thresh(apriltag_detector_t *td, image_u8_t *im) { //////////////////////////////////////////////////////// // step 1. threshold the image, creating the edge image. int w = im->width, h = im->height, s = im->stride; image_u8_t *threshim = threshold(td, im); assert(threshim->stride == s); image_u8_t *edgeim = image_u8_create(w, h); if (1) { image_u8_t *sumim = image_u8_create(w, h); // apply a horizontal sum kernel of width 3 for (int y = 0; y < h; y++) { for (int x = 1; x+1 < w; x++) { sumim->buf[y*s + x] = threshim->buf[y*s + x - 1] + threshim->buf[y*s + x + 0] + threshim->buf[y*s + x + 1]; } } timeprofile_stamp(td->tp, "sumim"); // deglitch if (td->qtp.deglitch) { for (int y = 1; y+1 < h; y++) { for (int x = 1; x+1 < w; x++) { // edge: black pixel next to white pixel if (threshim->buf[y*s + x] == 0 && sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] == 8) { threshim->buf[y*s + x] = 1; sumim->buf[y*s + x - 1]++; sumim->buf[y*s + x + 0]++; sumim->buf[y*s + x + 1]++; } if (threshim->buf[y*s + x] == 1 && sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] == 1) { threshim->buf[y*s + x] = 0; sumim->buf[y*s + x - 1]--; sumim->buf[y*s + x + 0]--; sumim->buf[y*s + x + 1]--; } } } timeprofile_stamp(td->tp, "deglitch"); } // apply a vertical sum kernel of width 3; check if any // over-threshold pixels are adjacent to an under-threshold // pixel. // // There are two types of edges: white pixels neighboring a // black pixel, and black pixels neighboring a white pixel. We // label these separately. (Values 0xc0 and 0x3f are picked // such that they add to 255 (see below) and so that they can be // viewed as pixel intensities for visualization purposes.) // // symmetry of detection. We don't want to use JUST "black // near white" (or JUST "white near black"), because that // biases the detection towards one side of the edge. This // measurably reduces detection performance. // // On large tags, we could treat "neighbor" pixels the same // way. But on very small tags, there may be other edges very // near the tag edge. Since each of these edges is effectively // two pixels thick (the white pixel near the black pixel, and // the black pixel near the white pixel), it becomes likely // that these two nearby edges will actually touch. // // A partial solution to this problem is to define edges to be // adjacent white-near-black and black-near-white pixels. // for (int y = 1; y+1 < h; y++) { for (int x = 1; x+1 < w; x++) { if (threshim->buf[y*s + x] == 0) { // edge: black pixel next to white pixel if (sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] > 0) edgeim->buf[y*s + x] = 0xc0; } else { // edge: white pixel next to black pixel when both // edge types are on, we get less bias towards one // side of the edge. if (sumim->buf[y*s + x - s] + sumim->buf[y*s + x] + sumim->buf[y*s + x + s] < 9) edgeim->buf[y*s + x] = 0x3f; } } } if (td->debug) { for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { threshim->buf[y*s + x] *= 255; } } image_u8_write_pnm(threshim, "debug_threshold.pnm"); image_u8_write_pnm(edgeim, "debug_edge.pnm"); // image_u8_destroy(edgeim2); } image_u8_destroy(threshim); image_u8_destroy(sumim); } timeprofile_stamp(td->tp, "edges"); //////////////////////////////////////////////////////// // step 2. find connected components. unionfind_t *uf = unionfind_create(w * h); for (int y = 1; y < h - 1; y++) { for (int x = 1; x < w -1; x++) { uint8_t v = edgeim->buf[y*s + x]; if (v==0) continue; // (dx,dy) pairs for 8 connectivity: // (REFERENCE) (1, 0) // (-1, 1) (0, 1) (1, 1) // // i.e., the minimum value of dx should be: // y=0: 1 // y=1: -1 for (int dy = 0; dy <= 1; dy++) { for (int dx = 1-2*dy; dx <= 1; dx++) { if (edgeim->buf[(y+dy)*s + (x+dx)] == v) { unionfind_connect(uf, y*w + x, (y+dy)*w + x + dx); } } } } } timeprofile_stamp(td->tp, "unionfind"); zhash_t *clustermap = zhash_create(sizeof(uint64_t), sizeof(zarray_t*), zhash_uint64_hash, zhash_uint64_equals); for (int y = 1; y < h-1; y++) { for (int x = 1; x < w-1; x++) { uint8_t v0 = edgeim->buf[y*s + x]; if (v0 == 0) continue; uint64_t rep0 = unionfind_get_representative(uf, y*w + x); // 8 connectivity. (4 neighbors to check). // for (int dy = 0; dy <= 1; dy++) { // for (int dx = 1-2*dy; dx <= 1; dx++) { // 4 connectivity. (2 neighbors to check) for (int n = 1; n <= 2; n++) { int dy = n & 1; int dx = (n & 2) >> 1; uint8_t v1 = edgeim->buf[(y+dy)*s + x + dx]; if (v0 + v1 != 255) continue; uint64_t rep1 = unionfind_get_representative(uf, (y+dy)*w + x+dx); uint64_t clusterid; if (rep0 < rep1) clusterid = (rep1 << 32) + rep0; else clusterid = (rep0 << 32) + rep1; zarray_t *cluster = NULL; if (!zhash_get(clustermap, &clusterid, &cluster)) { cluster = zarray_create(sizeof(struct pt)); zhash_put(clustermap, &clusterid, &cluster, NULL, NULL); } // NB: We will add some points multiple times to a // given cluster. I don't know an efficient way to // avoid that here; we remove them later on when we // sort points by pt_compare_theta. if (1) { struct pt p = { .x = x, .y = y}; zarray_add(cluster, &p); } if (1) { struct pt p = { .x = x+dx, .y = y+dy}; zarray_add(cluster, &p); } } } } // make segmentation image. if (td->debug) { image_u8_t *d = image_u8_create(w, h); assert(d->stride == s); uint8_t *colors = (uint8_t*) calloc(w*h, 1); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { uint32_t v = unionfind_get_representative(uf, y*w+x); uint32_t sz = unionfind_get_set_size(uf, y*w+x); if (sz < td->qtp.min_cluster_pixels) continue; uint8_t color = colors[v]; if (color == 0) { const int bias = 20; color = bias + (random() % (255-bias)); colors[v] = color; } float mix = 0.7; mix = 1.0; d->buf[y*d->stride + x] = mix*color + (1-mix)*im->buf[y*im->stride + x]; } } free(colors); image_u8_write_pnm(d, "debug_segmentation.pnm"); image_u8_destroy(d); } timeprofile_stamp(td->tp, "make clusters"); //////////////////////////////////////////////////////// // step 3. process each connected component. zarray_t *clusters = zhash_values(clustermap); zhash_destroy(clustermap); zarray_t *quads = zarray_create(sizeof(struct quad)); int sz = zarray_size(clusters); int chunksize = 1 + sz / (APRILTAG_TASKS_PER_THREAD_TARGET * td->nthreads); struct quad_task tasks[sz / chunksize + 1]; int ntasks = 0; for (int i = 0; i < sz; i += chunksize) { tasks[ntasks].td = td; tasks[ntasks].cidx0 = i; tasks[ntasks].cidx1 = imin(sz, i + chunksize); tasks[ntasks].h = h; tasks[ntasks].w = w; tasks[ntasks].quads = quads; tasks[ntasks].clusters = clusters; tasks[ntasks].im = im; workerpool_add_task(td->wp, do_quad_task, &tasks[ntasks]); ntasks++; } workerpool_run(td->wp); timeprofile_stamp(td->tp, "fit quads to clusters"); if (td->debug) { FILE *f = fopen("debug_lines.ps", "w"); fprintf(f, "%%!PS\n\n"); image_u8_t *im2 = image_u8_copy(im); image_u8_darken(im2); image_u8_darken(im2); // assume letter, which is 612x792 points. double scale = fmin(612.0/im->width, 792.0/im2->height); fprintf(f, "%.15f %.15f scale\n", scale, scale); fprintf(f, "0 %d translate\n", im2->height); fprintf(f, "1 -1 scale\n"); postscript_image(f, im); for (int i = 0; i < zarray_size(quads); i++) { struct quad *q; zarray_get_volatile(quads, i, &q); float rgb[3]; int bias = 100; for (int i = 0; i < 3; i++) rgb[i] = bias + (random() % (255-bias)); fprintf(f, "%f %f %f setrgbcolor\n", rgb[0]/255.0f, rgb[1]/255.0f, rgb[2]/255.0f); fprintf(f, "%.15f %.15f moveto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto %.15f %.15f lineto stroke\n", q->p[0][0], q->p[0][1], q->p[1][0], q->p[1][1], q->p[2][0], q->p[2][1], q->p[3][0], q->p[3][1], q->p[0][0], q->p[0][1]); } fclose(f); } // printf(" %d %d %d %d\n", indices[0], indices[1], indices[2], indices[3]); /* if (td->debug) { for (int i = 0; i < 4; i++) { int i0 = indices[i]; int i1 = indices[(i+1)&3]; if (i1 < i0) i1 += zarray_size(cluster); for (int j = i0; j <= i1; j++) { struct pt *p; zarray_get_volatile(cluster, j % zarray_size(cluster), &p); edgeim->buf[p->y*edgeim->stride + p->x] = 30+64*i; } } } */ unionfind_destroy(uf); for (int i = 0; i < zarray_size(clusters); i++) { zarray_t *cluster; zarray_get(clusters, i, &cluster); zarray_destroy(cluster); } zarray_destroy(clusters); image_u8_destroy(edgeim); return quads; }
int vx_gtk_display_dispatch_mouse(vx_display_t * disp, vx_mouse_event_t *event) { assert(disp->impl_type == VX_GTK_DISPLAY_IMPL); state_t * state = disp->impl; pthread_mutex_lock(&state->mutex); render_info_t * rinfo = state->last_render_info; if (rinfo == NULL) { pthread_mutex_unlock(&state->mutex); return 1; } {// Make a copy of the event, whose memory we will manage vx_mouse_event_t * tmp = event; event = malloc(sizeof(vx_mouse_event_t)); memcpy(event, tmp, sizeof(vx_mouse_event_t)); } // Determine which layer is focused: vx_mouse_event_t * last_event = state->last_mouse_event; state->last_mouse_event = event; if (!last_event ) { //XXX what to do here? (first time) pthread_mutex_unlock(&state->mutex); return 1; } uint32_t bdiff = event->button_mask ^ last_event->button_mask; free(last_event); // 1 Each time the mouse is pushed down, the layer_id is set to the layer under the mouse // 2 if the mouse is not pushed down, the layer under the mouse is selected int layer_under_mouse_id = pick_layer(rinfo, event->x, event->y); if (layer_under_mouse_id == 0) { pthread_mutex_unlock(&state->mutex); return 1; // there may be no layers } int button_clicked = bdiff && (bdiff & event->button_mask); int button_down = event->button_mask; if (!button_clicked && button_down) { // leave the layer id as is } else if (layer_under_mouse_id != 0){ state->mouse_pressed_layer_id = layer_under_mouse_id; } else { // no mouse under layer -- don't change the id? } int mouse_pressed_layer_id = state->mouse_pressed_layer_id; //local copy vx_camera_pos_t * mouse_pressed_layer_pos_orig = NULL; zhash_get(rinfo->camera_positions, &mouse_pressed_layer_id, &mouse_pressed_layer_pos_orig); vx_camera_pos_t * mouse_pressed_layer_pos = calloc(1,sizeof(vx_camera_pos_t)); // local copy memcpy(mouse_pressed_layer_pos,mouse_pressed_layer_pos_orig, sizeof(vx_camera_pos_t)); // Also dispatch to the relevant layers camera manager { layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &mouse_pressed_layer_id, &linfo); if (linfo != NULL) // sometimes there could be no layers linfo->event_handler->mouse_event(linfo->event_handler, NULL, mouse_pressed_layer_pos, event); } pthread_mutex_unlock(&state->mutex); pthread_mutex_lock(&state->listener_mutex); // notify all listeners of this event for (int i = 0; i < zarray_size(state->listeners); i++) { vx_display_listener_t * l = NULL; zarray_get(state->listeners, i, &l); l->event_dispatch_mouse(l, mouse_pressed_layer_id, mouse_pressed_layer_pos, event); } pthread_mutex_unlock(&state->listener_mutex); free(mouse_pressed_layer_pos); return 1; //gobble all events }
void vx_gtk_display_show_context_menu(vx_display_t * disp, vx_mouse_event_t * event) { state_t * state = disp->impl; vx_camera_pos_t layer_cam_pos; pthread_mutex_lock(&state->mutex); state->popup_layer_id = pick_layer(state->last_render_info, event->x, event->y); vx_camera_pos_t * pos = NULL; zhash_get(state->last_render_info->camera_positions, &state->popup_layer_id, &pos); if (pos != NULL) memcpy(&layer_cam_pos, pos, sizeof(vx_camera_pos_t)); pthread_mutex_unlock(&state->mutex); if (state->popup_layer_id == 0) return; layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &state->popup_layer_id, &linfo); GtkWidget * menu = gtk_menu_new(); // Camera buttons { GtkWidget * labelwrapper = gtk_menu_item_new(); GtkWidget * label = gtk_label_new("Foo"); gtk_label_set_markup(GTK_LABEL(label), "<b>Camera options</b>"); gtk_container_add(GTK_CONTAINER(labelwrapper), label); // Auto centers? I guess that's fine gtk_menu_shell_append(GTK_MENU_SHELL(menu), labelwrapper); GtkWidget * resetCam = gtk_menu_item_new_with_label("Reset Camera"); g_signal_connect(resetCam, "activate", (GCallback) menu_action_reset_camera, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), resetCam); GtkWidget * button1 = gtk_check_menu_item_new_with_label ("Perspective projection"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), button1); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(button1), 1); GtkWidget * button2 = gtk_check_menu_item_new_with_label ("Orthographic projection"); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(button2), 1); gtk_menu_shell_append(GTK_MENU_SHELL(menu), button2); gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (layer_cam_pos.perspectiveness == 1.0 ? button1 : button2), TRUE); g_signal_connect(button1, "activate", (GCallback) menu_action_perspective, state); g_signal_connect(button2, "activate", (GCallback) menu_action_ortho, state); // Interface modes GtkWidget * iface_wrapper = gtk_menu_item_new_with_label("Interface mode"); gtk_menu_shell_append(GTK_MENU_SHELL(menu), iface_wrapper); { GtkWidget * iface_menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(iface_wrapper), iface_menu); GtkWidget * iface_20d = gtk_check_menu_item_new_with_label("2.0D"); gtk_menu_shell_append(GTK_MENU_SHELL(iface_menu), iface_20d); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(iface_20d), 1); GtkWidget * iface_25d = gtk_check_menu_item_new_with_label("2.5D"); gtk_menu_shell_append(GTK_MENU_SHELL(iface_menu), iface_25d); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(iface_25d), 1); GtkWidget * iface_30d = gtk_check_menu_item_new_with_label("3.0D"); gtk_menu_shell_append(GTK_MENU_SHELL(iface_menu), iface_30d); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(iface_30d), 1); float iface = default_cam_mgr_get_interface_mode(linfo->cam_mgr); GtkWidget * active = NULL; if (iface == 2.0f) { active = iface_20d; } else if (iface == 2.5f) { active = iface_25d; } else if (iface == 3.0f) { active = iface_30d; } else { printf("WRN: iface mode %f not supported by menu!\n", iface); active = iface_25d; } gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (active), TRUE); g_signal_connect(iface_20d, "activate", (GCallback) menu_action_iface_20d, state); g_signal_connect(iface_25d, "activate", (GCallback) menu_action_iface_25d, state); g_signal_connect(iface_30d, "activate", (GCallback) menu_action_iface_30d, state); } } { GtkWidget * labelwrapper = gtk_menu_item_new(); GtkWidget * label = gtk_label_new("Foo"); gtk_label_set_markup(GTK_LABEL(label), "<b>Display Options</b>"); gtk_container_add(GTK_CONTAINER(labelwrapper), label); // Auto centers? I guess that's fine gtk_menu_shell_append(GTK_MENU_SHELL(menu), labelwrapper); GtkWidget * showBM = gtk_menu_item_new_with_label("Show Buffer/Layer Manager"); g_signal_connect(showBM, "activate",(GCallback) menu_action_buffer_manager, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), showBM); GtkWidget * scene = gtk_menu_item_new_with_label("Save Vx Scene"); g_signal_connect(scene, "activate",(GCallback) menu_action_scene, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), scene); GtkWidget * shot = gtk_menu_item_new_with_label("Save Screenshot"); g_signal_connect(shot, "activate",(GCallback) menu_action_screen_shot, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), shot); if (state->movie_file == NULL) { GtkWidget * movie = gtk_menu_item_new_with_label("Record movie"); g_signal_connect(movie, "activate",(GCallback) menu_action_record_movie, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), movie); } else { GtkWidget * movie = gtk_menu_item_new_with_label("Stop movie"); g_signal_connect(movie, "activate",(GCallback) menu_action_stop_movie, state); gtk_menu_shell_append(GTK_MENU_SHELL(menu), movie); } } gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, /* (event != NULL) ? event->button : 0, */ 0, gtk_get_current_event_time()); //gdk_event_get_time((GdkEvent*)event)); }
void process_camera_codes(state_t * state, vx_code_input_stream_t * cins) { int layer_id = cins->read_uint32(cins); int op = cins->read_uint32(cins); layer_info_t * linfo = NULL; zhash_get(state->layer_info_map, &layer_id, &linfo); if (linfo == NULL) return; uint64_t mtime; vx_camera_pos_t * cur_pos; if (verbose) printf("Op %d remaining %d\n",op, vx_code_input_stream_available(cins)); double eyedf[3]; double lookatdf[3]; double updf[3]; double xy0[2]; double xy1[2]; switch(op) { case OP_DEFAULTS: default_cam_mgr_defaults(linfo->cam_mgr, UI_ANIMATE_MS); break; case OP_PROJ_PERSPECTIVE: case OP_PROJ_ORTHO: cur_pos = default_cam_mgr_get_cam_target(linfo->cam_mgr,&mtime); cur_pos->perspectiveness = op == OP_PROJ_ORTHO ? 0.0f : 1.0f; default_cam_mgr_set_cam_pos(linfo->cam_mgr, cur_pos, 0, 0); vx_camera_pos_destroy(cur_pos); break; case OP_LOOKAT: eyedf[0] = cins->read_float(cins); eyedf[1] = cins->read_float(cins); eyedf[2] = cins->read_float(cins); lookatdf[0] = cins->read_float(cins); lookatdf[1] = cins->read_float(cins); lookatdf[2] = cins->read_float(cins); updf[0] = cins->read_float(cins); updf[1] = cins->read_float(cins); updf[2] = cins->read_float(cins); mtime = cins->read_uint32(cins); // animate ms ignored! XXX default_cam_mgr_lookat(linfo->cam_mgr, eyedf, lookatdf, updf, cins->read_uint8(cins), mtime); break; case OP_FIT2D: xy0[0] = cins->read_float(cins); xy0[1] = cins->read_float(cins); xy1[0] = cins->read_float(cins); xy1[1] = cins->read_float(cins); mtime = cins->read_uint32(cins); // animate ms ignored! XXX default_cam_mgr_fit2D(linfo->cam_mgr, xy0, xy1, cins->read_uint8(cins), mtime); break; case OP_FOLLOW_MODE_DISABLE: default_cam_mgr_follow_disable(linfo->cam_mgr); break; case OP_INTERFACE_MODE: { float mode = cins->read_float(cins); default_cam_mgr_set_interface_mode(linfo->cam_mgr, mode); } } if (op == OP_FOLLOW_MODE) { double pos3[3]; double quat4[4]; pos3[0] = cins->read_double(cins); pos3[1] = cins->read_double(cins); pos3[2] = cins->read_double(cins); quat4[0] = cins->read_double(cins); quat4[1] = cins->read_double(cins); quat4[2] = cins->read_double(cins); quat4[3] = cins->read_double(cins); int followYaw = cins->read_uint32(cins); uint32_t animate_ms = cins->read_uint32(cins); default_cam_mgr_follow(linfo->cam_mgr, pos3, quat4, followYaw, animate_ms); } }
static void save_scene(state_t * state, vx_code_input_stream_t * cins) { char * filename = NULL; if (vx_code_input_stream_available(cins) > 0) { const char * f2 = cins->read_str(cins); filename = strdup(f2); } else { // generate a unique ID uint64_t mtime = vx_mtime(); time_t now = time(NULL); struct tm * now2 = localtime(&now); filename=sprintf_alloc("v%4d%02d%02d_%02d%02d%02d_%03d.vxs", now2->tm_year + 1900, now2->tm_mon + 1, now2->tm_mday, now2->tm_hour, now2->tm_min, now2->tm_sec, (int)(mtime % 1000)); } vx_code_output_stream_t * couts = vx_gl_renderer_serialize(state->glrend); // Append camera positions if (state->last_render_info != NULL) { render_info_t *rinfo = state->last_render_info; for (int i = 0; i <4; i++) couts->write_uint32(couts, rinfo->viewport[i]); couts->write_uint32(couts, zarray_size(rinfo->layers)); for (int i = 0; i < zarray_size(rinfo->layers); i++) { layer_info_t * linfo = NULL; zarray_get(rinfo->layers, i, &linfo); couts->write_uint32(couts, linfo->layer_id); vx_camera_pos_t * pos = NULL; int * viewport = NULL; zhash_get(rinfo->camera_positions, &linfo->layer_id, &pos); zhash_get(rinfo->layer_positions, &linfo->layer_id, &viewport); vx_tcp_util_pack_camera_pos(pos, couts); for (int i = 0; i < 4; i++) couts->write_uint32(couts, viewport[i]); } } FILE * fp = fopen(filename, "w"); fwrite(couts->data, sizeof(uint8_t), couts->pos, fp); fclose(fp); printf("Wrote %d bytes to %s\n", couts->pos, filename); vx_code_output_stream_destroy(couts); free(filename); }
// Pass in a codes describing which resources are no longer in use. Decrement user counts, // and return a list of all resources whos counts have reached zero, which therefore // should be deleted from the display using a OP_DEALLOC_RESOURCES opcode void vx_resc_manager_buffer_resources(vx_resc_manager_t * mgr, const uint8_t * data, int datalen) { if (0) print_manager(mgr); vx_code_input_stream_t * cins = vx_code_input_stream_create(data, datalen); int code = cins->read_uint32(cins); assert(code == OP_BUFFER_RESOURCES); int worldID = cins->read_uint32(cins); char * name = strdup(cins->read_str(cins)); //freed when cur_resources is eventually removed from the buffer map int count = cins->read_uint32(cins); zhash_t * cur_resources = zhash_create(sizeof(uint64_t), sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals); vx_resc_t * vr = NULL; for (int i = 0; i < count; i++) { uint64_t id = cins->read_uint64(cins); zhash_put(cur_resources, &id, &vr, NULL, NULL); } assert(cins->pos == cins->len); // we've emptied the stream vx_code_input_stream_destroy(cins); // 1 Update our records zhash_t * worldBuffers = NULL; zhash_get(mgr->allLiveSets, &worldID, &worldBuffers); if (worldBuffers == NULL) { worldBuffers = zhash_create(sizeof(char*), sizeof(zhash_t*), zhash_str_hash, zhash_str_equals); zhash_put(mgr->allLiveSets, &worldID, &worldBuffers, NULL, NULL); } zhash_t * old_resources = NULL; char * old_name = NULL; zhash_put(worldBuffers, &name, &cur_resources, &old_name, &old_resources); free(old_name); // 2 Figure out which resources have become unused: if(old_resources != NULL) { removeAll(old_resources, cur_resources); zarray_t * dealloc = zarray_create(sizeof(uint64_t)); // now 'old_resources' contains only the resources that are no longer referenced // iterate through each one, and see if there is a buffer somewhere that references it zhash_iterator_t prev_itr; zhash_iterator_init(old_resources, &prev_itr); uint64_t id = -1; vx_resc_t * vr = NULL; while(zhash_iterator_next(&prev_itr, &id, &vr)) { // Check all worlds zhash_iterator_t world_itr;// gives us all worlds zhash_iterator_init(mgr->allLiveSets, &world_itr); uint32_t wIDl = -1; zhash_t * buffer_map = NULL; while(zhash_iterator_next(&world_itr, &wIDl, &buffer_map)) { zhash_iterator_t buffer_itr; // gives us all buffers zhash_iterator_init(buffer_map, &buffer_itr); char * bName = NULL; zhash_t * resc_map = NULL; while(zhash_iterator_next(&buffer_itr, &bName, &resc_map)) { if (zhash_contains(resc_map, &id)) { goto continue_outer_loop; } } } // If none of the worlds have this resource, we need to flag removal zarray_add(dealloc, &id); continue_outer_loop: ; } // 3 Issue dealloc commands if (zarray_size(dealloc) > 0) { vx_code_output_stream_t * couts = vx_code_output_stream_create(512); couts->write_uint32(couts, OP_DEALLOC_RESOURCES); couts->write_uint32(couts, zarray_size(dealloc)); for (int i = 0; i < zarray_size(dealloc); i++) { uint64_t id = 0; zarray_get(dealloc, i, &id); couts->write_uint64(couts, id); } mgr->disp->send_codes(mgr->disp, couts->data, couts->pos); vx_code_output_stream_destroy(couts); // Also remove the resources we deallocated from remoteResc for (int i = 0; i < zarray_size(dealloc); i++) { uint64_t id = 0; zarray_get(dealloc, i, &id); assert(zhash_contains(mgr->remoteResc, &id)); zhash_remove(mgr->remoteResc, &id, NULL, NULL); } } zarray_destroy(dealloc); zhash_destroy(old_resources); } if (0) { print_manager(mgr); printf("\n\n"); } }
static void * run_process(void * data) { vx_world_t * world = data; while (world->process_running) { vx_world_listener_t * listener = NULL; char * buffer_name = NULL; // 1) Wait until there's data pthread_mutex_lock(&world->queue_mutex); while (zarray_size(world->buffer_queue) == 0 && zarray_size(world->listener_queue) == 0 && world->process_running) { pthread_cond_wait(&world->queue_cond, &world->queue_mutex); } if (!world->process_running) { // XXX cleaning out the queue? pthread_mutex_unlock(&world->queue_mutex); break; } // Processing new listeners takes priority if ( zarray_size(world->listener_queue) > 0) { zarray_get(world->listener_queue, 0, &listener); zarray_remove_index(world->listener_queue, 0, 0); } else { assert(zarray_size(world->buffer_queue) > 0); zarray_get(world->buffer_queue, 0, &buffer_name); zarray_remove_index(world->buffer_queue, 0, 0); } pthread_mutex_unlock(&world->queue_mutex); // Operation A: New listener if (listener != NULL) { // re-transmit each buffer that has already been serialized pthread_mutex_lock(&world->buffer_mutex); zhash_iterator_t itr; zhash_iterator_init(world->buffer_map, &itr); char * name = NULL; vx_buffer_t * buffer = NULL; while(zhash_iterator_next(&itr, &name, &buffer)) { if (buffer->front_codes->pos != 0) { vx_code_output_stream_t * bresc_codes = make_buffer_resource_codes(buffer, buffer->front_resc); // Doing a swap in 3 steps (instead of 4) like this // is only safe if the listener is brand new, which we are // guaranteed is the case in this chunk of code listener->send_codes(listener, bresc_codes->data, bresc_codes->pos); listener->send_resources(listener, buffer->front_resc); listener->send_codes(listener, buffer->front_codes->data, buffer->front_codes->pos); vx_code_output_stream_destroy(bresc_codes); } } pthread_mutex_unlock(&world->buffer_mutex); } // Operation B: buffer swap if (buffer_name != NULL) { vx_buffer_t * buffer = NULL; pthread_mutex_lock(&world->buffer_mutex); zhash_get(world->buffer_map, &buffer_name, &buffer); pthread_mutex_unlock(&world->buffer_mutex); delayed_swap(buffer); } } pthread_exit(NULL); }