#include "shader.h" #include "geoshader.h" #include "miaux.h" typedef struct { miTag name; miInteger count; miScalar root_radius; miScalar tip_radius; miVector center; miScalar length_min; miScalar length_max; miScalar spiral_turns_min; miScalar spiral_turns_max; miScalar spiral_radius_min; miScalar spiral_radius_max; miScalar segment_length; miInteger random_seed; } hair_geo_curl_t; DLLEXPORT int hair_geo_curl_version(void) { return 1; } void hair_geo_curl_bbox(miObject *obj, void* params) { hair_geo_curl_t *p = (hair_geo_curl_t*)params; obj->bbox_min.x = p->center.x - p->length_max; obj->bbox_min.y = p->center.y - p->length_max; obj->bbox_min.z = p->center.z - p->length_max; obj->bbox_max.x = p->center.x + p->length_max; obj->bbox_max.y = p->center.y + p->length_max; obj->bbox_max.z = p->center.z + p->length_max; } miBoolean hair_geo_curl_callback(miTag tag, void *ptr); DLLEXPORT miBoolean hair_geo_curl ( miTag *result, miState *state, hair_geo_curl_t *params ) { hair_geo_curl_t *p = (hair_geo_curl_t*)mi_mem_allocate(sizeof(hair_geo_curl_t)); p->name = *mi_eval_tag(¶ms->name); p->count = *mi_eval_integer(¶ms->count); p->root_radius = *mi_eval_scalar(¶ms->root_radius); p->tip_radius = *mi_eval_scalar(¶ms->tip_radius); p->center = *mi_eval_vector(¶ms->center); p->length_min = *mi_eval_scalar(¶ms->length_min); p->length_max = *mi_eval_scalar(¶ms->length_max); p->spiral_turns_min = *mi_eval_scalar(¶ms->spiral_turns_min); p->spiral_turns_max = *mi_eval_scalar(¶ms->spiral_turns_max); p->spiral_radius_min = *mi_eval_scalar(¶ms->spiral_radius_min); p->spiral_radius_max = *mi_eval_scalar(¶ms->spiral_radius_max); p->segment_length = *mi_eval_scalar(¶ms->segment_length); p->random_seed = *mi_eval_integer(¶ms->random_seed); miaux_define_hair_object( p->name, hair_geo_curl_bbox, p, result, hair_geo_curl_callback); return miTRUE; } typedef struct { miVector hair_end; int vertex_count; miScalar turns; miScalar spiral_radius; } hair_spec_t; int create_hair_specifications( hair_spec_t **hair_specs, hair_geo_curl_t *p) { float pi_2 = M_PI * 2.0; int scalars_per_vertex = 4, total_scalar_count = 0, i; *hair_specs = (hair_spec_t*)mi_mem_allocate(p->count * sizeof(hair_spec_t)); for (i = 0; i < p->count; i++) { miScalar distance, length; hair_spec_t *spec = &((*hair_specs)[i]); spec->turns = miaux_random_range(p->spiral_turns_min, p->spiral_turns_max); spec->spiral_radius = miaux_random_range(p->spiral_radius_min, p->spiral_radius_max); distance = miaux_random_range(p->length_min, p->length_max); length = distance + pi_2 * spec->spiral_radius * spec->turns; miaux_random_point_on_sphere( &(spec->hair_end), &p->center, distance); spec->vertex_count = (int)(ceil(length / p->segment_length)); total_scalar_count += spec->vertex_count * scalars_per_vertex; } return total_scalar_count; } miBoolean hair_geo_curl_callback(miTag tag, void *ptr) { miHair_list *hair; miGeoIndex *harray; hair_geo_curl_t *p = (hair_geo_curl_t*)ptr; hair_spec_t *hair_specs; int i, total_scalar_count, hair_array_position; miScalar *hair_scalars; mi_srandom(p->random_seed); mi_api_incremental(miTRUE); miaux_define_hair_object(p->name, hair_geo_curl_bbox, p, NULL, NULL); hair = mi_api_hair_begin(); hair->approx = hair->degree = 1; mi_api_hair_info(1, 'r', 1); total_scalar_count = create_hair_specifications(&hair_specs, p); hair_scalars = mi_api_hair_scalars_begin(total_scalar_count); for (i = 0; i < p->count; i++) { float angle_offset = miaux_random_range(0, M_PI * 2); miaux_hair_spiral( &hair_scalars, &p->center, &hair_specs[i].hair_end, hair_specs[i].turns, hair_specs[i].vertex_count, angle_offset, hair_specs[i].spiral_radius, p->root_radius, p->tip_radius); } mi_api_hair_scalars_end(total_scalar_count); harray = mi_api_hair_hairs_begin(p->count + 1); hair_array_position = 0; for (i = 0; i < p->count + 1; i++) { harray[i] = hair_array_position; if (i < p->count) hair_array_position += hair_specs[i].vertex_count * 4; } mi_api_hair_hairs_end(); mi_api_hair_end(); mi_api_object_end(); mi_mem_release(hair_specs); return miTRUE; }