char * bu_strdupm(register const char *cp, const char *label) { char *base; size_t len; if (UNLIKELY(!cp && label)) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: [%s] NULL copy buffer\n", label); bu_semaphore_release(BU_SEM_SYSCALL); } if (!label) { label = "bu_strdup"; } len = strlen(cp)+1; base = (char *)bu_malloc(len, label); if (UNLIKELY(bu_debug&BU_DEBUG_MEM_LOG)) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "%p strdup%llu \"%s\"\n", (void *)base, (unsigned long long)len, cp); bu_semaphore_release(BU_SEM_SYSCALL); } memcpy(base, cp, len); return base; }
void db_sync(struct db_i *dbip) { RT_CK_DBI(dbip); bu_semaphore_acquire(BU_SEM_SYSCALL); /* make sure we have something to do */ if (!dbip->dbi_fp) { bu_semaphore_release(BU_SEM_SYSCALL); return; } /* flush the file */ (void)fflush(dbip->dbi_fp); #if defined(HAVE_FSYNC) && !defined(STRICT_FLAGS) /* make sure it's written out */ (void)fsync(fileno(dbip->dbi_fp)); #else # if defined(HAVE_SYNC) && !defined(STRICT_FLAGS) /* try the whole filesystem if sans fsync() */ sync(); # endif #endif bu_semaphore_release(BU_SEM_SYSCALL); }
HIDDEN void parallel_interface_arg(struct thread_data *user_thread_data) { /* keep track of our parallel ID number */ thread_set_cpu(user_thread_data->cpu_id); if (user_thread_data->affinity) { int ret; /* lock us onto a core corresponding to our parallel ID number */ ret = parallel_set_affinity(user_thread_data->cpu_id); if (ret) { bu_log("WARNING: encountered unexpected problem setting CPU affinity\n"); } } bu_semaphore_acquire(BU_SEM_THREAD); user_thread_data->parent->started++; bu_semaphore_release(BU_SEM_THREAD); (*(user_thread_data->user_func))(user_thread_data->cpu_id, user_thread_data->user_arg); bu_semaphore_acquire(BU_SEM_THREAD); user_thread_data->parent->finished++; bu_semaphore_release(BU_SEM_THREAD); parallel_mapping(PARALLEL_PUT, user_thread_data->cpu_id, 0); }
HIDDEN void parallel_interface_arg(struct thread_data *user_thread_data) { /* keep track of our parallel ID number */ thread_set_cpu(user_thread_data->cpu_id); if (user_thread_data->affinity) { int ret; /* lock us onto a core corresponding to our parallel ID number */ ret = parallel_set_affinity(user_thread_data->cpu_id); if (ret) { bu_log("WARNING: encountered unexpected problem setting CPU affinity\n"); } } if (!user_thread_data->counted) { bu_semaphore_acquire(BU_SEM_SYSCALL); parallel_nthreads_started++; bu_semaphore_release(BU_SEM_SYSCALL); } (*(user_thread_data->user_func))(user_thread_data->cpu_id, user_thread_data->user_arg); if (!user_thread_data->counted) { bu_semaphore_acquire(BU_SEM_SYSCALL); parallel_nthreads_finished++; bu_semaphore_release(BU_SEM_SYSCALL); } }
void paintCellFb(struct application *ap, unsigned char *pixpaint, unsigned char *pixexpendable) { int gx, gy; int gyfin, gxfin; int gxorg, gyorg; int x, y; int cnt; #if DEBUG_CELLFB brst_log("paintCellFb: expendable {%d, %d, %d}\n", pixexpendable[RED], pixexpendable[GRN], pixexpendable[BLU]); #endif gridToFb(ap->a_x, ap->a_y, &gx, &gy); gxorg = gx+1; gyorg = gy+1; gxfin = zoom == 1 ? gx+zoom+1 : gx+zoom; gyfin = zoom == 1 ? gy+zoom+1 : gy+zoom; cnt = gxfin - gxorg; for (y = gyorg; y < gyfin; y++) { if (zoom != 1 && (y - gy) % zoom == 0) continue; bu_semaphore_acquire(RT_SEM_STATS); (void) fb_read(fbiop, gxorg, y, (unsigned char *)pixbuf, cnt); bu_semaphore_release(RT_SEM_STATS); for (x = gxorg; x < gxfin; x++) { if (SAMERGB(&pixbuf[x-gxorg][0], pixexpendable) ) { #if DEBUG_CELLFB brst_log("Clobbering:<%d, %d>{%d, %d, %d}\n", x, y, pixbuf[x-gxorg][RED], pixbuf[x-gxorg][GRN], pixbuf[x-gxorg][BLU]); #endif COPYRGB(&pixbuf[x-gxorg][0], pixpaint); } #if DEBUG_CELLFB else brst_log("Preserving:<%d, %d>{%d, %d, %d}\n", x, y, pixbuf[x-gxorg][RED], pixbuf[x-gxorg][GRN], pixbuf[x-gxorg][BLU]); #endif } bu_semaphore_acquire(RT_SEM_STATS); (void) fb_write(fbiop, gxorg, y, (unsigned char *)pixbuf, cnt); bu_semaphore_release(RT_SEM_STATS); #if DEBUG_CELLFB brst_log("paintCellFb: fb_write(%d, %d)\n", x, y); #endif } return; }
void bu_free_mapped_files(int verbose) { struct bu_mapped_file *mp, *next; if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_log("bu_free_mapped_files(verbose=%d)\n", verbose); bu_semaphore_acquire(BU_SEM_MAPPEDFILE); next = BU_LIST_FIRST(bu_mapped_file, &bu_mapped_file_list); while (BU_LIST_NOT_HEAD(next, &bu_mapped_file_list)) { BU_CK_MAPPED_FILE(next); mp = next; next = BU_LIST_NEXT(bu_mapped_file, &mp->l); if (mp->uses > 0) continue; /* Found one that needs to have storage released */ if (UNLIKELY(verbose || (bu_debug&BU_DEBUG_MAPPED_FILE))) bu_pr_mapped_file("freeing", mp); BU_LIST_DEQUEUE(&mp->l); /* If application pointed mp->apbuf at mp->buf, break that * association so we don't double-free the buffer. */ if (mp->apbuf == mp->buf) mp->apbuf = (void *)NULL; #ifdef HAVE_SYS_MMAN_H if (mp->is_mapped) { int ret; bu_semaphore_acquire(BU_SEM_SYSCALL); ret = munmap(mp->buf, (size_t)mp->buflen); bu_semaphore_release(BU_SEM_SYSCALL); if (UNLIKELY(ret < 0)) perror("munmap"); /* XXX How to get this chunk of address space back to malloc()? */ } else #endif { bu_free(mp->buf, "bu_mapped_file.buf[]"); } mp->buf = (void *)NULL; /* sanity */ bu_free((void *)mp->name, "bu_mapped_file.name"); if (mp->appl) bu_free((void *)mp->appl, "bu_mapped_file.appl"); bu_free((void *)mp, "struct bu_mapped_file"); } bu_semaphore_release(BU_SEM_MAPPEDFILE); }
size_t bu_strlcatm(char *dst, const char *src, size_t size, const char *label) { size_t srcsize; size_t dstsize; if (!dst && label) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: NULL destination string, size %lu [%s]\n", (unsigned long)size, label); bu_semaphore_release(BU_SEM_SYSCALL); } if (UNLIKELY(!dst || !src || size <= 0)) { return 0; } if (!label) { label = "bu_strlcat"; } dstsize = strlen(dst); srcsize = strlen(src); if (UNLIKELY(dstsize == size - 1)) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: [%s] concatenation string is already full at %lu chars\n", label, (unsigned long)size-1); bu_semaphore_release(BU_SEM_SYSCALL); } else if (UNLIKELY(dstsize > size - 1)) { /* probably missing null-termination or is not an initialized buffer */ bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: [%s] concatenation string is already full, exceeds size (%lu > %lu)\n", label, (unsigned long)dstsize, (unsigned long)size-1); bu_semaphore_release(BU_SEM_SYSCALL); } else if (UNLIKELY(srcsize > size - dstsize - 1)) { if (UNLIKELY(bu_debug)) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: [%s] string truncation, exceeding %lu char max concatenating %lu chars (started with %lu)\n", label, (unsigned long)size-1, (unsigned long)srcsize, (unsigned long)dstsize); bu_semaphore_release(BU_SEM_SYSCALL); } } #ifdef HAVE_STRLCAT /* don't return to ensure consistent null-termination behavior in following */ (void)strlcat(dst, src, size); #else (void)strncat(dst, src, size - dstsize - 1); #endif /* be sure to null-terminate, contrary to strncat behavior */ if (dstsize + srcsize < size - 1) { dst[dstsize + srcsize] = '\0'; } else { dst[size-1] = '\0'; /* sanity */ } return strlen(dst); }
void bn_noise_init(void) { int i, j, k, temp; int rndtabi = BN_RAND_TABSIZE - 1; bu_semaphore_acquire( BU_SEM_BN_NOISE ); if (ht.hashTableValid) { bu_semaphore_release( BU_SEM_BN_NOISE ); return; } BN_RANDSEED(rndtabi, (BN_RAND_TABSIZE-1) ); ht.hashTableMagic1 = (long *) bu_malloc( 2*sizeof(long) + 4096*sizeof(short int), "noise hashTable"); ht.hashTable = (short *)&ht.hashTableMagic1[1]; ht.hashTableMagic2 = (long *)&ht.hashTable[4096]; *ht.hashTableMagic1 = MAGIC_TAB1; *ht.hashTableMagic2 = MAGIC_TAB2; ht.magic_end = MAGIC_STRHT2; ht.magic = MAGIC_STRHT1; for (i = 0; i < 4096; i++) ht.hashTable[i] = i; /* scramble the hash table */ for (i = 4095; i > 0; i--) { j = (int)(BN_RANDOM(rndtabi) * 4096.0); temp = ht.hashTable[i]; ht.hashTable[i] = ht.hashTable[j]; ht.hashTable[j] = temp; } BN_RANDSEED(k, 13); for (i = 0; i < MAXSIZE; i++) RTable[i] = BN_RANDOM(k) * 2.0 - 1.0; ht.hashTableValid = 1; bu_semaphore_release( BU_SEM_BN_NOISE ); CK_HT(); }
/** * b u _ v l s _ r e a d * * Read the remainder of a UNIX file onto the end of a vls. * * Returns - * nread number of characters read * 0 if EOF encountered immediately * -1 read error */ int bu_vls_read( struct bu_vls *vp, int fd ) { size_t todo; int got; int ret = 0; BU_CK_VLS(vp); for (;;) { bu_vls_extend( vp, _VLS_ALLOC_READ ); todo = (size_t)vp->vls_max - vp->vls_len - vp->vls_offset - 1; bu_semaphore_acquire(BU_SEM_SYSCALL); got = read(fd, vp->vls_str+vp->vls_offset+vp->vls_len, todo ); bu_semaphore_release(BU_SEM_SYSCALL); if ( got < 0 ) { /* Read error, abandon the read */ return -1; } if (got == 0) break; vp->vls_len += got; ret += got; } /* force null termination */ vp->vls_str[vp->vls_len+vp->vls_offset] = '\0'; return ret; }
static union tree * bev_facetize_region_end(struct db_tree_state *UNUSED(tsp), const struct db_full_path *pathp, union tree *curtree, genptr_t client_data) { struct bu_list vhead; struct ged *gedp = (struct ged *)client_data; BU_LIST_INIT(&vhead); if (RT_G_DEBUG&DEBUG_TREEWALK) { char *sofar = db_path_to_string(pathp); bu_vls_printf(gedp->ged_result_str, "bev_facetize_region_end() path='%s'\n", sofar); bu_free((genptr_t)sofar, "path string"); } if (curtree->tr_op == OP_NOP) return curtree; bu_semaphore_acquire(RT_SEM_MODEL); if (bev_facetize_tree) { union tree *tr; BU_ALLOC(tr, union tree); RT_TREE_INIT(tr); tr->tr_op = OP_UNION; tr->tr_b.tb_regionp = REGION_NULL; tr->tr_b.tb_left = bev_facetize_tree; tr->tr_b.tb_right = curtree; bev_facetize_tree = tr; } else { bev_facetize_tree = curtree; } bu_semaphore_release(RT_SEM_MODEL); /* Tree has been saved, and will be freed later */ return TREE_NULL; }
/* * R A Y M I S S * * Called via a_miss linkage from rt_shootray() when ray misses. */ int raymiss(register struct application *ap) { bu_semaphore_acquire( RT_SEM_RESULTS ); scanbuf[ap->a_x] = 255; bu_semaphore_release( RT_SEM_RESULTS ); return(0); }
/* * R A Y H I T * * Called via a_hit linkage from rt_shootray() when ray hits. */ int rayhit(register struct application *ap, struct partition *PartHeadp, struct seg *segp) { bu_semaphore_acquire( RT_SEM_RESULTS ); scanbuf[ap->a_x] = 1; bu_semaphore_release( RT_SEM_RESULTS ); return(1); /* report hit to main routine */ }
size_t bu_strlcpym(char *dst, const char *src, size_t size, const char *label) { size_t srcsize; if (UNLIKELY(!dst && label)) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: NULL destination string, size %lu [%s]\n", (unsigned long)size, label); bu_semaphore_release(BU_SEM_SYSCALL); } if (UNLIKELY(!dst || !src || size <= 0)) { return 0; } if (!label) { label = "bu_strlcpy"; } srcsize = strlen(src); if (UNLIKELY(bu_debug)) { if (srcsize > size - 1) { bu_semaphore_acquire(BU_SEM_SYSCALL); fprintf(stderr, "WARNING: [%s] string truncation, exceeding %lu char max copying %lu chars\n", label, (unsigned long)size-1, (unsigned long)srcsize); bu_semaphore_release(BU_SEM_SYSCALL); } } #ifdef HAVE_STRLCPY /* don't return to ensure consistent null-termination behavior in following */ (void)strlcpy(dst, src, size); #else (void)strncpy(dst, src, size - 1); #endif /* be sure to always null-terminate, contrary to strncpy behavior */ if (srcsize < size - 1) { dst[srcsize] = '\0'; } else { dst[size-1] = '\0'; /* sanity */ } return strlen(dst); }
/* * V I E W _ E O L * * Called by worker() at the end of each line. Depricated. * Any end-of-line processing should be done in view_pixel(). */ void view_eol(register struct application *ap) { bu_semaphore_acquire( BU_SEM_SYSCALL ); if ( outfp != NULL ) fwrite( scanbuf, 1, width, outfp ); #if 0 else if ( fbp != FBIO_NULL ) fb_write( fbp, 0, ap->a_y, scanbuf, width ); #endif bu_semaphore_release( BU_SEM_SYSCALL ); }
/** * grab the next row of rays to be evaluated */ int get_next_row(struct fitness_state *fstate) { int r; bu_semaphore_acquire(SEM_WORK); if (fstate->row < fstate->res[Y]) r = ++fstate->row; /* get a row to work on */ else r = 0; /* signal end of work */ bu_semaphore_release(SEM_WORK); return r; }
struct region_pair * add_unique_pair(struct region_pair *list, /* list to add into */ struct region *r1, /* first region involved */ struct region *r2, /* second region involved */ double dist, /* distance/thickness metric value */ point_t pt) /* location where this takes place */ { struct region_pair *rp, *rpair; /* look for it in our list */ bu_semaphore_acquire(GED_SEM_LIST); for (BU_LIST_FOR (rp, region_pair, &list->l)) { if ((r1 == rp->r.r1 && r2 == rp->r2) || (r1 == rp->r2 && r2 == rp->r.r1)) { /* we already have an entry for this region pair, we * increase the counter, check the depth and update * thickness maximum and entry point if need be and * return. */ rp->count++; if (dist > rp->max_dist) { rp->max_dist = dist; VMOVE(rp->coord, pt); } rpair = rp; goto found; } } /* didn't find it in the list. Add it */ BU_ALLOC(rpair, struct region_pair); rpair->r.r1 = r1; rpair->r2 = r2; rpair->count = 1; rpair->max_dist = dist; VMOVE(rpair->coord, pt); list->max_dist ++; /* really a count */ /* insert in the list at the "nice" place */ for (BU_LIST_FOR (rp, region_pair, &list->l)) { if (bu_strcmp(rp->r.r1->reg_name, r1->reg_name) <= 0) break; } BU_LIST_INSERT(&rp->l, &rpair->l); found: bu_semaphore_release(GED_SEM_LIST); return rpair; }
void bu_close_mapped_file(struct bu_mapped_file *mp) { BU_CK_MAPPED_FILE(mp); if (UNLIKELY(bu_debug&BU_DEBUG_MAPPED_FILE)) bu_pr_mapped_file("close:uses--", mp); if (UNLIKELY(!mp)) { bu_log("bu_close_mapped_file() called with null pointer\n"); return; } bu_semaphore_acquire(BU_SEM_MAPPEDFILE); --mp->uses; bu_semaphore_release(BU_SEM_MAPPEDFILE); }
void plotPartition(struct hit *ihitp, struct hit *ohitp) { if (plotfp == NULL) return; bu_semaphore_acquire(BU_SEM_SYSCALL); pl_3line(plotfp, (int) ihitp->hit_point[X], (int) ihitp->hit_point[Y], (int) ihitp->hit_point[Z], (int) ohitp->hit_point[X], (int) ohitp->hit_point[Y], (int) ohitp->hit_point[Z] ); bu_semaphore_release(BU_SEM_SYSCALL); return; }
void plotRayPoint(struct xray *rayp) { int endpoint[3]; if (plotfp == NULL) return; VJOIN1(endpoint, rayp->r_pt, cellsz, rayp->r_dir); bu_semaphore_acquire(BU_SEM_SYSCALL); pl_color(plotfp, R_BURST, G_BURST, B_BURST); /* draw point */ pl_3point(plotfp, (int) endpoint[X], (int) endpoint[Y], (int) endpoint[Z]); bu_semaphore_release(BU_SEM_SYSCALL); return; }
/* this function provides book-keeping so that we give out unique * thread identifiers and for tracking a thread's parent context. */ static struct parallel_info * parallel_mapping(parallel_action_t action, int id, size_t max) { /* container for keeping track of recursive invocation data, limits, current values */ static struct parallel_info mapping[MAX_PSW] = {{0,0,0,0,0}}; int got_cpu; switch (action) { case PARALLEL_GET: if (id < 0) { bu_semaphore_acquire(BU_SEM_THREAD); for (got_cpu = 1; got_cpu < MAX_PSW; got_cpu++) { if (mapping[got_cpu].id == 0) { mapping[got_cpu].id = got_cpu; break; } } bu_semaphore_release(BU_SEM_THREAD); if (got_cpu >= MAX_PSW) bu_bomb("Compile-time parallelism limit reached. Unable to track more threading.\n"); mapping[got_cpu].started = mapping[got_cpu].finished = 0; mapping[got_cpu].parent = bu_parallel_id(); } else { got_cpu = id; if (mapping[got_cpu].id != got_cpu) { /* presumably id == 0 */ mapping[got_cpu].id = got_cpu; } } if (mapping[got_cpu].lim == 0 && max > 0) mapping[got_cpu].lim = max; return &mapping[got_cpu]; case PARALLEL_PUT: mapping[id].started = mapping[id].finished = mapping[id].lim = mapping[id].parent = 0; mapping[id].id = 0; /* separate to avoid race */ } return NULL; }
/** * b u _ v l s _ w r i t e * * Write the VLS to the provided file descriptor. */ void bu_vls_write( int fd, const struct bu_vls *vp ) { int status; BU_CK_VLS(vp); if ( vp->vls_len <= 0 ) return; bu_semaphore_acquire(BU_SEM_SYSCALL); status = write( fd, vp->vls_str + vp->vls_offset, (size_t)vp->vls_len ); bu_semaphore_release(BU_SEM_SYSCALL); if ( status != vp->vls_len ) { perror("write"); bu_bomb("bu_vls_write() write error\n"); } }
/** * b u _ v l s _ f w r i t e * * Write the VLS to the provided file pointer. */ void bu_vls_fwrite(FILE *fp, const struct bu_vls *vp) { int status; BU_CK_VLS(vp); if ( vp->vls_len <= 0 ) return; bu_semaphore_acquire(BU_SEM_SYSCALL); status = fwrite( vp->vls_str + vp->vls_offset, (size_t)vp->vls_len, 1, fp ); bu_semaphore_release(BU_SEM_SYSCALL); if ( status != 1 ) { perror("fwrite"); bu_bomb("bu_vls_fwrite() write error\n"); } }
void paintSpallFb(struct application *ap) { unsigned char pixel[3]; int x, y; int err; fastf_t celldist; #if DEBUG_SPALLFB brst_log("paintSpallFb: a_x=%d a_y=%d a_cumlen=%g cellsz=%g zoom=%d\n", ap->a_x, ap->a_y, ap->a_cumlen, cellsz, zoom); #endif pixel[RED] = ap->a_color[RED] * 255; pixel[GRN] = ap->a_color[GRN] * 255; pixel[BLU] = ap->a_color[BLU] * 255; gridToFb(ap->a_x, ap->a_y, &x, &y); CenterCell(x); /* center of cell */ CenterCell(y); celldist = ap->a_cumlen/cellsz * zoom; x = roundToInt(x + VDOT(ap->a_ray.r_dir, gridhor) * celldist); y = roundToInt(y + VDOT(ap->a_ray.r_dir, gridver) * celldist); bu_semaphore_acquire(RT_SEM_STATS); err = fb_write(fbiop, x, y, pixel, 1); bu_semaphore_release(RT_SEM_STATS); #if DEBUG_SPALLFB brst_log("paintSpallFb:gridhor=<%g, %g, %g> gridver=<%g, %g, %g>\n", gridhor[X], gridhor[Y], gridhor[Z], gridver[X], gridver[Y], gridver[Z]); brst_log("paintSpallFb:fb_write(x=%d, y=%d, pixel={%d, %d, %d})\n", x, y, (int) pixel[RED], (int) pixel[GRN], (int) pixel[BLU] ); #endif if (err == -1) brst_log("Write failed to pixel <%d, %d> from cell <%d, %d>.\n", x, y, ap->a_x, ap->a_y); return; }
void prnt_Scroll(const char *fmt, ...) { va_list ap; /* We use the same lock as malloc. Sys-call or mem lock, really */ bu_semaphore_acquire(BU_SEM_SYSCALL); /* lock */ va_start(ap, fmt); if (tty) { /* Only move cursor and scroll if newline is output. */ static int newline = 1; if (CS != NULL) { SetScrlReg(TOP_SCROLL_WIN, PROMPT_LINE - 1); if (newline) { SCROLL_PR_MOVE(); (void) ClrEOL(); } (void)vfprintf(stdout, fmt, ap); (void) ResetScrlReg(); } else if (DL != NULL) { if (newline) { SCROLL_DL_MOVE(); (void) DeleteLn(); SCROLL_PR_MOVE(); (void) ClrEOL(); } (void)vfprintf(stdout, fmt, ap); } else (void)vfprintf(stdout, fmt, ap); /* End of line detected by existence of a newline. */ newline = fmt[strlen(fmt)-1] == '\n'; hmredraw(); } else (void)vfprintf(stderr, fmt, ap); va_end(ap); bu_semaphore_release(BU_SEM_SYSCALL); /* unlock */ return; }
/* * Log an error. * This version buffers a full line, to save network traffic. */ void bu_log(const char *fmt, ...) { va_list vap; char buf[512]; /* a generous output line. Must be AUTO, else non-PARALLEL. */ if (print_on == 0) return; bu_semaphore_acquire(BU_SEM_SYSCALL); va_start(vap, fmt); (void)vsprintf(buf, fmt, vap); va_end(vap); if (pcsrv == PKC_NULL || pcsrv == PKC_ERROR) { fprintf(stderr, "%s", buf); goto out; } if (debug) fprintf(stderr, "%s", buf); if (pkg_send(MSG_PRINT, buf, strlen(buf)+1, pcsrv) < 0) { fprintf(stderr, "pkg_send MSG_PRINT failed\n"); bu_exit(12, NULL); } out: bu_semaphore_release(BU_SEM_SYSCALL); }
struct fbm_spec * find_spec_wgt(double h, double l, double o) { struct fbm_spec *ep; int i; for (ep = etbl, i=0; i < etbl_next; i++, ep++) { if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt"); if (ep->lacunarity == l && ep->h_val == h && ep->octaves >= o) return ep; } /* we didn't find the table we wanted so we've got to semaphore on * the list to wait our turn to add what we want to the table. */ bu_semaphore_acquire( BU_SEM_BN_NOISE ); /* We search the list one more time in case the last process to * hold the semaphore just created the table we were about to add */ for (ep = etbl, i=0; i < etbl_next; i++, ep++) { if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt"); if (ep->lacunarity == l && ep->h_val == h && ep->octaves >= o) break; } if (i >= etbl_next) ep = build_spec_tbl(h, l, o); bu_semaphore_release( BU_SEM_BN_NOISE ); return (ep); }
/* * R A Y H I T * * Rayhit() is called by rt_shootray() when the ray hits one or more objects. * A per-shotline header record is written, followed by information about * each object hit. * * Note that the GIFT-3 format uses a different convention for the "zero" * distance along the ray. RT has zero at the ray origin (emanation plain), * while GIFT has zero at the screen plain translated so that it contains * the model origin. This difference is compensated for by adding the * 'dcorrection' distance correction factor. * * Also note that the GIFT-3 format requires information about the start * point of the ray in two formats. First, the h, v coordinates of the * grid cell CENTERS (in screen space coordinates) are needed. * Second, the ACTUAL h, v coordinates fired from are needed. * * An optional rtg3.pl UnixPlot file is written, permitting a * color vector display of ray-model intersections. */ int rayhit(struct application *ap, register struct partition *PartHeadp, struct seg *segp) { register struct partition *pp = PartHeadp->pt_forw; int comp_count; /* component count */ fastf_t dfirst, dlast; /* ray distances */ static fastf_t dcorrection = 0; /* RT to GIFT dist corr */ int card_count; /* # comp. on this card */ const char *fmt; /* printf() format string */ struct bu_vls str; char buf[128]; /* temp. sprintf() buffer */ point_t hv; /* GIFT h, v coords, in inches */ point_t hvcen; int prev_id=-1; point_t first_hit; int first; if ( pp == PartHeadp ) return(0); /* nothing was actually hit?? */ if ( ap->a_rt_i->rti_save_overlaps ) rt_rebuild_overlaps( PartHeadp, ap, 1 ); part_compact(ap, PartHeadp, TOL); /* count components in partitions */ comp_count = 0; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { if ( pp->pt_regionp->reg_regionid > 0 ) { prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else if ( prev_id <= 0 ) { /* normally air would be output along with a solid partition, but this will require a '111' partition */ prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else prev_id = pp->pt_regionp->reg_regionid; } pp = PartHeadp->pt_back; if ( pp!=PartHeadp && pp->pt_regionp->reg_regionid <= 0 ) comp_count++; /* a trailing '111' ident */ if ( comp_count == 0 ) return( 0 ); /* Set up variable length string, to buffer this shotline in. * Note that there is one component per card, and that each card * (line) is 80 characters long. Hence the parameters given to * rt-vls-extend(). */ bu_vls_init( &str ); bu_vls_extend( &str, 80 * (comp_count+1) ); /* * Find the H, V coordinates of the grid cell center. * RT uses the lower left corner of each cell. */ { point_t center; fastf_t dx; fastf_t dy; dx = ap->a_x + 0.5; dy = ap->a_y + 0.5; VJOIN2( center, viewbase_model, dx, dx_model, dy, dy_model ); MAT4X3PNT( hvcen, model2hv, center ); } /* * Find exact h, v coordinates of actual ray start by * projecting start point into GIFT h, v coordinates. */ MAT4X3PNT( hv, model2hv, ap->a_ray.r_pt ); /* * In RT, rays are launched from the plane of the screen, * and ray distances are relative to the start point. * In GIFT-3 output files, ray distances are relative to * the (H, V) plane translated so that it contains the origin. * A distance correction is required to convert between the two. * Since this really should be computed only once, not every time, * the trip_count flag was added. */ { static int trip_count; vect_t tmp; vect_t viewZdir; if ( trip_count == 0) { VSET( tmp, 0, 0, -1 ); /* viewing direction */ MAT4X3VEC( viewZdir, view2model, tmp ); VUNITIZE( viewZdir ); /* dcorrection will typically be negative */ dcorrection = VDOT( ap->a_ray.r_pt, viewZdir ); trip_count = 1; } } /* This code is for diagnostics. * bu_log("dcorrection=%g\n", dcorrection); */ /* dfirst and dlast have been made negative to account for GIFT looking * in the opposite direction of RT. */ dfirst = -(PartHeadp->pt_forw->pt_inhit->hit_dist + dcorrection); dlast = -(PartHeadp->pt_back->pt_outhit->hit_dist + dcorrection); #if 0 /* This code is to note any occurances of negative distances. */ if ( PartHeadp->pt_forw->pt_inhit->hit_dist < 0) { bu_log("ERROR: dfirst=%g at partition x%x\n", dfirst, PartHeadp->pt_forw ); bu_log("\tdcorrection = %f\n", dcorrection ); bu_log("\tray start point is ( %f %f %f ) in direction ( %f %f %f )\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) ); VJOIN1( PartHeadp->pt_forw->pt_inhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( PartHeadp->pt_back->pt_outhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_outhit->hit_dist, ap->a_ray.r_dir ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } /* End of bug trap. */ #endif /* * Output the ray header. The GIFT statements that * would have generated this are: * 410 write(1, 411) hcen, vcen, h, v, ncomp, dfirst, dlast, a, e * 411 format(2f7.1, 2f9.3, i3, 2f8.2,' A', f6.1,' E', f6.1) */ #define SHOT_FMT "%7.1f%7.1f%9.3f%9.3f%3d%8.2f%8.2f A%6.1f E%6.1f" if ( rt_perspective > 0 ) { bn_ae_vec( &azimuth, &elevation, ap->a_ray.r_dir ); } bu_vls_printf( &str, SHOT_FMT, hvcen[0], hvcen[1], hv[0], hv[1], comp_count, dfirst * MM2IN, dlast * MM2IN, azimuth, elevation ); /* * As an aid to debugging, take advantage of the fact that * there are more than 80 columns on UNIX "cards", and * add debugging information to the end of the line to * allow this shotline to be reproduced offline. * -b gives the shotline x, y coordinates when re-running RTG3, * -p and -d are used with RTSHOT * The easy way to activate this is with the harmless -!1 option * when running RTG3. */ if ( R_DEBUG || bu_debug || RT_G_DEBUG ) { bu_vls_printf( &str, " -b%d,%d -p %26.20e %26.20e %26.20e -d %26.20e %26.20e %26.20e\n", ap->a_x, ap->a_y, V3ARGS(ap->a_ray.r_pt), V3ARGS(ap->a_ray.r_dir) ); } else { bu_vls_putc( &str, '\n' ); } /* loop here to deal with individual components */ card_count = 0; prev_id = -1; first = 1; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { /* * The GIFT statements that would have produced * this output are: * do 632 i=icomp, iend * if (clos(icomp).gt.999.99.or.slos(i).gt.999.9) goto 635 * 632 continue * write(1, 633)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 633 format(1x, 3(i4, f6.2, 2f5.1, i1, f5.1)) * goto 670 * 635 write(1, 636)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 636 format(1x, 3(i4, f6.1, 2f5.1, i1, f5.0)) */ fastf_t comp_thickness; /* component line of sight thickness */ fastf_t in_obliq; /* in obliquity angle */ fastf_t out_obliq; /* out obliquity angle */ int region_id; /* solid region's id */ int air_id; /* air id */ fastf_t dot_prod; /* dot product of normal and ray dir */ fastf_t air_thickness; /* air line of sight thickness */ vect_t normal; /* surface normal */ register struct partition *nextpp = pp->pt_forw; region_id = pp->pt_regionp->reg_regionid; if ( region_id <= 0 && prev_id > 0 ) { /* air region output with previous partition */ prev_id = region_id; continue; } comp_thickness = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist; /* The below code is meant to catch components with zero or * negative thicknesses. This is not supposed to be possible, * but the condition has been seen. */ #if 0 if ( comp_thickness <= 0 ) { VJOIN1( pp->pt_inhit->hit_point, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( pp->pt_outhit->hit_point, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir ); bu_log("ERROR: comp_thickness=%g for region id = %d at h=%g, v=%g (x=%d, y=%d), partition at x%x\n", comp_thickness, region_id, hv[0], hv[1], ap->a_x, ap->a_y, pp ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); bu_log("Send this output to the BRL-CAD Developers ([email protected])\n"); if ( ! (RT_G_DEBUG & DEBUG_ARB8)) { rt_g.debug |= DEBUG_ARB8; rt_shootray(ap); rt_g.debug &= ~DEBUG_ARB8; } } #endif if ( nextpp == PartHeadp ) { if ( region_id <= 0 ) { /* last partition is air, need a 111 'phantom armor' before AND after */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before and after air region %s\n", pp->pt_regionp->reg_name ); region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else { /* Last partition, no air follows, use code 9 */ air_id = 9; air_thickness = 0.0; } } else if ( region_id <= 0 ) { /* air region, need a 111 'phantom armor' */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before air region %s\n", pp->pt_regionp->reg_name ); prev_id = region_id; region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else if ( nextpp->pt_regionp->reg_regionid <= 0 && nextpp->pt_regionp->reg_aircode != 0 ) { /* Next partition is air region */ air_id = nextpp->pt_regionp->reg_aircode; air_thickness = nextpp->pt_outhit->hit_dist - nextpp->pt_inhit->hit_dist; prev_id = air_id; } else { /* 2 solid regions, maybe with gap */ air_id = 0; air_thickness = nextpp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist; if ( air_thickness < 0.0 ) air_thickness = 0.0; if ( !NEAR_ZERO( air_thickness, 0.1 ) ) { air_id = 1; /* air gap */ if ( R_DEBUG & RDEBUG_HITS ) bu_log("air gap added\n"); } else { air_thickness = 0.0; } prev_id = region_id; } /* * Compute the obliquity angles in degrees, ie, * the "declension" angle down off the normal vector. * RT normals always point outwards; * the "inhit" normal points opposite the ray direction, * the "outhit" normal points along the ray direction. * Hence the one sign change. * XXX this should probably be done with atan2() */ if ( first ) { first = 0; VJOIN1( first_hit, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); } out: RT_HIT_NORMAL( normal, pp->pt_inhit, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); in_obliq = acos( -dot_prod ) * bn_radtodeg; RT_HIT_NORMAL( normal, pp->pt_outhit, pp->pt_outseg->seg_stp, &(ap->a_ray), pp->pt_outflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); out_obliq = acos( dot_prod ) * bn_radtodeg; /* Check for exit obliquties greater than 90 degrees. */ #if 0 if ( in_obliq > 90 || in_obliq < 0 ) { bu_log("ERROR: in_obliquity=%g\n", in_obliq); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } if ( out_obliq > 90 || out_obliq < 0 ) { bu_log("ERROR: out_obliquity=%g\n", out_obliq); VPRINT(" r_dir", ap->a_ray.r_dir); VPRINT("normal", normal); bu_log("dot=%g, acos(dot)=%g\n", VDOT( ap->a_ray.r_dir, normal ), acos( VDOT( ap->a_ray.r_dir, normal ) ) ); /* Print the defective one */ rt_pr_pt( ap->a_rt_i, pp ); /* Print the whole ray's partition list */ rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } #endif if ( in_obliq > 90.0 ) in_obliq = 90.0; if ( in_obliq < 0.0 ) in_obliq = 0.0; if ( out_obliq > 90.0 ) out_obliq = 90.0; if ( out_obliq < 0.0 ) out_obliq = 0.0; /* * Handle 3-components per card output format, with * a leading space in front of the first component. */ if ( card_count == 0 ) { bu_vls_strcat( &str, " " ); } comp_thickness *= MM2IN; /* Check thickness fields for format overflow */ if ( comp_thickness > 999.99 || air_thickness*MM2IN > 999.9 ) fmt = "%4d%6.1f%5.1f%5.1f%1d%5.0f"; else fmt = "%4d%6.2f%5.1f%5.1f%1d%5.1f"; #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_acquire( BU_SEM_SYSCALL ); #endif snprintf(buf, 128, fmt, region_id, comp_thickness, in_obliq, out_obliq, air_id, air_thickness*MM2IN ); #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_release( BU_SEM_SYSCALL ); #endif bu_vls_strcat( &str, buf ); card_count++; if ( card_count >= 3 ) { bu_vls_strcat( &str, "\n" ); card_count = 0; } /* A color rtg3.pl UnixPlot file of output commands * is generated. This is processed by plot(1) * plotting filters such as pl-fb or pl-sgi. * Portions of a ray passing through air within the * model are represented in blue, while portions * passing through a solid are assigned green. * This will always be done single CPU, * to prevent output garbling. (See view_init). */ if (R_DEBUG & RDEBUG_RAYPLOT) { vect_t inpt; vect_t outpt; VJOIN1(inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir); VJOIN1(outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir); pl_color(plotfp, 0, 255, 0); /* green */ pdv_3line(plotfp, inpt, outpt); if (air_thickness > 0) { vect_t air_end; VJOIN1(air_end, ap->a_ray.r_pt, pp->pt_outhit->hit_dist + air_thickness, ap->a_ray.r_dir); pl_color(plotfp, 0, 0, 255); /* blue */ pdv_3cont(plotfp, air_end); } } if ( nextpp == PartHeadp && air_id != 9 ) { /* need to output a 111 'phantom armor' at end of shotline */ air_id = 9; air_thickness = 0.0; region_id = 111; comp_thickness = 0.0; goto out; } } /* If partway through building the line, add a newline */ if ( card_count > 0 ) { /* * Note that GIFT zero-fills the unused component slots, * but neither COVART II nor COVART III require it, * so just end the line here. */ bu_vls_strcat( &str, "\n" ); } /* Single-thread through file output. * COVART will accept non-sequential ray data provided the * ray header and its associated data are not separated. CAVEAT: * COVART will not accept headers out of sequence. */ bu_semaphore_acquire( BU_SEM_SYSCALL ); fputs( bu_vls_addr( &str ), outfp ); if ( shot_fp ) { fprintf( shot_fp, "%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %ld %.5f %.5f %.5f\n", azimuth, elevation, V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ), line_num, V3ARGS( first_hit) ); line_num += 1 + (comp_count / 3 ); if ( comp_count % 3 ) line_num++; } /* End of single-thread region */ bu_semaphore_release( BU_SEM_SYSCALL ); /* Release vls storage */ bu_vls_free( &str ); return(0); }
void render_camera_render_thread(int UNUSED(cpu), void *ptr) { render_camera_thread_data_t *td; int d, n, res_ind, scanline, v_scanline; vect_t pixel, accum, v1, v2; struct tie_ray_s ray; fastf_t view_inv; VSETALL(v1, 0); td = (render_camera_thread_data_t *)ptr; view_inv = 1.0 / td->camera->view_num; td->camera->render.tie = td->tie; res_ind = 0; /* row, vertical */ /* for (i = td->tile->orig_y; i < td->tile->orig_y + td->tile->size_y; i++) { */ while (1) { /* Determine if this scanline should be computed by this thread */ bu_semaphore_acquire(TIE_SEM_WORKER); if (*td->scanline == td->tile->size_y) { bu_semaphore_release(TIE_SEM_WORKER); return; } else { scanline = *td->scanline; (*td->scanline)++; } bu_semaphore_release(TIE_SEM_WORKER); v_scanline = scanline + td->tile->orig_y; if (td->tile->format == RENDER_CAMERA_BIT_DEPTH_24) { res_ind = 3*scanline*td->tile->size_x; } else if (td->tile->format == RENDER_CAMERA_BIT_DEPTH_128) { res_ind = 4*scanline*td->tile->size_x; } /* optimization if there is no depth of field being applied */ if (td->camera->view_num == 1) { VSCALE(v1, td->camera->view_list[0].step_y, v_scanline); VADD2(v1, v1, td->camera->view_list[0].top_l); } /* scanline, horizontal, each pixel */ for (n = td->tile->orig_x; n < td->tile->orig_x + td->tile->size_x; n++) { /* depth of view samples */ if (td->camera->view_num > 1) { VSET(accum, 0, 0, 0); for (d = 0; d < td->camera->view_num; d++) { VSCALE(ray.dir, td->camera->view_list[d].step_y, v_scanline); VADD2(ray.dir, ray.dir, td->camera->view_list[d].top_l); VSCALE(v1, td->camera->view_list[d].step_x, n); VADD2(ray.dir, ray.dir, v1); VSET(pixel, (tfloat)RENDER_CAMERA_BGR, (tfloat)RENDER_CAMERA_BGG, (tfloat)RENDER_CAMERA_BGB); VMOVE(ray.pos, td->camera->view_list[d].pos); ray.depth = 0; VUNITIZE(ray.dir); /* Compute pixel value using this ray */ td->camera->render.work(&td->camera->render, td->tie, &ray, &pixel); VADD2(accum, accum, pixel); } /* Find Mean value of all views */ VSCALE(pixel, accum, view_inv); } else { if (td->camera->type == RENDER_CAMERA_PERSPECTIVE) { VSCALE(v2, td->camera->view_list[0].step_x, n); VADD2(ray.dir, v1, v2); VSET(pixel, (tfloat)RENDER_CAMERA_BGR, (tfloat)RENDER_CAMERA_BGG, (tfloat)RENDER_CAMERA_BGB); VMOVE(ray.pos, td->camera->view_list[0].pos); ray.depth = 0; VUNITIZE(ray.dir); /* Compute pixel value using this ray */ td->camera->render.work(&td->camera->render, td->tie, &ray, &pixel); } else { VMOVE(ray.pos, td->camera->view_list[0].pos); VMOVE(ray.dir, td->camera->view_list[0].top_l); VSCALE(v1, td->camera->view_list[0].step_x, n); VSCALE(v2, td->camera->view_list[0].step_y, v_scanline); VADD2(ray.pos, ray.pos, v1); VADD2(ray.pos, ray.pos, v2); VSET(pixel, (tfloat)RENDER_CAMERA_BGR, (tfloat)RENDER_CAMERA_BGG, (tfloat)RENDER_CAMERA_BGB); ray.depth = 0; /* Compute pixel value using this ray */ td->camera->render.work(&td->camera->render, td->tie, &ray, &pixel); } } if (td->tile->format == RENDER_CAMERA_BIT_DEPTH_24) { if (pixel[0] > 1) pixel[0] = 1; if (pixel[1] > 1) pixel[1] = 1; if (pixel[2] > 1) pixel[2] = 1; ((char *)(td->res_buf))[res_ind+0] = (unsigned char)(255 * pixel[0]); ((char *)(td->res_buf))[res_ind+1] = (unsigned char)(255 * pixel[1]); ((char *)(td->res_buf))[res_ind+2] = (unsigned char)(255 * pixel[2]); res_ind += 3; } else if (td->tile->format == RENDER_CAMERA_BIT_DEPTH_128) { tfloat alpha; alpha = 1.0; ((tfloat *)(td->res_buf))[res_ind + 0] = pixel[0]; ((tfloat *)(td->res_buf))[res_ind + 1] = pixel[1]; ((tfloat *)(td->res_buf))[res_ind + 2] = pixel[2]; ((tfloat *)(td->res_buf))[res_ind + 3] = alpha; res_ind += 4; } /* printf("Pixel: [%d, %d, %d]\n", rgb[0], rgb[1], rgb[2]); */ } } }
/** * action performed at the end of each scanline */ void view_eol(struct application *ap) { int cpu = ap->a_resource->re_cpu; int i; if (overlay) { /* * Overlay mode. Check if the pixel is an edge. If so, write * it to the framebuffer. */ for (i = 0; i < per_processor_chunk; ++i) { if (writeable[cpu][i]) { /* * Write this pixel */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, i, ap->a_y, &scanline[cpu][i*3], 1); bu_semaphore_release(BU_SEM_SYSCALL); } } return; } else if (blend) { /* * Blend mode. * * Read a line from the existing framebuffer, convert to HSV, * manipulate, and put the results in the scanline as RGB. */ int replace_down = 0; /* flag that specifies if the pixel in the * scanline below must be replaced. */ RGBpixel rgb; fastf_t hsv[3]; bu_semaphore_acquire(BU_SEM_SYSCALL); if (fb_read(fbp, 0, ap->a_y, blendline[cpu], per_processor_chunk) < 0) bu_exit(EXIT_FAILURE, "rtedge: error reading from framebuffer.\n"); bu_semaphore_release(BU_SEM_SYSCALL); for (i = 0; i < per_processor_chunk; ++i) { /* * Is this pixel an edge? */ if (writeable[cpu][i]) { /* * The pixel is an edge, retrieve the appropriate * pixel from the line buffer and convert it to HSV. */ rgb[RED] = blendline[cpu][i*3+RED]; rgb[GRN] = blendline[cpu][i*3+GRN]; rgb[BLU] = blendline[cpu][i*3+BLU]; /* * Is the pixel in the blendline array the background * color? If so, look left and down to determine which * pixel is the "source" of the edge. Unless, of * course, we are on the bottom scanline or the * leftmost column (x=y=0) */ if (i != 0 && ap->a_y != 0 && !diffpixel(rgb, fb_bg_color)) { RGBpixel left; RGBpixel down; left[RED] = blendline[cpu][(i-1)*3+RED]; left[GRN] = blendline[cpu][(i-1)*3+GRN]; left[BLU] = blendline[cpu][(i-1)*3+BLU]; bu_semaphore_acquire(BU_SEM_SYSCALL); fb_read(fbp, i, ap->a_y - 1, down, 1); bu_semaphore_release(BU_SEM_SYSCALL); if (diffpixel(left, fb_bg_color)) { /* * Use this one. */ rgb[RED] = left[RED]; rgb[GRN] = left[GRN]; rgb[BLU] = left[BLU]; } else if (diffpixel(down, fb_bg_color)) { /* * Use the pixel from the scanline below */ replace_down = 1; rgb[RED] = down[RED]; rgb[GRN] = down[GRN]; rgb[BLU] = down[BLU]; } } /* * Convert to HSV */ bu_rgb_to_hsv(rgb, hsv); /* * Now perform the manipulations. */ hsv[VAL] *= 3.0; hsv[SAT] /= 3.0; if (hsv[VAL] > 1.0) { fastf_t d = hsv[VAL] - 1.0; hsv[VAL] = 1.0; hsv[SAT] -= d; hsv[SAT] = hsv[SAT] >= 0.0 ? hsv[SAT] : 0.0; } /* * Convert back to RGB. */ bu_hsv_to_rgb(hsv, rgb); if (replace_down) { /* * Write this pixel immediately, do not put it * into the blendline since it corresponds to the * wrong scanline. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, i, ap->a_y, rgb, 1); bu_semaphore_release(BU_SEM_SYSCALL); replace_down = 0; } else { /* * Put this pixel back into the blendline array. * We'll push it to the buffer when the entire * scanline has been processed. */ blendline[cpu][i*3+RED] = rgb[RED]; blendline[cpu][i*3+GRN] = rgb[GRN]; blendline[cpu][i*3+BLU] = rgb[BLU]; } } /* end "if this pixel is an edge" */ } /* end pixel loop */ /* * Write the blendline to the framebuffer. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, 0, ap->a_y, blendline[cpu], per_processor_chunk); bu_semaphore_release(BU_SEM_SYSCALL); return; } /* end blend */ if (fbp != FBIO_NULL) { /* * Simple whole scanline write to a framebuffer. */ bu_semaphore_acquire(BU_SEM_SYSCALL); fb_write(fbp, 0, ap->a_y, scanline[cpu], per_processor_chunk); bu_semaphore_release(BU_SEM_SYSCALL); } if (outputfile != NULL) { /* * Write to a file. */ bu_semaphore_acquire(BU_SEM_SYSCALL); /* TODO : Add double type data to maintain resolution */ icv_writeline(bif, ap->a_y, scanline[cpu], ICV_DATA_UCHAR); bu_semaphore_release(BU_SEM_SYSCALL); } if (fbp == FBIO_NULL && outputfile == NULL) bu_log("rtedge: strange, no end of line actions taken.\n"); return; }
/** * compare a ray that hit to source */ int compare_hit(register struct application *ap, struct partition *partHeadp, struct seg *UNUSED(segs)) { register struct partition *pp=NULL; register struct part *mp=NULL; struct fitness_state *fstate = (struct fitness_state *) ap->a_uptr; fastf_t xp, yp, lastpt=0.0; int status = 0; if (partHeadp == NULL && fstate->ray[ap->a_user] == NULL) { bu_semaphore_acquire(SEM_SAME); fstate->same += fstate->a_len; bu_semaphore_release(SEM_SAME); return 0; } /* move from head */ if (partHeadp!=NULL) pp = partHeadp->pt_forw; if (fstate->ray[ap->a_user] !=NULL) mp = BU_LIST_FORW(part, &fstate->ray[ap->a_user]->l); /* if both rays missed, count this as the same. * no need to evaluate further*/ bu_semaphore_acquire(SEM_SAME); bu_semaphore_acquire(SEM_DIFF); while (pp != partHeadp && mp != fstate->ray[ap->a_user]) { if (status & STATUS_PP) xp = pp->pt_outhit->hit_dist; else xp = pp->pt_inhit->hit_dist; if (status & STATUS_MP) yp = mp->outhit_dist; else yp = mp->inhit_dist; if (xp < 0) xp = 0; if (yp < 0) yp = 0; if (status==STATUS_EMPTY) { if (NEAR_EQUAL(xp, yp, 1.0e-5)) { fstate->same += xp; status = (STATUS_PP | STATUS_MP); lastpt = xp; } else if (xp < yp) { fstate->same+= xp; lastpt = xp; status = STATUS_PP; } else if (yp < xp) { fstate->same+= yp; lastpt = yp; status = STATUS_MP; } } else if (status == (STATUS_MP | STATUS_PP)) { if (NEAR_EQUAL(xp, yp, 1.0e-5)) { fstate->same += xp - lastpt; status = STATUS_EMPTY; pp = pp->pt_forw; mp = BU_LIST_FORW(part, &mp->l); lastpt = xp; } else if (xp < yp) { fstate->same += xp - lastpt; lastpt = xp; status = STATUS_MP; pp=pp->pt_forw; } else if (yp < xp) { fstate->same += yp - lastpt; lastpt = yp; status = STATUS_PP; mp = BU_LIST_FORW(part, &mp->l); } } else if (status == STATUS_PP) { if (NEAR_EQUAL(xp, yp, 1.0e-5)) { fstate->diff += xp - lastpt; status = STATUS_MP; lastpt = yp; pp = pp->pt_forw; } else if (xp > yp) { fstate->diff += yp - lastpt; lastpt = yp; status = STATUS_PP | STATUS_MP; } else if (xp < yp) { fstate->diff += xp - lastpt; status = STATUS_EMPTY; pp = pp ->pt_forw; lastpt = xp; } } else if (status == STATUS_MP) { if (NEAR_EQUAL(xp, yp, 1.0e-5)) { fstate->diff += yp - lastpt; status = STATUS_PP; lastpt = xp; mp = BU_LIST_FORW(part, &mp->l); } else if (xp < yp) { fstate->diff += xp - lastpt; lastpt = xp; status = STATUS_PP | STATUS_MP; } else if (xp > yp) { fstate->diff += yp - lastpt; status = STATUS_EMPTY; mp = BU_LIST_FORW(part, &mp->l); lastpt = yp; } } } /* we could be halfway through evaluating a partition * finish evaluating it before proceeding */ if (status == STATUS_PP) { if (pp->pt_outhit->hit_dist > fstate->a_len) { /* trim ray */ fstate->diff += fstate->a_len - lastpt; lastpt = fstate->a_len; } else { fstate->diff+= pp->pt_outhit->hit_dist - lastpt; lastpt = pp->pt_outhit->hit_dist; } pp = pp->pt_forw; } else if (status == STATUS_MP) { fstate->diff += mp->outhit_dist - lastpt; lastpt = mp->outhit_dist; mp = BU_LIST_FORW(part, &mp->l); } /* if there are a different # of partitions in source and individual */ while (mp != fstate->ray[ap->a_user]) { fstate->diff += mp->outhit_dist - mp->inhit_dist; lastpt = mp->outhit_dist; mp = BU_LIST_FORW(part, &mp->l); } while (pp != partHeadp && pp->pt_inhit->hit_dist < fstate->a_len) { if (pp->pt_outhit->hit_dist > fstate->a_len) { /* trim bounding box */ fstate->diff += fstate->a_len - pp->pt_inhit->hit_dist; lastpt = fstate->a_len; } else { fstate->diff += pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist; lastpt = pp->pt_outhit->hit_dist; } pp = pp->pt_forw; } /* include trailing empty space as similar */ fstate->same += fstate->a_len - lastpt; bu_semaphore_release(SEM_SAME); bu_semaphore_release(SEM_DIFF); return 1; }