Click on the filename to display or download the file.
channel_ramp.mi
declare shader
color "channel_ramp" (
array scalar "keys",
array scalar "r",
array scalar "g",
array scalar "b" )
version 1
apply environment, texture
end declare
channel_ramp.c
#include "shader.h"
#include "miaux.h"
#define RAMPSIZE 1024
typedef struct {
int r_size, g_size, b_size;
miScalar r[RAMPSIZE];
miScalar g[RAMPSIZE];
miScalar b[RAMPSIZE];
} channel_ramp_table;
struct channel_ramp {
int i_keys;
int n_keys;
miScalar keys[1];
int i_r;
int n_r;
miScalar r[1];
int i_g;
int n_g;
miScalar g[1];
int i_b;
int n_b;
miScalar b[1];
};
DLLEXPORT
int channel_ramp_version(void) { return 1; }
DLLEXPORT
miBoolean channel_ramp_init(
miState *state, struct channel_ramp *params, miBoolean *instance_init_required)
{
if (params == NULL) { /* Main shader init (not an instance) */
*instance_init_required = miTRUE;
} else { /* Instance initialization */
int n_keys, n_r, n_g, n_b;
miScalar *keys, *red, *green, *blue;
channel_ramp_table *ramp;
n_keys = *mi_eval_integer(¶ms->n_keys);
keys = mi_eval_scalar(params->keys) +
*mi_eval_integer(¶ms->i_keys);
if ((n_r = *mi_eval_integer(¶ms->n_r)) != n_keys)
mi_fatal("Incorrect number of red values: %d", n_r);
red = mi_eval_scalar(params->r) + *mi_eval_integer(¶ms->i_r);
if ((n_g = *mi_eval_integer(¶ms->n_g)) != n_keys)
mi_fatal("Incorrect number of green values: %d", n_g);
green = mi_eval_scalar(params->g) + *mi_eval_integer(¶ms->i_g);
if ((n_b = *mi_eval_integer(¶ms->n_b)) != n_keys)
mi_fatal("Incorrect number of blue values: %d", n_b);
blue = mi_eval_scalar(params->b) + *mi_eval_integer(¶ms->i_b);
ramp = miaux_user_memory_pointer(state, sizeof(channel_ramp_table));
miaux_piecewise_sinusoid(ramp->r, RAMPSIZE, n_keys, keys, red);
miaux_piecewise_sinusoid(ramp->g, RAMPSIZE, n_keys, keys, green);
miaux_piecewise_sinusoid(ramp->b, RAMPSIZE, n_keys, keys, blue);
}
return miTRUE;
}
DLLEXPORT
miBoolean channel_ramp_exit(miState *state, void *params)
{
return miaux_release_user_memory("channel_ramp", state, params);
}
DLLEXPORT
miBoolean channel_ramp (
miColor *result, miState *state, struct channel_ramp *params )
{
miScalar altitude = miaux_altitude(state);
channel_ramp_table *ramp = miaux_user_memory_pointer(state, 0);
result->r = miaux_interpolated_lookup(ramp->r, RAMPSIZE, altitude);
result->g = miaux_interpolated_lookup(ramp->g, RAMPSIZE, altitude);
result->b = miaux_interpolated_lookup(ramp->b, RAMPSIZE, altitude);
return miTRUE;
}
channel_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_sinusoid(
miScalar result[], int result_count,
int key_count, miScalar key_positions[], miScalar key_values[])
{
int key, i;
for (key = 1; key < key_count; key++) {
int start = (int)(key_positions[key-1] * result_count);
int end = (int)(key_positions[key] * result_count) - 1;
for (i = start; i <= end; i++) {
result[i] = miaux_sinusoid_fit(
i, start, end, key_values[key-1], key_values[key]);
}
}
}
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;
}
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);
}
miScalar miaux_interpolated_lookup(miScalar lookup_table[], int table_size,
miScalar t)
{
int lower_index = (int)(t * (table_size - 1));
miScalar lower_value = lookup_table[lower_index];
int upper_index = lower_index + 1;
miScalar upper_value = lookup_table[upper_index];
return miaux_fit(
t * table_size, lower_index, upper_index, lower_value, upper_value);
}
22 April 2008 23:40:48