/* * Function: ri_transport_sample * * Triggers light transporter and computes radiance along the ray. * * Parameters: * * *render - The global renderer data. * *ray - The ray originating camera which throughs pixel plane. * *resut - Light transport result(including radiance). * * Returns: * * Always 1. */ int ri_transport_sample( ri_render_t *render, const ri_ray_t *ray, ri_transport_info_t *result) { ri_ray_t newray; memcpy(&newray, ray, sizeof(ri_ray_t)); /* copy */ /* * Initialize */ { ri_vector_setzero(result->radiance); result->nbound_diffuse = 0; result->nbound_specular = 0; ri_intersection_state_clear( &result->state ); } trace_path(render, &newray, result); return 1; }
static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn) { HDC new_hdc=NULL; GpGraphics *new_graphics=NULL; GpStatus stat; INT save_state; if (!path->pathdata.Count) /* PathToRegion doesn't support empty paths */ { *hrgn = CreateRectRgn( 0, 0, 0, 0 ); return *hrgn ? Ok : OutOfMemory; } if (!graphics) { new_hdc = CreateCompatibleDC(0); if (!new_hdc) return OutOfMemory; stat = GdipCreateFromHDC(new_hdc, &new_graphics); graphics = new_graphics; if (stat != Ok) { DeleteDC(new_hdc); return stat; } } else if (!graphics->hdc) { graphics->hdc = new_hdc = CreateCompatibleDC(0); if (!new_hdc) return OutOfMemory; } save_state = SaveDC(graphics->hdc); EndPath(graphics->hdc); SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE : WINDING)); stat = trace_path(graphics, path); if (stat == Ok) { *hrgn = PathToRegion(graphics->hdc); stat = *hrgn ? Ok : OutOfMemory; } RestoreDC(graphics->hdc, save_state); if (new_hdc) { DeleteDC(new_hdc); if (new_graphics) GdipDeleteGraphics(new_graphics); else graphics->hdc = NULL; } return stat; }
static void trace_pixel(ri_vector_t *radiance, int x, int y) { unsigned char type; double bsdf[3]; ri_ray_t ray; ri_intersection_state_t state; pathnode_t node; ri_vector_t Le; /* first check a ray hits scene object through pixel (x, y) */ ri_vector_copy(&ray.org, cam_pos); sample_pixel(&ray.dir, x, y); ray.thread_num = 0; if (!ri_raytrace(ri_render_get(), &ray, &state)) { /* hits background */ ri_texture_ibl_fetch(radiance, light->texture, ray.dir); return; } node.depth = 2; node.G[0] = 1.0; node.G[1] = 1.0; node.G[2] = 1.0; ri_mem_copy(&node.state, &state, sizeof(ri_intersection_state_t)); ri_vector_copy(&node.indir, ray.dir); // assume that the camera is not located in the transparent object node.interior = 0; trace_path(&node); /* connect the path to the IBL light source */ type = sample_reflection_type(node.state.geom->material); //if (node.interior) printf("???\n"); sample_outdir(&ray.dir, &type, node.interior, node.state.geom->material, node.indir, node.state.Ng); brdf(bsdf, type, &node.state, node.indir, ray.dir, node.state.Ng); node.G[0] *= bsdf[0]; node.G[1] *= bsdf[1]; node.G[2] *= bsdf[2]; ri_vector_copy(&ray.org, node.state.P); light_sample(&Le, ray.org, ray.dir); radiance->f[0] = Le.f[0] * node.G[0]; radiance->f[1] = Le.f[1] * node.G[1]; radiance->f[2] = Le.f[2] * node.G[2]; }
static GpStatus get_path_hrgn(GpPath *path, GpGraphics *graphics, HRGN *hrgn) { HDC new_hdc=NULL; GpGraphics *new_graphics=NULL; GpStatus stat; INT save_state; if (!graphics) { new_hdc = GetDC(0); if (!new_hdc) return OutOfMemory; stat = GdipCreateFromHDC(new_hdc, &new_graphics); graphics = new_graphics; if (stat != Ok) { ReleaseDC(0, new_hdc); return stat; } } else if (!graphics->hdc) { graphics->hdc = new_hdc = GetDC(0); if (!new_hdc) return OutOfMemory; } save_state = SaveDC(graphics->hdc); EndPath(graphics->hdc); SetPolyFillMode(graphics->hdc, (path->fill == FillModeAlternate ? ALTERNATE : WINDING)); stat = trace_path(graphics, path); if (stat == Ok) { *hrgn = PathToRegion(graphics->hdc); stat = *hrgn ? Ok : OutOfMemory; } RestoreDC(graphics->hdc, save_state); if (new_hdc) { ReleaseDC(0, new_hdc); if (new_graphics) GdipDeleteGraphics(new_graphics); else graphics->hdc = NULL; } return stat; }
int btree_select(btree_t bt, const void *key, btree_selmode_t mode, void *key_ret, void *data_ret) { const struct btree_def *def = bt->def; check_btree(bt); switch (mode) { case BTREE_CLEAR: bt->slot[0] = -1; break; case BTREE_READ: break; case BTREE_EXACT: case BTREE_LE: if (!trace_path(bt, key, bt->path, bt->slot) && mode == BTREE_EXACT) bt->slot[0] = -1; break; case BTREE_FIRST: cursor_first(bt); break; case BTREE_NEXT: cursor_next(bt); break; } /* Return the data at the cursor */ if (bt->slot[0] >= 0) { if (key_ret) memcpy(key_ret, PAGE_KEY(bt->path[0], bt->slot[0]), def->key_size); if (data_ret) memcpy(data_ret, PAGE_DATA(bt->path[0], bt->slot[0]), def->data_size); return 0; } return 1; }
int btree_delete(btree_t bt, const void *key) { const struct btree_def *def = bt->def; const int halfsize = def->branches / 2; struct btree_page *path[MAX_HEIGHT] = {0}; int slot[MAX_HEIGHT] = {0}; int h; check_btree(bt); /* Trace a path to the item to be deleted */ if (!key) { if (bt->slot[0] < 0) return 1; memcpy(path, bt->path, sizeof(path)); memcpy(slot, bt->slot, sizeof(slot)); } else if (!trace_path(bt, key, path, slot)) { return 1; } /* Select the next item if we're deleting at the cursor */ if (bt->slot[0] == slot[0] && bt->path[0] == path[0]) cursor_next(bt); /* Delete from the leaf node. If it's still full enough, then we don't * need to do anything else. */ delete_item(path[0], slot[0]); if (path[0]->num_children >= halfsize) return 0; /* Trace back up the tree, fixing underfull nodes. If we can fix by * borrowing, do it and we're done. Otherwise, we need to fix by * merging, which may result in another underfull node, and we need * to continue. */ for (h = 1; h <= bt->root->height; h++) { struct btree_page *p = path[h]; struct btree_page *c = path[h - 1]; int s = slot[h]; if (s > 0) { /* Borrow/merge from lower page */ struct btree_page *d = *PAGE_PTR(p, s - 1); if (d->num_children > halfsize) { move_item(d, d->num_children - 1, c, 0); memcpy(PAGE_KEY(p, s), PAGE_KEY(c, 0), def->key_size); return 0; } merge_pages(d, c); delete_item(p, s); free(c); } else { /* Borrow/merge from higher page */ struct btree_page *d = *PAGE_PTR(p, s + 1); if (d->num_children > halfsize) { move_item(d, 0, c, c->num_children); memcpy(PAGE_KEY(p, s + 1), PAGE_KEY(d, 0), def->key_size); return 0; } merge_pages(c, d); delete_item(p, s + 1); free(d); } if (p->num_children >= halfsize) return 0; } /* If the root contains only a single pointer to another page, * shrink the tree. This does not affect the cursor. */ if (bt->root->height && bt->root->num_children == 1) { struct btree_page *old = bt->root; bt->root = *PAGE_PTR(old, 0); free(old); } return 0; }
int btree_put(btree_t bt, const void *key, const void *data) { const struct btree_def *def = bt->def; struct btree_page *new_root = NULL; struct btree_page *path_new[MAX_HEIGHT] = {0}; struct btree_page *path_old[MAX_HEIGHT] = {0}; int slot_old[MAX_HEIGHT] = {0}; int h; check_btree(bt); /* Special case: cursor overwrite */ if (!key) { if (bt->slot[0] < 0) { fprintf(stderr, "btree: put at invalid cursor\n"); return -1; } memcpy(PAGE_DATA(bt->path[0], bt->slot[0]), data, def->data_size); return 1; } /* Find a path down the tree that leads to the page which should * contain this datum (though the page might be too big to hold it). */ if (trace_path(bt, key, path_old, slot_old)) { /* Special case: overwrite existing item */ memcpy(PAGE_DATA(path_old[0], slot_old[0]), data, def->data_size); return 1; } /* Trace from the leaf up. If the leaf is at its maximum size, it will * need to split, and cause a pointer to be added in the parent page * of the same node (which may in turn cause it to split). */ for (h = 0; h <= bt->root->height; h++) { if (path_old[h]->num_children < def->branches) break; path_new[h] = allocate_page(bt, h); if (!path_new[h]) goto fail; } /* If the split reaches the top (i.e. the root splits), then we need * to allocate a new root node. */ if (h > bt->root->height) { if (h >= MAX_HEIGHT) { fprintf(stderr, "btree: maximum height exceeded\n"); goto fail; } new_root = allocate_page(bt, h); if (!new_root) goto fail; } /* Trace up to one page above the split. At each page that needs * splitting, copy the top half of keys into the new page. Also, * insert a key into one of the pages at all pages from the leaf * to the page above the top of the split. */ for (h = 0; h <= bt->root->height; h++) { int s = slot_old[h] + 1; struct btree_page *p = path_old[h]; /* If there's a split at this level, copy the top half of * the keys from the old page to the new one. Check to see * if the position we were going to insert into is in the * old page or the new one. */ if (path_new[h]) { split_page(path_old[h], path_new[h]); if (s > p->num_children) { s -= p->num_children; p = path_new[h]; } } /* Insert the key in the appropriate page */ if (h) insert_ptr(p, s, PAGE_KEY(path_new[h - 1], 0), path_new[h - 1]); else insert_data(p, s, key, data); /* If there was no split at this level, there's nothing to * insert higher up, and we're all done. */ if (!path_new[h]) return 0; } /* If we made it this far, the split reached the top of the tree, and * we need to grow it using the extra page we allocated. */ assert (new_root); if (bt->slot[0] >= 0) { /* Fix up the cursor, if active */ bt->slot[new_root->height] = bt->path[bt->root->height] == new_root ? 1 : 0; bt->path[new_root->height] = new_root; } memcpy(PAGE_KEY(new_root, 0), def->zero, def->key_size); *PAGE_PTR(new_root, 0) = path_old[h - 1]; memcpy(PAGE_KEY(new_root, 1), PAGE_KEY(path_new[h - 1], 0), def->key_size); *PAGE_PTR(new_root, 1) = path_new[h - 1]; new_root->num_children = 2; bt->root = new_root; return 0; fail: for (h = 0; h <= bt->root->height; h++) if (path_new[h]) free(path_new[h]); return -1; }
/* * Function: trace_path * * Samples light transport path in recursive manner. In curent * implementation, <trace_path> acts as distribution ray tracing. * * Parameters: * * *render - The global renderer data. * *ray - The ray to be traced. * *resut - Light transport result(including radiance). * * Returns: * * None. */ static void trace_path(ri_render_t *render, ri_ray_t *ray, ri_transport_info_t *result) { int max_nbound_specular = 10; if (result->nbound_specular > max_nbound_specular) { /* Too much reflection, terminate. */ return; } ri_light_t *light = NULL; int hit; /* hack */ vec white; vec black; ri_vector_set1(white, 1.0); ri_vector_set1(black, 0.0); hit = ri_raytrace(render, ray, &(result->state)); if (hit) { if (result->state.geom->light) { light = result->state.geom->light; /* Hit light geometry. */ vcpy(result->radiance, light->col); return; } vcpy(result->radiance, white); } else { vcpy(result->radiance, black); } return; #if 0 // TODO int hit, lighthit; int hasfresnel; ri_vector_t col; ri_vector_t transmit_ray; ri_vector_t reflect_ray; ri_vector_t offset; ri_vector_t raydir; ri_vector_t rayorg; ri_vector_t refrad, trasrad; ri_vector_t normal; ri_light_t *light; ri_vector_t rad; ri_material_t *material; ri_ray_t lightray; ri_transport_info_t ref_result; /* for reflection */ double r, d, s, t; float fresnel_factor = 1.0f; float kr, kt; float eta = 1.0f / 1.4f; float etaval; if (result->nbound_specular > 8) { //printf("too reflection\n"); return; } light = get_light(render); ri_vector_copy(&raydir, ray->dir); result->state.inside = 0; hit = ri_raytrace(render, ray, &(result->state)); if (hit) { if (light->geom) { /* Check if a ray also hits light geometry and * that is closer than scene geometry or not. */ ri_vector_copy(&lightray.org, ray->org); ri_vector_copy(&lightray.dir, ray->dir); lighthit = ri_raytrace_geom( light->geom, &lightray, &(result->state)); if (lighthit && (lightray.isectt < ray->isectt) ) { // light is "seen" ri_vector_copy(&result->radiance, light->col); result->hit = 1; return; } } r = randomMT(); material = result->state.geom->material; if (!material) { d = 1.0; s = 0.0; t = 0.0; } else { d = ri_vector_ave(&material->kd); s = ri_vector_ave(&material->ks); t = ri_vector_ave(&material->kt); } if (s > 0.0) { /* specular reflection */ if (result->state.geom->material && result->state.geom->material->fresnel) { /* Fresnel reflection */ ri_fresnel(&ray->dir, &transmit_ray, &kr, &kt, &ray->dir, &result->state.normal, eta); fresnel_factor = kr; } else { ri_reflect(&(ray->dir), &ray->dir, &result->state.normal); fresnel_factor = 1.0f; } ri_vector_copy(&(ray->org), result->state.P); ri_vector_copy(&col, result->state.color); result->nbound_specular++; /* push radiance */ ri_vector_copy(&rad, result->radiance); ri_vector_zero(&(result->radiance)); trace_path(render, ray, result); /* pop radiance */ ri_vector_mul(&(result->radiance), &result->radiance, &material->ks); ri_vector_mul(&(result->radiance), &result->radiance, &col); ri_vector_scale(&(result->radiance), fresnel_factor); ri_vector_add(&(result->radiance), &result->radiance, &rad); } if (d > 0.0) { /* diffuse reflection */ result->nbound_diffuse++; ri_shade(&rad, &ray->dir, ray, &(result->state)); ri_vector_mul(&rad, &rad, &material->kd); ri_vector_add(&(result->radiance), &result->radiance, &rad); } if (t > 0.0) { /* specular refraction */ if (result->state.geom->material && result->state.geom->material->fresnel) { hasfresnel = 1; } else { hasfresnel = 0; } if (hasfresnel) { /* Fresnel effect */ ri_vector_copy(&normal, result->state.normal); if (result->state.inside) { printf("inside val = %d\n", result->state.inside); printf("inside\n"); /* ray hits inside surface */ //ri_vector_neg(&normal); etaval = 1.0 / eta; } else { etaval = eta; } ri_fresnel(&reflect_ray, &transmit_ray, &kr, &kt, &ray->dir, &normal, etaval); } else { ri_refract(&(ray->dir), &ray->dir, &result->state.normal, eta); kr = 0.0; kt = 1.0; } /* slightly moves the ray towards outgoing direction */ ri_vector_copy(&rayorg, result->state.P); /* ray.org = ray.org + 0.001 * ray.dir */ ri_vector_copy(&offset, &transmit_ray); ri_vector_scale(&offset, 0.001); ri_vector_add(&(ray->org), &rayorg, &offset); /* ray.dir = refract direction */ ri_vector_copy(&(ray->dir), &transmit_ray); ri_vector_copy(&col, &result->state.color); result->nbound_specular++; ray->prev_hit = 'S'; /* push radiance */ ri_vector_copy(&rad, &result->radiance); ri_vector_zero(&(result->radiance)); trace_path(render, ray, result); /* pop radiance */ ri_vector_mul(&(result->radiance), &result->radiance, &material->kt); ri_vector_mul(&(result->radiance), &result->radiance, &col); ri_vector_scale(&(result->radiance), kt); if (hasfresnel) { /* add reflection color */ /* ray.org = ray.org + 0.001 * ray.dir */ ri_vector_copy(&offset, &reflect_ray); ri_vector_scale(&offset, 0.001); ri_vector_add(&(ray->org), &rayorg, &offset); ri_vector_copy(&(ray->dir), &reflect_ray); ri_vector_copy(&col, &result->state.color); ray->prev_hit = 'S'; ri_vector_zero(&ref_result.radiance); ref_result.nbound_specular = result->nbound_specular; ref_result.nbound_diffuse = result->nbound_diffuse; ref_result.state.inside = 0; trace_path(render, ray, &ref_result); /* pop radiance */ ri_vector_mul(&(ref_result.radiance), &ref_result.radiance, &col); ri_vector_scale(&(ref_result.radiance), kr); ri_vector_add(&(result->radiance), &result->radiance, &ref_result.radiance); } ri_vector_add(&(result->radiance), &result->radiance, &rad); } //} else if (result->nbound_specular + result->nbound_diffuse < 2) { } else { /* check if hit light geometry */ ray->isectt = 0.0f; if (light->type == LIGHTTYPE_IBL || light->type == LIGHTTYPE_SUNSKY) { ri_texture_ibl_fetch(&(result->radiance), light->texture, &ray->dir); result->hit = 1; return; } else if (ri_render_get()->background_map) { ri_texture_ibl_fetch(&(result->radiance), ri_render_get()->background_map, &ray->dir); result->hit = 1; return; } else { if (light->geom) { /* area light. */ lighthit = ri_raytrace_geom( light->geom, ray, &(result->state)); if (lighthit) { // light is "seen" result->radiance.e[0] = 1.0; result->radiance.e[1] = 1.0; result->radiance.e[2] = 1.0; result->hit = 1; return; } } else if (light->type == LIGHTTYPE_DOME) { //ri_vector_copy(&(result->radiance), // &(light->col)); //ri_vector_scale(&(result->radiance), // (float)light->intensity); } } } #endif return; }
static int trace_path(pathnode_t *path) { unsigned char type; /* type of reflection */ int hit; int prev_interior; double bsdf[3]; ri_vector_t outdir; ri_ray_t ray; ri_intersection_state_t next_state; ri_material_t *material; if (path->depth >= MAX_PATH_VERTICES) { return 0; } material = path->state.geom->material; if (!russian_roulette(material)) { return 0; } type = sample_reflection_type(material); prev_interior = path->interior; if (path->interior && !floateq(material->ior, 1.0f)) { /* ray exits from a transparent object */ path->interior = 0; } sample_outdir(&outdir, &type, path->interior, material, path->indir, path->state.Ng); if (type == 'T' && prev_interior) { /* ray enters into a transparent object */ path->interior = 1; } /* find next surface point where ray hits */ ri_vector_copy(&ray.org, path->state.P); ri_vector_copy(&ray.dir, outdir); ray.thread_num = 0; hit = ri_raytrace(ri_render_get(), &ray, &next_state); if (!hit) { return 0; } brdf(bsdf, type, &path->state, path->indir, outdir, path->state.Ng); path->G[0] *= bsdf[0]; path->G[1] *= bsdf[1]; path->G[2] *= bsdf[2]; path->depth++; ri_vector_copy(&path->indir, outdir); //ri_vector_neg(&path->indir); ri_mem_copy(&path->state, &next_state, sizeof(ri_intersection_state_t)); return trace_path(path); }