Click on the filename to display or download the file.
color_ramp.mi
declare shader
color "color_ramp" (
array color "colors" )
version 1
apply environment, texture
end declare
color_ramp.c
#include "shader.h"
#include "miaux.h"
#define RAMPSIZE 1024
struct color_ramp {
int i_colors;
int n_colors;
miColor colors[1];
};
DLLEXPORT
int color_ramp_version(void) { return 1; }
DLLEXPORT
miBoolean color_ramp_init(
miState *state, struct color_ramp *params,
miBoolean *instance_init_required)
{
if (params == NULL) { /* Main shader init (not an instance) */
*instance_init_required = miTRUE;
} else { /* Instance initialization */
int n_colors = *mi_eval_integer(¶ms->n_colors);
miColor *colors =
mi_eval_color(params->colors) + *mi_eval_integer(¶ms->i_colors);
miColor *ramp =
miaux_user_memory_pointer(state, sizeof(miColor) * RAMPSIZE);
miaux_piecewise_color_sinusoid(ramp, RAMPSIZE, n_colors, colors);
}
return miTRUE;
}
DLLEXPORT
miBoolean color_ramp_exit(miState *state, void *params)
{
return miaux_release_user_memory("color_ramp", state, params);
}
DLLEXPORT
miBoolean color_ramp (
miColor *result, miState *state, struct color_ramp *params )
{
miColor *ramp = miaux_user_memory_pointer(state, 0);
miaux_interpolated_color_lookup(
result, ramp, RAMPSIZE, miaux_altitude(state));
return miTRUE;
}
color_ramp_util.c
void* miaux_user_memory_pointer(miState *state, int allocation_size)
{
void **user_pointer;
mi_query(miQ_FUNC_USERPTR, state, 0, &user_pointer);
if (allocation_size > 0) {
*user_pointer = mi_mem_allocate(allocation_size);
}
return *user_pointer;
}
void miaux_piecewise_color_sinusoid(
miColor result[], int result_count, int key_count, miColor key_values[])
{
int key, i;
for (key = 1; key < key_count; key++) {
int start = (int)(key_values[key-1].a * result_count);
int end = (int)(key_values[key].a * result_count) - 1;
for (i = start; i <= end; i++) {
result[i].r =
miaux_sinusoid_fit(
i, start, end, key_values[key-1].r, key_values[key].r);
result[i].g =
miaux_sinusoid_fit(
i, start, end, key_values[key-1].g, key_values[key].g);
result[i].b =
miaux_sinusoid_fit(
i, start, end, key_values[key-1].b, key_values[key].b);
}
}
}
double miaux_sinusoid_fit(
double v, double oldmin, double oldmax, double newmin, double newmax)
{
return miaux_fit(sin(miaux_fit(v, oldmin, oldmax, -M_PI_2, M_PI_2)),
-1, 1,
newmin, newmax);
}
double miaux_fit(
double v, double oldmin, double oldmax, double newmin, double newmax)
{
return newmin + ((v - oldmin) / (oldmax - oldmin)) * (newmax - newmin);
}
miBoolean miaux_release_user_memory(char* shader_name, miState *state, void *params)
{
if (params != NULL) { /* Shader instance exit */
void **user_pointer;
if (!mi_query(miQ_FUNC_USERPTR, state, 0, &user_pointer))
mi_fatal("Could not get user pointer in shader exit function %s_exit",
shader_name);
mi_mem_release(*user_pointer);
}
return miTRUE;
}
void miaux_interpolated_color_lookup(miColor* result,
miColor lookup_table[], int table_size,
miScalar t)
{
int lower_index = (int)(t * table_size);
miColor lower_value = lookup_table[lower_index];
int upper_index = lower_index + 1;
miColor upper_value = lookup_table[upper_index];
result->r = miaux_fit(t * table_size, lower_index, upper_index,
lower_value.r, upper_value.r);
result->g = miaux_fit(t * table_size, lower_index, upper_index,
lower_value.g, upper_value.g);
result->b = miaux_fit(t * table_size, lower_index, upper_index,
lower_value.b, upper_value.b);
}
float miaux_altitude(miState *state)
{
miVector ray;
mi_vector_to_world(state, &ray, &state->dir);
mi_vector_normalize(&ray);
return miaux_fit(asin(ray.y), -M_PI_2, M_PI_2, 0.0, 1.0);
}
22 April 2008 23:40:49