static void vx_world_buffer_destroy(vx_buffer_t * buffer) { vx_world_t * vw = buffer->world; pthread_mutex_lock(&vw->buffer_mutex); free(buffer->name); zarray_vmap(buffer->back_objs, vx_object_dec_destroy); zarray_destroy(buffer->back_objs); zarray_vmap(buffer->pending_objs, vx_object_dec_destroy); zarray_destroy(buffer->pending_objs); zarray_vmap(buffer->front_objs, vx_object_dec_destroy); zarray_destroy(buffer->front_objs); zhash_vmap_values(buffer->front_resc, vx_resc_dec_destroy); zhash_destroy(buffer->front_resc); vx_code_output_stream_destroy(buffer->front_codes); pthread_mutex_destroy(&buffer->mutex); free(buffer); pthread_mutex_unlock(&vw->buffer_mutex); }
void url_parser_destroy (url_parser_t *urlp) { free(urlp->protocol); free(urlp->host); free(urlp->path); zarray_vmap(urlp->keys, free); zarray_vmap(urlp->vals, free); zarray_destroy(urlp->keys); zarray_destroy(urlp->vals); free(urlp); }
void vx_util_unproject(double * winxyz, double * model_matrix, double * projection_matrix, int * viewport, double * vec3_out) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * mm = matd_create_data(4, 4, model_matrix); zarray_add(fp, &mm); matd_t * pm = matd_create_data(4, 4, projection_matrix); zarray_add(fp, &pm); matd_t *invpm = matd_op("(MM)^-1", pm, mm); zarray_add(fp, &invpm); double v[4] = { 2*(winxyz[0]-viewport[0]) / viewport[2] - 1, 2*(winxyz[1]-viewport[1]) / viewport[3] - 1, 2*winxyz[2] - 1, 1 }; matd_t * vm = matd_create_data(4, 1, v); zarray_add(fp, &vm); matd_t * objxyzh = matd_op("MM", invpm, vm); zarray_add(fp, &objxyzh); vec3_out[0] = objxyzh->data[0] / objxyzh->data[3]; vec3_out[1] = objxyzh->data[1] / objxyzh->data[3]; vec3_out[2] = objxyzh->data[2] / objxyzh->data[3]; // cleanup zarray_vmap(fp, matd_destroy); zarray_destroy(fp); }
void vx_util_project(double * xyz, double * M44, double * P44, int * viewport, double * win_out3) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * M = matd_create_data(4,4, M44); zarray_add(fp, &M); matd_t * P = matd_create_data(4,4, P44); zarray_add(fp, &P); matd_t * xyzp = matd_create(4,1); zarray_add(fp, &xyzp); memcpy(xyzp->data, xyz, 3*sizeof(double)); xyzp->data[3] = 1.0; matd_t * p = matd_op("MMM", P, M, xyzp); zarray_add(fp, &p); p->data[0] = p->data[0] / p->data[3]; p->data[1] = p->data[1] / p->data[3]; p->data[2] = p->data[2] / p->data[3]; double res[] = { viewport[0] + viewport[2]*(p->data[0]+1)/2.0, viewport[1] + viewport[3]*(p->data[1]+1)/2.0, (viewport[2] + 1)/2.0 }; memcpy(win_out3, res, 3*sizeof(double)); // cleanup zarray_vmap(fp, matd_destroy); zarray_destroy(fp); }
void default_cam_mgr_rotate(default_cam_mgr_t * state, double *q, uint32_t animate_ms) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * eye = matd_create_data(3,1,state->eye1); zarray_add(fp, &eye); matd_t *lookat = matd_create_data(3,1,state->lookat1); zarray_add(fp, &lookat); matd_t *up = matd_create_data(3,1,state->up1); zarray_add(fp, &up); matd_t * toEye = matd_subtract(eye, lookat); zarray_add(fp, &toEye); matd_t * nextToEye = matd_create(3,1); zarray_add(fp, &nextToEye); vx_util_quat_rotate(q, toEye->data, nextToEye->data); matd_t * nextEye = matd_add(lookat, nextToEye); zarray_add(fp, &nextEye); matd_t * nextUp = matd_copy(up); zarray_add(fp, &nextUp); vx_util_quat_rotate(q, up->data, nextUp->data); // copy back results memcpy(state->eye1, nextEye->data, sizeof(double)*3); memcpy(state->up1, nextUp->data, sizeof(double)*3); state->mtime1 = vx_util_mtime() + animate_ms; // Disable any prior fit command default_destroy_fit(state); // cleanup zarray_vmap(fp, matd_destroy); zarray_destroy(fp); default_cam_mgr_follow_disable(state); }
void getopt_destroy (getopt_t *gopt) { // free the extra arguments and container zarray_vmap (gopt->extraargs, free); zarray_destroy (gopt->extraargs); // deep free of the getopt_option structs. Also frees key/values, so // after this loop, hash tables will no longer work zarray_vmap (gopt->options, getopt_option_destroy); zarray_destroy (gopt->options); // free tables zhash_destroy (gopt->lopts); zhash_destroy (gopt->sopts); free (gopt); }
void vx_util_lookat(double * _eye, double * _lookat, double * _up, double * _out44) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * eye = matd_create_data(3,1, _eye); zarray_add(fp, &eye); matd_t * lookat = matd_create_data(3,1, _lookat); zarray_add(fp, &lookat); matd_t * up = matd_create_data(3,1, _up); zarray_add(fp, &up); up = matd_vec_normalize(up); zarray_add(fp, &up); // note different pointer than before! matd_t * tmp1 = matd_subtract(lookat, eye); zarray_add(fp, &tmp1); matd_t * f = matd_vec_normalize(tmp1); zarray_add(fp, &f); matd_t * s = matd_crossproduct(f, up); zarray_add(fp, &s); matd_t * u = matd_crossproduct(s, f); zarray_add(fp, &u); matd_t * M = matd_create(4,4); // set the rows of M with s, u, -f zarray_add(fp, &M); memcpy(M->data,s->data,3*sizeof(double)); memcpy(M->data + 4,u->data,3*sizeof(double)); memcpy(M->data + 8,f->data,3*sizeof(double)); for (int i = 0; i < 3; i++) M->data[2*4 +i] *= -1; M->data[3*4 + 3] = 1.0; matd_t * T = matd_create(4,4); T->data[0*4 + 3] = -eye->data[0]; T->data[1*4 + 3] = -eye->data[1]; T->data[2*4 + 3] = -eye->data[2]; T->data[0*4 + 0] = 1; T->data[1*4 + 1] = 1; T->data[2*4 + 2] = 1; T->data[3*4 + 3] = 1; zarray_add(fp, &T); matd_t * MT = matd_op("MM",M,T); zarray_add(fp, &MT); memcpy(_out44, MT->data, 16*sizeof(double)); // cleanup zarray_vmap(fp, matd_destroy); zarray_destroy(fp); }
// Do a quick swap: void vx_buffer_swap(vx_buffer_t * buffer) { pthread_mutex_lock(&buffer->mutex); { // It's possible that the serialization is running behind, // and may not have already serialized the pending_objs // In that case, they are discarded here, momentarily blocking // the calling thread. if (zarray_size(buffer->pending_objs) > 0) { // *+*+ corresponding decrement (if falling behind) zarray_vmap(buffer->pending_objs, vx_object_dec_destroy); zarray_clear(buffer->pending_objs); static int once = 1; if (once) { once = 0; printf("NFO: World serialization fell behind\n"); } } // swap zarray_t * tmp = buffer->pending_objs; buffer->pending_objs = buffer->back_objs; buffer->back_objs = tmp; } pthread_mutex_unlock(&buffer->mutex); // Now flag a swap on the serialization thread pthread_mutex_lock(&buffer->world->queue_mutex); { // Ensure that the string is already in the queue, or add it if // it isn't. Duplicates are prohibited int index = -1; for (int i = 0, sz = zarray_size(buffer->world->buffer_queue); i < sz; i++) { char * test = NULL; zarray_get(buffer->world->buffer_queue, i, &test); if (strcmp(test, buffer->name) == 0) { index = i; break; } } if (index < 0) { zarray_add(buffer->world->buffer_queue, &buffer->name); pthread_cond_signal(&buffer->world->queue_cond); } } pthread_mutex_unlock(&buffer->world->queue_mutex); }
void vx_util_angle_axis_to_quat(double theta, double * axis3, double * qout) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * axis = matd_create_data(3,1, axis3); zarray_add(fp, &axis); matd_t * axis_norm = matd_vec_normalize(axis); zarray_add(fp, &axis_norm); qout[0] = cos(theta/2); double s = sin(theta/2); qout[1] = axis_norm->data[0] * s; qout[2] = axis_norm->data[1] * s; qout[3] = axis_norm->data[2] * s; // cleanup zarray_vmap(fp, matd_destroy); zarray_destroy(fp); }
vx_camera_pos_t * default_cam_mgr_get_cam_pos(default_cam_mgr_t * state, int * viewport, uint64_t mtime) { vx_camera_pos_t * p = calloc(1, sizeof(vx_camera_pos_t)); memcpy(p->viewport, viewport, 4*sizeof(int)); p->perspective_fovy_degrees = state->perspective_fovy_degrees; p->zclip_near = state->zclip_near; p->zclip_far = state->zclip_far; // process a fit command if necessary: if (state->fit != NULL) { fit_t * f = state->fit; // consume the fit command state->fit = NULL; // XXX minor race condition, could lose a fit cmd // XXX We can probably do better than this using the viewport... state->lookat1[0] = (f->xy0[0] + f->xy1[0]) / 2; state->lookat1[1] = (f->xy0[1] + f->xy1[1]) / 2; state->lookat1[2] = 0; // dimensions of fit double Fw = f->xy1[0] - f->xy0[0]; double Fh = f->xy1[1] - f->xy0[1]; // aspect ratios double Far = Fw / Fh; double Var = p->viewport[2] * 1.0 / p->viewport[3]; double tAngle = tan(p->perspective_fovy_degrees/2*M_PI/180.0); double height = fabs(0.5 * (Var > Far ? Fh : Fw / Var) / tAngle); state->eye1[0] = state->lookat1[0]; state->eye1[1] = state->lookat1[1]; state->eye1[2] = height; state->up1[0] = 0; state->up1[1] = 1; state->up1[2] = 0; state->mtime1 = f->mtime; free(f); } if (mtime > state->mtime1) { memcpy(p->eye, state->eye1, 3*sizeof(double)); memcpy(p->up, state->up1, 3*sizeof(double)); memcpy(p->lookat, state->lookat1, 3*sizeof(double)); p->perspectiveness = state->perspectiveness1; } else if (mtime <= state->mtime0) { memcpy(p->eye, state->eye0, 3*sizeof(double)); memcpy(p->up, state->up0, 3*sizeof(double)); memcpy(p->lookat, state->lookat0, 3*sizeof(double)); p->perspectiveness = state->perspectiveness0; } else { double alpha1 = ((double) mtime - state->mtime0) / (state->mtime1 - state->mtime0); double alpha0 = 1.0 - alpha1; scaled_combination(state->eye0, alpha0, state->eye1, alpha1, p->eye, 3); scaled_combination(state->up0, alpha0, state->up1, alpha1, p->up, 3); scaled_combination(state->lookat0, alpha0, state->lookat1, alpha1, p->lookat, 3); p->perspectiveness = state->perspectiveness0*alpha0 + state->perspectiveness1*alpha1; // Tweak so eye-to-lookat is the right distance { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * eye = matd_create_data(3,1, p->eye); zarray_add(fp, &eye); matd_t * lookat = matd_create_data(3,1, p->lookat); zarray_add(fp, &lookat); matd_t * up = matd_create_data(3,1, p->up); zarray_add(fp, &up); matd_t * eye0 = matd_create_data(3,1, state->eye0); zarray_add(fp, &eye0); matd_t * lookat0 = matd_create_data(3,1, state->lookat0); zarray_add(fp, &lookat0); matd_t * up0 = matd_create_data(3,1, state->up0); zarray_add(fp, &up0); matd_t * eye1 = matd_create_data(3,1, state->eye1); zarray_add(fp, &eye1); matd_t * lookat1 = matd_create_data(3,1, state->lookat1); zarray_add(fp, &lookat1); matd_t * up1 = matd_create_data(3,1, state->up1); zarray_add(fp, &up1); double dist0 = matd_vec_dist(eye0, lookat0); double dist1 = matd_vec_dist(eye1, lookat1); matd_t * dist = matd_create_scalar(dist0*alpha0 + dist1*alpha1); zarray_add(fp, &dist); matd_t * eye2p = matd_subtract(eye,lookat); zarray_add(fp, &eye2p); eye2p = matd_vec_normalize(eye2p); zarray_add(fp, &eye2p); eye = matd_op("M + (M*M)", lookat, eye2p, dist); // Only modified eye memcpy(p->eye, eye->data, 3*sizeof(double)); zarray_vmap(fp, matd_destroy); zarray_destroy(fp); } } // Need to do more fixup depending on interface mode! { if (state->interface_mode <= 2.0) { // stack eye on lookat: p->eye[0] = p->lookat[0]; p->eye[1] = p->lookat[1]; p->lookat[2] = 0; // skip fabs() for ENU/NED compat //p->eye[2] = fabs(p->eye[2]); { matd_t * up = matd_create_data(3,1, p->up); up->data[2] = 0; // up should never point in Z matd_t * up_norm = matd_vec_normalize(up); memcpy(p->up, up_norm->data, sizeof(double)*3); matd_destroy(up); matd_destroy(up_norm); } } else if (state->interface_mode == 2.5) { zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t * eye = matd_create_data(3,1, p->eye); zarray_add(fp, &eye); matd_t * lookat = matd_create_data(3,1, p->lookat); zarray_add(fp, &lookat); matd_t * up = matd_create_data(3,1, p->up); zarray_add(fp, &up); lookat->data[2] = 0.0; // Level horizon matd_t * dir = matd_subtract(lookat, eye); zarray_add(fp, &dir); matd_t * dir_norm = matd_vec_normalize(dir); zarray_add(fp, &dir_norm); matd_t * left = matd_crossproduct(up, dir_norm); zarray_add(fp, &left); left->data[2] = 0.0; left = matd_vec_normalize(left); zarray_add(fp, &left); // Don't allow upside down //up->data[2] = fmax(0.0, up->data[2]); // XXX NED? // Find an 'up' direction perpendicular to left matd_t * dot_scalar = matd_create_scalar(matd_vec_dot_product(up, left)); zarray_add(fp, &dot_scalar); up = matd_op("M - (M*M)", up, left, dot_scalar); zarray_add(fp, &up); up = matd_vec_normalize(up); zarray_add(fp, &up); // Now find eye position by computing new lookat dir matd_t * eye_dir = matd_crossproduct(up, left); zarray_add(fp, &eye_dir); matd_t *eye_dist_scalar = matd_create_scalar(matd_vec_dist(eye, lookat)); zarray_add(fp, &eye_dist_scalar); eye = matd_op("M + (M*M)", lookat, eye_dir, eye_dist_scalar); zarray_add(fp, &eye); // export results back to p: memcpy(p->eye, eye->data, sizeof(double)*3); memcpy(p->lookat, lookat->data, sizeof(double)*3); memcpy(p->up, up->data, sizeof(double)*3); zarray_vmap(fp, matd_destroy); zarray_destroy(fp); } } // Fix up for bad zoom if (1) { matd_t * eye = matd_create_data(3,1, p->eye); matd_t * lookat = matd_create_data(3,1, p->lookat); matd_t * up = matd_create_data(3,1, p->up); matd_t * lookeye = matd_subtract(lookat, eye); matd_t * lookdir = matd_vec_normalize(lookeye); double dist = matd_vec_dist(eye, lookat); dist = fmin(state->zclip_far / 3.0, dist); dist = fmax(state->zclip_near * 3.0, dist); matd_scale_inplace(lookdir, dist); matd_t * eye_fixed = matd_subtract(lookat, lookdir); memcpy(p->eye, eye_fixed->data, sizeof(double)*3); matd_destroy(eye); matd_destroy(lookat); matd_destroy(up); matd_destroy(lookeye); matd_destroy(lookdir); matd_destroy(eye_fixed); } // copy the result back into 'state' { memcpy(state->eye0, p->eye, 3*sizeof(double)); memcpy(state->up0, p->up, 3*sizeof(double)); memcpy(state->lookat0, p->lookat, 3*sizeof(double)); state->perspectiveness0 = p->perspectiveness; state->mtime0 = mtime; } return p; }
static void * movie_run(void * params) { state_t * state = params; zarray_t * frames = zarray_create(sizeof(movie_frame_t*)); char * last_filename = NULL; char * current_filename = NULL; gzFile gzMovie = NULL; int movie_frames = 0; int lost_frames = 0; uint64_t movie_start_mtime = 0; while (state->rendering) { pthread_mutex_lock(&state->movie_mutex); while (state->rendering && current_filename == state->movie_file && zarray_size(state->movie_pending) == 0) pthread_cond_wait(&state->movie_cond, &state->movie_mutex); if (!state->rendering) // exit signaled while waiting on cond break; for (int i = 0; i < zarray_size(state->movie_pending); i++) { movie_frame_t * tmp = NULL; zarray_get(state->movie_pending, i, &tmp); zarray_add(frames, &tmp); } zarray_clear(state->movie_pending); current_filename = state->movie_file; pthread_mutex_unlock(&state->movie_mutex); // Depending on setup, execute different actions // 1) Open 2) Close 3) Write a frame if (zarray_size(frames) > 0 && current_filename != NULL) { // Write the most recent frame, dump the rest movie_frame_t * movie_img = NULL; zarray_get(frames, zarray_size(frames)-1, &movie_img); zarray_remove_index(frames, zarray_size(frames)-1, 0); char header[256]; sprintf(header, "#mtime=%"PRIu64"\nP6 %d %d %d\n", movie_img->mtime, movie_img->width, movie_img->height, 255); int header_len = strlen(header); int imglen = movie_img->stride*movie_img->height;// RGB format gzwrite(gzMovie, header, header_len); gzwrite(gzMovie, movie_img->buf, imglen); int res = gzflush(gzMovie, Z_SYNC_FLUSH); if (res != Z_OK) { int errval = 0; printf("Error writing movie %s. Closing file\n", gzerror(gzMovie, &errval)); gzclose(gzMovie); free(current_filename); current_filename = NULL; } movie_frames++; movie_frame_destroy (movie_img); } // cleanup the frames: lost_frames += zarray_size(frames); zarray_vmap(frames, movie_frame_destroy); zarray_clear(frames); // Got a new filename, need to start recording if (current_filename != NULL && last_filename == NULL) { gzMovie = gzopen(current_filename, "w3"); movie_frames = 0; lost_frames = 0; movie_start_mtime = vx_mtime(); printf("NFO: Starting movie at %s\n", current_filename); if (gzMovie == NULL) { printf("WRN: Unable to start movie at %s\n", current_filename); free(current_filename); // XXX Would need to edit // state->movie_file ? current_filename = NULL; } } if (current_filename == NULL && last_filename != NULL) { gzclose(gzMovie); printf("NFO: Wrote/lost %d/%d movie frames at %.2f fps to %s\n", movie_frames, lost_frames, 1e3 * movie_frames / (vx_mtime() - movie_start_mtime), last_filename); free(last_filename); } last_filename = current_filename; } // XXX Cleanup? might shutdown while recording? return NULL; }
// this loop tries to run at X fps, and issue render commands static void * render_loop(void * foo) { state_t * state = foo; if (verbose)printf("Starting render thread!\n"); uint64_t render_count = 0; uint64_t last_mtime = vx_mtime(); double avgDT = 1.0f/state->target_frame_rate; uint64_t avg_loop_us = 3000; // initial render time guess while (state->rendering) { int64_t sleeptime = (1000000 / state->target_frame_rate) - (int64_t) avg_loop_us; if (sleeptime > 0) usleep(sleeptime); // XXX fix to include render time // Diagnostic tracking uint64_t mtime_start = vx_mtime(); // XXX avgDT = avgDT*.9 + .1 * (mtime_start - last_mtime)/1000; last_mtime = mtime_start; render_count++; if (verbose) { if (render_count % 100 == 0) printf("Average render DT = %.3f FPS = %.3f avgloopus %"PRIu64" sleeptime = %"PRIi64"\n", avgDT, 1.0/avgDT, avg_loop_us, sleeptime); } // prep the render data render_buffer_t rbuf; rbuf.state = state; rbuf.width = gtku_image_pane_get_width(state->imagePane); rbuf.height = gtku_image_pane_get_height(state->imagePane); if (rbuf.width == 0 && rbuf.height == 0) continue; // if the viewport is 0,0 // smartly reuse, or reallocate the output pixel buffer when resizing occurs GdkPixbuf * pixbuf = state->pixbufs[state->cur_pb_idx]; if (pixbuf == NULL || gdk_pixbuf_get_width(pixbuf) != rbuf.width || gdk_pixbuf_get_height(pixbuf) != rbuf.height) { if (pixbuf != NULL) { g_object_unref(pixbuf); free(state->pixdatas[state->cur_pb_idx]); } state->pixdatas[state->cur_pb_idx] = malloc(rbuf.width*rbuf.height*3); // can't stack allocate, can be too big (retina) pixbuf = gdk_pixbuf_new_from_data(state->pixdatas[state->cur_pb_idx], GDK_COLORSPACE_RGB, FALSE, 8, rbuf.width, rbuf.height, rbuf.width*3, NULL, NULL); // no destructor fn for pix data, handle manually state->pixbufs[state->cur_pb_idx] = pixbuf; } // second half of init: rbuf.out_buf = gdk_pixbuf_get_pixels(pixbuf); rbuf.format = GL_RGB; rbuf.rendered = 0; // 1 compute all the viewports render_info_t * rinfo = render_info_create(); rinfo->viewport[0] = rinfo->viewport[1] = 0; rinfo->viewport[2] = rbuf.width; rinfo->viewport[3] = rbuf.height; { zhash_iterator_t itr; uint32_t layer_id = 0; layer_info_t * linfo = NULL; zhash_iterator_init(state->layer_info_map, &itr); while(zhash_iterator_next(&itr, &layer_id, &linfo)){ zarray_add(rinfo->layers, &linfo); } zarray_sort(rinfo->layers, zvx_layer_info_compare); } zarray_t * fp = zarray_create(sizeof(matd_t*)); matd_t *mm = matd_create(4,4); zarray_add(fp, &mm); matd_t *pm = matd_create(4,4); zarray_add(fp, &pm); pthread_mutex_lock(&state->mutex); for (int i = 0; i < zarray_size(rinfo->layers); i++) { layer_info_t *linfo = NULL; zarray_get(rinfo->layers, i, &linfo); int * viewport = vx_viewport_mgr_get_pos(linfo->vp_mgr, rinfo->viewport, mtime_start); vx_camera_pos_t *pos = default_cam_mgr_get_cam_pos(linfo->cam_mgr, viewport, mtime_start); // store viewport, pos zhash_put(rinfo->layer_positions, &linfo->layer_id, &viewport, NULL, NULL); zhash_put(rinfo->camera_positions, &linfo->layer_id, &pos, NULL, NULL); // feed the actual camera/projection matrix to the gl side vx_camera_pos_model_matrix(pos,mm->data); vx_camera_pos_projection_matrix(pos, pm->data); matd_t * pmmm = matd_multiply(pm,mm); zarray_add(fp, &pmmm); float pm16[16]; vx_util_copy_floats(pmmm->data, pm16, 16); float eye3[16]; vx_util_copy_floats(pos->eye, eye3, 3); vx_gl_renderer_set_layer_render_details(state->glrend, linfo->layer_id, viewport, pm16, eye3); } // 2 Render the data task_thread_schedule_blocking(gl_thread, render_task, &rbuf); render_info_t * old = state->last_render_info; state->last_render_info = rinfo; pthread_mutex_unlock(&state->mutex); // 3 if a render occurred, then swap gtk buffers if (rbuf.rendered) { // point to the correct buffer for the next render: state->cur_pb_idx = (state->cur_pb_idx +1 ) % 2; // flip y coordinate in place: vx_util_flipy(rbuf.width*3, rbuf.height, rbuf.out_buf); // swap the image's backing buffer g_object_ref(pixbuf); // XXX Since gtku always unrefs with each of these calls, increment accordingly gtku_image_pane_set_buffer(state->imagePane, pixbuf); } // 3.1 If a movie is in progress, also need to serialize the frame pthread_mutex_lock(&state->movie_mutex); if (state->movie_file != NULL) { int last_idx = (state->cur_pb_idx + 1) % 2; GdkPixbuf * pb = state->pixbufs[last_idx]; movie_frame_t * movie_img = calloc(1, sizeof(movie_frame_t)); movie_img->mtime = mtime_start; movie_img->width = gdk_pixbuf_get_width(pb); movie_img->height = gdk_pixbuf_get_height(pb); movie_img->stride = 3*movie_img->width; movie_img->buf = malloc(movie_img->stride*movie_img->height); memcpy(movie_img->buf, state->pixdatas[last_idx], movie_img->stride*movie_img->height); // Alloc in this thread, dealloc in movie thread zarray_add(state->movie_pending, & movie_img); pthread_cond_signal(&state->movie_cond); } pthread_mutex_unlock(&state->movie_mutex); // cleanup if (old) render_info_destroy(old); zarray_vmap(fp, matd_destroy); zarray_destroy(fp); uint64_t mtime_end = vx_mtime(); avg_loop_us = (uint64_t)(.5*avg_loop_us + .5 * 1000 * (mtime_end - mtime_start)); } if (verbose) printf("Render thread exiting\n"); pthread_exit(NULL); }
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; }
loc_t* fit_lines(image_u32_t* im, node_t* n, vx_buffer_t* buf, metrics_t met, loc_t* out) { // usleep(2000000); srand(time(NULL)); // isolate valid entries zarray_t* loc_arr = zarray_create(sizeof(loc_t*)); for(int i = 0; i < im->height; i++) { if(n->sides[i].leftmost.x == im->width) continue; // not apart of blob loc_t* loc = malloc(sizeof(loc_t)); loc->x = n->sides[i].leftmost.x; loc->y = n->sides[i].leftmost.y; loc->valid = 0; zarray_add(loc_arr, &loc); } for(int i = 0; i < im->height; i++) { if(n->sides[i].rightmost.x == -1) continue; loc_t* loc = malloc(sizeof(loc_t)); loc->x = n->sides[i].rightmost.x; loc->y = n->sides[i].rightmost.y; loc->valid = 0; zarray_add(loc_arr, &loc); } // printf("\n\nall\n"); // for(int i = 0; i < zarray_size(loc_arr); i++) // { // loc_t* p1; // zarray_get(loc_arr, i, &p1); // printf("(%d, %d)\n", p1->x, p1->y); // } // printf("\n\n"); int iterations = 0; int best_score = 0; int lines_found = 0; loc_t line_match[8]; int max_iterations = 500; while(lines_found < 2 && zarray_size(loc_arr) > met.num_outliers) // still a lot of points left { if(iterations > max_iterations) break; // reset image and array // vx_object_t *vim = vxo_image_from_u32(im, 0, 0); // vx_buffer_add_back(buf, vxo_pix_coords(VX_ORIGIN_BOTTOM_LEFT, vim)); add_arr_of_locs_to_buffer(loc_arr, buf, 1.0, vx_black, met); int num_outliers = met.num_outliers/met.consensus_accuracy; while(best_score < ((zarray_size(loc_arr) - num_outliers)/(4 - lines_found))) { reset_locs(loc_arr); // pick random sample (2 points) loc_t* p1; loc_t* p2; zarray_get(loc_arr, (rand()%zarray_size(loc_arr)), &p1); p2 = p1; while(p1 == p2) zarray_get(loc_arr, (rand()%zarray_size(loc_arr)), &p2); // don't get same point // find consensus score of line from other points // if inside consensus range add 1 int tmp_score = 0; for(int j = 0; j < zarray_size(loc_arr); j++) { loc_t* tmp; zarray_get(loc_arr, j, &tmp); if(fabs(dist_from_point_to_line(p1, p2, tmp)) < (double)met.consensus_accuracy) { tmp->valid = 1; // printf("dist: (%d, %d, %d) %lf\n", tmp->x, tmp->y, tmp->valid, // fabs(dist_from_point_to_line(p1, p2, tmp))); tmp_score++; } } // keep best line so far if(tmp_score > best_score) { if(lines_found != 0) { // if 2nd line intersects, throw it out and find another loc_t intersect = get_line_intersection(line_match[0], line_match[1], *p1, *p2); if(in_range(im, intersect.x, intersect.y)) continue; } best_score = tmp_score; // printf(" score:%d, %d, %d %lf\n", best_score, ((zarray_size(loc_arr)-1)/(4-lines_found)), // zarray_size(loc_arr), 10/met.std_dev_from_square); line_match[lines_found*2] = *p1; line_match[lines_found*2+1] = *p2; } iterations++; if(iterations > max_iterations) break; } // loc_t ext_lines[2]; // extend_lines_to_edge_of_image(im, line_match[lines_found*2], line_match[lines_found*2+1], ext_lines); // add_line_to_buffer(im, buf, 2.0, ext_lines[0], ext_lines[1], vx_yellow); // delete all points associated with the found line zarray_t* endpoints_arr = zarray_create(sizeof(loc_t*)); for(int i = 0; i < zarray_size(loc_arr); i++) { loc_t* tmp; zarray_get(loc_arr, i, &tmp); // printf("removed: (%d, %d, %d) \n", tmp->x, tmp->y, tmp->valid); if(tmp->valid) { // add_circle_to_buffer(buf, 1.0, *tmp, vx_red); zarray_add(endpoints_arr, &tmp); zarray_remove_index(loc_arr, i, 0); i--; } } // find endpoints of line loc_t ext_lines[2]; extend_lines_to_edge_of_image(im, line_match[lines_found*2], line_match[lines_found*2+1], ext_lines); line_t endpoints = find_line_endpoints(endpoints_arr, &ext_lines[0], &ext_lines[1]); add_circle_to_buffer(buf, 2.0, endpoints.start, vx_red); add_circle_to_buffer(buf, 2.0, endpoints.end, vx_red); line_match[lines_found*2] = endpoints.start; line_match[lines_found*2+1] = endpoints.end; lines_found++; best_score = 0; // vx_buffer_swap(buf); // usleep(500000); } loc_t* ret = calloc(lines_found*2, sizeof(loc_t)); for(int i = 0; i < lines_found; i++) { ret[i*2] = line_match[i*2]; ret[i*2+1] = line_match[i*2+1]; loc_t ext_lines[2]; extend_lines_to_edge_of_image(im, line_match[i*2], line_match[i*2+1], ext_lines); add_line_to_buffer(im, buf, 2.0, ext_lines[0], ext_lines[1], vx_blue); } zarray_vmap(loc_arr, free); zarray_destroy(loc_arr); return(ret); // int corners_found = 0; // loc_t corners[4]; // find_corners_from_lines(im,line_match, 4, &corners_found, corners); // for(int i = 0; i < corners_found; i++) { // printf("(%d, %d)\n", corners[i].x, corners[i].y); // add_circle_to_buffer(buf, 3.0, corners[i], vx_blue); // } // printf("(%d, %d) (%d, %d) %lf\n", line_match[0].x, line_match[0].y, // line_match[1].x, line_match[1].y, // (double)best_score/N); }
// Call this only from the serialization thread // static void delayed_swap(vx_buffer_t * buffer) { if (!buffer->front_objs) return; // buffer has not yet finished initialization if (verbose) printf("DBG: swap %s\n", buffer->name); pthread_mutex_lock(&buffer->mutex); { // clear existing front buffer->front_codes->pos = 0; // reset // *+*+ corresponding decrement (if keeping up) zarray_vmap(buffer->front_objs, vx_object_dec_destroy); zarray_clear(buffer->front_objs); // swap out the pending objects without tying up this mutex for too long zarray_t * tmp = buffer->front_objs; buffer->front_objs = buffer->pending_objs; buffer->pending_objs = tmp; // empty } pthread_mutex_unlock(&buffer->mutex); vx_world_t * world = buffer->world; zhash_t * old_resources = buffer->front_resc; // Serialize each object into resources and opcodes vx_code_output_stream_t * codes = buffer->front_codes; codes->write_uint32(codes, OP_BUFFER_CODES); codes->write_uint32(codes, world->worldID); codes->write_str(codes, buffer->name); codes->write_uint32(codes, buffer->draw_order); // XXX We should move this op code elsewhere zhash_t * resources = zhash_create(sizeof(uint64_t),sizeof(vx_resc_t*), zhash_uint64_hash, zhash_uint64_equals); for (int i = 0; i < zarray_size(buffer->front_objs); i++) { vx_object_t * obj = NULL; zarray_get(buffer->front_objs, i, &obj); obj->append(obj, resources, codes); } // *&&* we will hold on to these until next swap() call zhash_vmap_values(resources, vx_resc_inc_ref); zhash_t * all_resources = zhash_copy(resources); addAll(all_resources, old_resources); // Claim use of the union of the last frame, and the current frame // this avoids a race condition where another buffer (maybe in another world) // could force deallocation of some resources before the new render codes arrive if (verbose) printf("DBG: claim union via codes\n"); if (verbose > 1) { printf(" claimed %d IDS ", zhash_size(all_resources)); zhash_vmap_values(all_resources, _print_id); printf("\n"); } send_buffer_resource_codes(buffer, all_resources); if (verbose) printf("DBG: Send actual resources\n"); if (verbose > 1) { printf(" send %d IDS ", zhash_size(all_resources)); zhash_vmap_values(all_resources, _print_id); printf("\n"); } notify_listeners_send_resources(world, all_resources); if (verbose) printf("DBG: send render codes\n"); notify_listeners_codes(world, codes); // Claim the actual set of resources which are in use now, which may result in some // resources being deleted from the gl context if (verbose) printf("DBG: reduce claim to actual in use\n"); if (verbose > 1) { printf(" actual %d IDS ", zhash_size(resources)); zhash_vmap_values(resources, _print_id); printf("\n\n"); } send_buffer_resource_codes(buffer, resources); buffer->front_resc = resources; // set of current resources zhash_destroy(all_resources); // *&&* corresponding decrement of resources zhash_vmap_values(old_resources, vx_resc_dec_destroy); zhash_destroy(old_resources); }