1 /*
2  * vp_context.c
3  *
4  * Routines to create, modify and destroy vpContext objects.
5  *
6  * Copyright (c) 1994 The Board of Trustees of The Leland Stanford
7  * Junior University.  All rights reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation for any purpose is hereby granted without fee, provided
11  * that the above copyright notice and this permission notice appear in
12  * all copies of this software and that you do not sell the software.
13  * Commercial licensing is available by contacting the author.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * Author:
20  *    Phil Lacroute
21  *    Computer Systems Laboratory
22  *    Electrical Engineering Dept.
23  *    Stanford University
24  */
25 
26 /*
27  * $Date: 1994/12/30 23:52:38 $
28  * $Revision: 1.28 $
29  */
30 
31 #include "vp_global.h"
32 
33 static void InitContext ANSI_ARGS((vpContext *vpc));
34 #ifdef HAVE_HIRES_TIMER
35 static void StartHiResTimer ANSI_ARGS((vpContext *vpc));
36 #endif
37 
38 #ifdef STATISTICS
39 int vpResampleCount = 0;
40 int vpCompositeCount = 0;
41 int vpERTSkipCount = 0;
42 int vpERTSkipAgainCount = 0;
43 int vpERTUpdateCount = 0;
44 int vpSpecialZeroSkipCount = 0;
45 int vpRunFragmentCount = 0;
46 #endif
47 
48 /*
49  * InitContext
50  *
51  * Initialize the fields of a context that have defaults.
52  */
53 
54 static void
InitContext(vpc)55 InitContext(vpc)
56 vpContext *vpc;
57 {
58     extern int read(), write();
59     int m, l;
60 
61     vpc->xlen = 0;
62     vpc->ylen = 0;
63     vpc->zlen = 0;
64     vpc->raw_bytes_per_voxel = 0;
65     vpc->num_voxel_fields = 0;
66     vpc->num_shade_fields = 0;
67     vpc->min_opacity = 0.0;
68     vpc->num_clsfy_params = 0;
69     vpc->color_channels = 1;
70     vpc->shading_mode = LOOKUP_SHADER;
71     vpc->num_materials = 1;
72     vpc->color_field = 0;
73     vpc->weight_field = 0;
74     for (m = 0; m < VP_MAX_MATERIAL; m++) {
75 	vpc->matl_props[m][EXT_SURFACE][MATL_AMB_R] = DEFAULT_AMBIENT;
76 	vpc->matl_props[m][EXT_SURFACE][MATL_DIFF_R] = DEFAULT_DIFFUSE;
77 	vpc->matl_props[m][EXT_SURFACE][MATL_SPEC_R] = DEFAULT_SPECULAR;
78 	vpc->matl_props[m][EXT_SURFACE][MATL_AMB_G] = DEFAULT_AMBIENT;
79 	vpc->matl_props[m][EXT_SURFACE][MATL_DIFF_G] = DEFAULT_DIFFUSE;
80 	vpc->matl_props[m][EXT_SURFACE][MATL_SPEC_G] = DEFAULT_SPECULAR;
81 	vpc->matl_props[m][EXT_SURFACE][MATL_AMB_B] = DEFAULT_AMBIENT;
82 	vpc->matl_props[m][EXT_SURFACE][MATL_DIFF_B] = DEFAULT_DIFFUSE;
83 	vpc->matl_props[m][EXT_SURFACE][MATL_SPEC_B] = DEFAULT_SPECULAR;
84 	vpc->matl_props[m][EXT_SURFACE][MATL_SHINY] = DEFAULT_SHINYNESS;
85 
86 	vpc->matl_props[m][INT_SURFACE][MATL_AMB_R] = DEFAULT_AMBIENT;
87 	vpc->matl_props[m][INT_SURFACE][MATL_DIFF_R] = DEFAULT_DIFFUSE;
88 	vpc->matl_props[m][INT_SURFACE][MATL_SPEC_R] = DEFAULT_SPECULAR;
89 	vpc->matl_props[m][INT_SURFACE][MATL_AMB_G] = DEFAULT_AMBIENT;
90 	vpc->matl_props[m][INT_SURFACE][MATL_DIFF_G] = DEFAULT_DIFFUSE;
91 	vpc->matl_props[m][INT_SURFACE][MATL_SPEC_G] = DEFAULT_SPECULAR;
92 	vpc->matl_props[m][INT_SURFACE][MATL_AMB_B] = DEFAULT_AMBIENT;
93 	vpc->matl_props[m][INT_SURFACE][MATL_DIFF_B] = DEFAULT_DIFFUSE;
94 	vpc->matl_props[m][INT_SURFACE][MATL_SPEC_B] = DEFAULT_SPECULAR;
95 	vpc->matl_props[m][INT_SURFACE][MATL_SHINY] = DEFAULT_SHINYNESS;
96     }
97     for (l = 0; l < VP_MAX_LIGHTS; l++) {
98 	vpc->light_enable[l] = 0;
99 	vpSetVector4(vpc->light_vector[l], 0.57735, 0.57735, 0.57735, 1.);
100 	vpSetVector3(vpc->light_color[l], 1., 1., 1.);
101     }
102     vpc->light_enable[0] = 1;
103     vpc->light_both_sides = 0;
104     vpc->reverse_surface_sides = 0;
105     vpc->dc_enable = 0;
106     vpc->dc_front_factor = 1.;
107     vpc->dc_density = 1.;
108     vpc->dc_quantization = DEFAULT_DC_QUANTIZATION;
109     vpIdentity4(vpc->transforms[VP_MODEL]);
110     vpIdentity4(vpc->transforms[VP_VIEW]);
111     vpIdentity4(vpc->transforms[VP_PROJECT]);
112     vpWindow(vpc, VP_PARALLEL, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5);
113     vpc->current_matrix = VP_MODEL;
114     vpc->concat_left = 0;
115     vpc->axis_override = VP_NO_AXIS;
116     vpc->max_opacity = 1.0;
117     vpc->factored_view_ready = 0;
118     vpc->int_image_width_hint = 0;
119     vpc->int_image_height_hint = 0;
120     vpc->clamp_shade_table = 1;
121     vpc->enable_shadows = 0;
122     vpc->shadow_light_num = VP_LIGHT0;
123     vpc->shadow_width_hint = 0;
124     vpc->shadow_height_hint = 0;
125     vpc->shadow_bias = 4;
126     vpc->write_func = write;
127     vpc->read_func = read;
128     vpc->mmap_func = NULL;
129     vpc->log_alloc_func = NULL;
130     vpc->log_free_func = NULL;
131     vpc->status_func = NULL;
132     vpc->client_data = NULL;
133     vpc->error_code = VP_OK;
134 #ifdef DEBUG
135     bzero(vpc->debug_enable, VPDEBUG_COUNT * sizeof(short));
136     vpc->trace_u = -1;
137     vpc->trace_v = -1;
138     vpc->trace_shadow_k = 0;
139 #endif
140 
141 #ifdef USE_TIMER
142     bzero(vpc->timer_ticks, VPTIMER_COUNT * sizeof(unsigned));
143 #ifdef HAVE_LORES_TIMER
144     vpc->timer_usec_per_tick = 1.0;
145 #endif
146 #ifdef HAVE_HIRES_TIMER
147     StartHiResTimer(vpc);
148 #endif
149 #endif /* USE_TIMER */
150 }
151 
152 /*
153  * vpCreateContext
154  *
155  * Create a rendering context.
156  */
157 
158 vpContext *
vpCreateContext()159 vpCreateContext()
160 {
161     vpContext *vpc;
162 
163     /* NOTE: cannot use Alloc() to allocate a context since it
164        requires a context as an argument */
165     if ((vpc = (vpContext *)malloc(sizeof(vpContext))) == NULL)
166 	VPBug("out of memory");
167     bzero(vpc, sizeof(vpContext));
168     InitContext(vpc);
169     return(vpc);
170 }
171 
172 /*
173  * vpDestroyContext
174  *
175  * Destroy a rendering context.
176  */
177 
178 void
vpDestroyContext(vpc)179 vpDestroyContext(vpc)
180 vpContext *vpc;
181 {
182     VPResizeDepthCueTable(vpc, 0, 0);
183     VPResizeRenderBuffers(vpc, 0, 0, 0);
184     vpDestroyClassifiedVolume(vpc);
185     vpDestroyMinMaxOctree(vpc);
186     if (vpc->sum_table != NULL)
187 	Dealloc(vpc, vpc->sum_table);
188     VPResizeShadowBuffer(vpc, 0, 0);
189 
190     /* NOTE: don't use Dealloc() to deallocate a context since
191        it wasn't created with Alloc() */
192     free((void *)vpc);
193 }
194 
195 /*
196  * vpSetVolumeSize
197  *
198  * Set the size of the volume.
199  */
200 
201 vpResult
vpSetVolumeSize(vpc,xlen,ylen,zlen)202 vpSetVolumeSize(vpc, xlen, ylen, zlen)
203 vpContext *vpc;
204 int xlen, ylen, zlen;
205 {
206     vpc->xlen = xlen;
207     vpc->ylen = ylen;
208     vpc->zlen = zlen;
209     vpc->factored_view_ready = 0;
210     vpDestroyClassifiedVolume(vpc);
211     vpDestroyMinMaxOctree(vpc);
212     return(VP_OK);
213 }
214 
215 /*
216  * vpSetVoxelSize
217  *
218  * Set the size of a voxel.
219  */
220 
221 vpResult
vpSetVoxelSize(vpc,bytes_per_voxel,num_voxel_fields,num_shade_fields,num_clsfy_fields)222 vpSetVoxelSize(vpc, bytes_per_voxel, num_voxel_fields, num_shade_fields,
223 	       num_clsfy_fields)
224 vpContext *vpc;
225 int bytes_per_voxel;
226 int num_voxel_fields;
227 int num_shade_fields;
228 int num_clsfy_fields;
229 {
230     if (num_voxel_fields >= VP_MAX_FIELDS)
231 	return(VPSetError(vpc, VPERROR_LIMIT_EXCEEDED));
232     if (num_clsfy_fields < 0 || num_clsfy_fields > num_voxel_fields)
233 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
234     if (num_shade_fields < 0 || num_shade_fields > num_voxel_fields)
235 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
236     vpc->raw_bytes_per_voxel = bytes_per_voxel;
237     vpc->num_voxel_fields = num_voxel_fields;
238     vpc->num_shade_fields = num_shade_fields;
239     vpc->num_clsfy_params = num_clsfy_fields;
240     vpDestroyClassifiedVolume(vpc);
241     vpDestroyMinMaxOctree(vpc);
242     return(VP_OK);
243 }
244 
245 /*
246  * vpSetVoxelField
247  *
248  * Set the size and position of a voxel field.
249  */
250 
251 vpResult
vpSetVoxelField(vpc,field_num,field_size,field_offset,field_max)252 vpSetVoxelField(vpc, field_num, field_size, field_offset, field_max)
253 vpContext *vpc;
254 int field_num;
255 int field_size;
256 int field_offset;
257 int field_max;
258 {
259     if (field_num < 0 || field_num >= vpc->num_voxel_fields)
260 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
261     if (field_size != 1 && field_size != 2 && field_size != 4)
262 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
263     if (field_offset < 0 || field_offset >= vpc->raw_bytes_per_voxel)
264 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
265     vpc->field_size[field_num] = field_size;
266     vpc->field_offset[field_num] = field_offset;
267     vpc->field_max[field_num] = field_max;
268     vpDestroyClassifiedVolume(vpc);
269     vpDestroyMinMaxOctree(vpc);
270     return(VP_OK);
271 }
272 
273 /*
274  * vpSetRawVoxels
275  *
276  * Set the array of unclassified voxels.
277  */
278 
279 vpResult
vpSetRawVoxels(vpc,raw_voxels,raw_voxels_size,xstride,ystride,zstride)280 vpSetRawVoxels(vpc, raw_voxels, raw_voxels_size, xstride, ystride, zstride)
281 vpContext *vpc;
282 int xstride, ystride, zstride;
283 void *raw_voxels;
284 int raw_voxels_size;
285 {
286     vpc->raw_voxels = raw_voxels;
287     vpc->raw_voxels_size = raw_voxels_size;
288     vpc->xstride = xstride;
289     vpc->ystride = ystride;
290     vpc->zstride = zstride;
291     if (raw_voxels_size != 0)
292 	vpDestroyClassifiedVolume(vpc);
293     vpDestroyMinMaxOctree(vpc);
294     return(VP_OK);
295 }
296 
297 /*
298  * vpSetClassifierTable
299  *
300  * Specify a lookup table for one of the classification function's
301  * parameters.
302  */
303 
304 vpResult
vpSetClassifierTable(vpc,param_num,param_field,table,table_size)305 vpSetClassifierTable(vpc, param_num, param_field, table, table_size)
306 vpContext *vpc;
307 int param_num;
308 int param_field;
309 float *table;
310 int table_size;
311 {
312     if (param_num < 0 || param_num >= vpc->num_clsfy_params)
313 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
314     if (param_field < 0 || param_field >= vpc->num_voxel_fields)
315 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
316     vpc->param_field[param_num] = param_field;
317     vpc->clsfy_table[param_num] = table;
318     vpc->clsfy_table_size[param_num] = table_size;
319     return(VP_OK);
320 }
321 
322 /*
323  * vpSetLookupShader
324  *
325  * Define a lookup shader.
326  */
327 
328 vpResult
vpSetLookupShader(vpc,color_channels,num_materials,color_field,color_table,color_table_size,weight_field,weight_table,weight_table_size)329 vpSetLookupShader(vpc, color_channels, num_materials,
330 		  color_field, color_table, color_table_size,
331 		  weight_field, weight_table, weight_table_size)
332 vpContext *vpc;
333 int color_channels;
334 int num_materials;
335 int color_field;
336 float *color_table;
337 int color_table_size;
338 int weight_field;
339 float *weight_table;
340 int weight_table_size;
341 {
342     if (color_channels != 1 && color_channels != 3)
343 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
344     if (num_materials <= 0 || num_materials >= VP_MAX_MATERIAL)
345 	return(VPSetError(vpc, VPERROR_LIMIT_EXCEEDED));
346     if (color_field < 0 || color_field >= vpc->num_voxel_fields ||
347 	color_table == NULL || color_table_size == 0)
348 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
349     if (num_materials > 1) {
350 	if (weight_field < 0 || weight_field >= vpc->num_voxel_fields ||
351 	    weight_table == NULL || weight_table_size == 0)
352 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
353     }
354     vpc->color_channels = color_channels;
355     vpc->shading_mode = LOOKUP_SHADER;
356     vpc->shade_color_table = color_table;
357     vpc->shade_color_table_size = color_table_size;
358     vpc->shade_weight_table = weight_table;
359     vpc->shade_weight_table_size = weight_table_size;
360     vpc->num_materials = num_materials;
361     vpc->color_field = color_field;
362     vpc->weight_field = weight_field;
363     return(VP_OK);
364 }
365 
366 /*
367  * vpSetShadowLookupShader
368  *
369  * Define a lookup shader that support shadows.
370  */
371 
372 vpResult
vpSetShadowLookupShader(vpc,color_channels,num_materials,color_field,color_table,color_table_size,weight_field,weight_table,weight_table_size,shadow_table,shadow_table_size)373 vpSetShadowLookupShader(vpc, color_channels, num_materials,
374 			color_field, color_table, color_table_size,
375 			weight_field, weight_table, weight_table_size,
376 			shadow_table, shadow_table_size)
377 vpContext *vpc;
378 int color_channels;
379 int num_materials;
380 int color_field;
381 float *color_table;
382 int color_table_size;
383 int weight_field;
384 float *weight_table;
385 int weight_table_size;
386 float *shadow_table;
387 int shadow_table_size;
388 {
389     if (color_channels != 1 && color_channels != 3)
390 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
391     if (num_materials <= 0 || num_materials >= VP_MAX_MATERIAL)
392 	return(VPSetError(vpc, VPERROR_LIMIT_EXCEEDED));
393     if (color_field < 0 || color_field >= vpc->num_voxel_fields ||
394 	color_table == NULL || color_table_size == 0)
395 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
396     if (num_materials > 1) {
397 	if (weight_field < 0 || weight_field >= vpc->num_voxel_fields ||
398 	    weight_table == NULL || weight_table_size == 0)
399 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
400     }
401     if (shadow_table_size != color_table_size)
402 	return(VPSetError(vpc, VPERROR_BAD_SIZE));
403     vpc->color_channels = color_channels;
404     vpc->shading_mode = LOOKUP_SHADER;
405     vpc->shade_color_table = color_table;
406     vpc->shade_color_table_size = color_table_size;
407     vpc->shade_weight_table = weight_table;
408     vpc->shade_weight_table_size = weight_table_size;
409     vpc->num_materials = num_materials;
410     vpc->color_field = color_field;
411     vpc->weight_field = weight_field;
412     vpc->shadow_color_table = shadow_table;
413     vpc->shadow_color_table_size = shadow_table_size;
414     return(VP_OK);
415 }
416 
417 /*
418  * vpSetMaterial
419  *
420  * Set material parameters.
421  */
422 
423 vpResult
vpSetMaterial(vpc,material,property,surface_side,r,g,b)424 vpSetMaterial(vpc, material, property, surface_side, r, g, b)
425 vpContext *vpc;
426 int material;
427 int property;
428 int surface_side;
429 double r, g, b;
430 {
431     material -= VP_MATERIAL0;
432     if (material < 0 || material >= vpc->num_materials)
433 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
434     if (surface_side == 0 || (surface_side & ~VP_BOTH_SIDES) != 0)
435 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
436     if (property != VP_SHINYNESS) {
437 	if (r < 0. || g < 0. || b < 0.)
438 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
439     }
440     switch (property) {
441     case VP_AMBIENT:
442 	if (surface_side & VP_EXTERIOR) {
443 	    vpc->matl_props[material][EXT_SURFACE][MATL_AMB_R] = r * 255.;
444 	    vpc->matl_props[material][EXT_SURFACE][MATL_AMB_G] = g * 255.;
445 	    vpc->matl_props[material][EXT_SURFACE][MATL_AMB_B] = b * 255.;
446 	}
447 	if (surface_side & VP_INTERIOR) {
448 	    vpc->matl_props[material][INT_SURFACE][MATL_AMB_R] = r * 255.;
449 	    vpc->matl_props[material][INT_SURFACE][MATL_AMB_G] = g * 255.;
450 	    vpc->matl_props[material][INT_SURFACE][MATL_AMB_B] = b * 255.;
451 	}
452 	break;
453     case VP_DIFFUSE:
454 	if (surface_side & VP_EXTERIOR) {
455 	    vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_R] = r * 255.;
456 	    vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_G] = g * 255.;
457 	    vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_B] = b * 255.;
458 	}
459 	if (surface_side & VP_INTERIOR) {
460 	    vpc->matl_props[material][INT_SURFACE][MATL_DIFF_R] = r * 255.;
461 	    vpc->matl_props[material][INT_SURFACE][MATL_DIFF_G] = g * 255.;
462 	    vpc->matl_props[material][INT_SURFACE][MATL_DIFF_B] = b * 255.;
463 	}
464 	break;
465     case VP_SPECULAR:
466 	if (surface_side & VP_EXTERIOR) {
467 	    vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_R] = r * 255.;
468 	    vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_G] = g * 255.;
469 	    vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_B] = b * 255.;
470 	}
471 	if (surface_side & VP_INTERIOR) {
472 	    vpc->matl_props[material][INT_SURFACE][MATL_SPEC_R] = r * 255.;
473 	    vpc->matl_props[material][INT_SURFACE][MATL_SPEC_G] = g * 255.;
474 	    vpc->matl_props[material][INT_SURFACE][MATL_SPEC_B] = b * 255.;
475 	}
476 	break;
477     case VP_SHINYNESS:
478 	if (surface_side & VP_EXTERIOR)
479 	    vpc->matl_props[material][EXT_SURFACE][MATL_SHINY] = r;
480 	if (surface_side & VP_INTERIOR)
481 	    vpc->matl_props[material][INT_SURFACE][MATL_SHINY] = r;
482 	break;
483     default:
484 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
485     }
486     return(VP_OK);
487 }
488 
489 /*
490  * vpSetLight
491  *
492  * Set the properties of a directional light source.
493  */
494 
495 vpResult
vpSetLight(vpc,light_num,property,n0,n1,n2)496 vpSetLight(vpc, light_num, property, n0, n1, n2)
497 vpContext *vpc;
498 int light_num;
499 int property;
500 double n0, n1, n2;
501 {
502     vpVector4 v1, v2;
503 
504     light_num -= VP_LIGHT0;
505     if (light_num < 0 || light_num >= VP_MAX_LIGHTS)
506 	return(VPSetError(vpc, VPERROR_LIMIT_EXCEEDED));
507     switch (property) {
508     case VP_DIRECTION:
509 	vpSetVector4(v1, n0, n1, n2, 1.);
510 	if (vpNormalize3(v1) != VP_OK)
511 	    return(VPSetError(vpc, VPERROR_SINGULAR));
512 	vpMatrixVectorMult4(v2, vpc->transforms[VP_MODEL], v1);
513 	vpc->light_vector[light_num][0] = v2[0];
514 	vpc->light_vector[light_num][1] = v2[1];
515 	vpc->light_vector[light_num][2] = v2[2];
516 	vpc->light_vector[light_num][3] = v2[3];
517 	break;
518     case VP_COLOR:
519 	if (n0 < 0. || n0 > 1. || n1 < 0. || n1 > 1. || n2 < 0. || n2 > 1.)
520 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
521 	vpc->light_color[light_num][0] = n0;
522 	vpc->light_color[light_num][1] = n1;
523 	vpc->light_color[light_num][2] = n2;
524 	break;
525     default:
526 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
527     }
528     return(VP_OK);
529 }
530 
531 /*
532  * vpEnable
533  *
534  * Enable or disable an option.
535  */
536 
537 vpResult
vpEnable(vpc,option,value)538 vpEnable(vpc, option, value)
539 vpContext *vpc;
540 int option;
541 int value;
542 {
543     switch (option) {
544     case VP_LIGHT0:
545     case VP_LIGHT1:
546     case VP_LIGHT2:
547     case VP_LIGHT3:
548     case VP_LIGHT4:
549     case VP_LIGHT5:
550 	if (value == 0)
551 	    vpc->light_enable[option - VP_LIGHT0] = 0;
552 	else
553 	    vpc->light_enable[option - VP_LIGHT0] = 1;
554 	break;
555     case VP_LIGHT_BOTH_SIDES:
556 	if (value == 0)
557 	    vpc->light_both_sides = 0;
558 	else
559 	    vpc->light_both_sides = 1;
560 	break;
561     case VP_REVERSE_SURFACE_SIDES:
562 	if (value == 0)
563 	    vpc->reverse_surface_sides = 0;
564 	else
565 	    vpc->reverse_surface_sides = 1;
566 	break;
567     case VP_DEPTH_CUE:
568 	if (value == 0)
569 	    vpc->dc_enable = 0;
570 	else
571 	    vpc->dc_enable = 1;
572 	break;
573     case VP_VIEW_X_AXIS:
574 	if (value == 0)
575 	    vpc->skip_rle_x = 1;
576 	else
577 	    vpc->skip_rle_x = 0;
578 	break;
579     case VP_VIEW_Y_AXIS:
580 	if (value == 0)
581 	    vpc->skip_rle_y = 1;
582 	else
583 	    vpc->skip_rle_y = 0;
584 	break;
585     case VP_VIEW_Z_AXIS:
586 	if (value == 0)
587 	    vpc->skip_rle_z = 1;
588 	else
589 	    vpc->skip_rle_z = 0;
590 	break;
591     case VP_SHADOW:
592 	if (value == 0) {
593 	    vpc->enable_shadows = 0;
594 	} else {
595 	    vpc->enable_shadows = 1;
596 	}
597 	vpc->factored_view_ready = 0;
598 	break;
599     case VP_CLAMP_SHADE_TABLE:
600 	if (value == 0)
601 	    vpc->clamp_shade_table = 0;
602 	else
603 	    vpc->clamp_shade_table = 1;
604 	break;
605     default:
606 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
607     }
608     return(VP_OK);
609 }
610 
611 /*
612  * vpSetDepthCueing
613  *
614  * Set depth cueing parameters.
615  */
616 
617 vpResult
vpSetDepthCueing(vpc,front_factor,density)618 vpSetDepthCueing(vpc, front_factor, density)
619 vpContext *vpc;
620 double front_factor;
621 double density;
622 {
623     if (front_factor <= 0.)
624 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
625     vpc->dc_front_factor = front_factor;
626     vpc->dc_density = density;
627     if (vpc->dc_table_len > 0)
628 	VPComputeDepthCueTable(vpc, 0, vpc->dc_table_len-1);
629     return(VP_OK);
630 }
631 
632 /*
633  * vpCurrentMatrix
634  *
635  * Set the current matrix.
636  */
637 
638 vpResult
vpCurrentMatrix(vpc,option)639 vpCurrentMatrix(vpc, option)
640 vpContext *vpc;
641 int option;
642 {
643     switch (option) {
644     case VP_MODEL:
645     case VP_VIEW:
646     case VP_PROJECT:
647 	vpc->current_matrix = option;
648 	break;
649     default:
650 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
651     }
652     return(VP_OK);
653 }
654 
655 /*
656  * vpIdentityMatrix
657  *
658  * Load the identity into the current matrix.
659  */
660 
661 vpResult
vpIdentityMatrix(vpc)662 vpIdentityMatrix(vpc)
663 vpContext *vpc;
664 {
665     vpIdentity4(vpc->transforms[vpc->current_matrix]);
666     vpc->factored_view_ready = 0;
667     return(VP_OK);
668 }
669 
670 /*
671  * vpSetMatrix
672  *
673  * Load the elements of the current matrix.
674  */
675 
676 vpResult
vpSetMatrix(vpc,matrix)677 vpSetMatrix(vpc, matrix)
678 vpContext *vpc;
679 vpMatrix4 matrix;
680 {
681     bcopy(matrix, vpc->transforms[vpc->current_matrix], sizeof(vpMatrix4));
682     vpc->factored_view_ready = 0;
683     return(VP_OK);
684 }
685 
686 /*
687  * vpGetMatrix
688  *
689  * Get the elements of the indicated matrix.
690  */
691 
692 vpResult
vpGetMatrix(vpc,matrix_code,matrix)693 vpGetMatrix(vpc, matrix_code, matrix)
694 vpContext *vpc;
695 int matrix_code;
696 vpMatrix4 matrix;
697 {
698     switch (matrix_code) {
699     case VP_MODEL:
700     case VP_VIEW:
701     case VP_PROJECT:
702 	bcopy(vpc->transforms[matrix_code], matrix, sizeof(vpMatrix4));
703 	break;
704     case VP_SCREEN:
705 	VPComputeViewTransform(vpc, matrix);
706 	break;
707     default:
708 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
709     }
710     return(VP_OK);
711 }
712 
713 /*
714  * vpMultMatrix
715  *
716  * Multiply the current matrix by the given matrix.
717  */
718 
719 vpResult
vpMultMatrix(vpc,matrix)720 vpMultMatrix(vpc, matrix)
721 vpContext *vpc;
722 vpMatrix4 matrix;
723 {
724     vpMatrix4 tmp;
725 
726     if (vpc->concat_left)
727 	vpMatrixMult4(tmp, matrix, vpc->transforms[vpc->current_matrix]);
728     else
729 	vpMatrixMult4(tmp, vpc->transforms[vpc->current_matrix], matrix);
730     bcopy(tmp, vpc->transforms[vpc->current_matrix], sizeof(vpMatrix4));
731     vpc->factored_view_ready = 0;
732     return(VP_OK);
733 }
734 
735 /*
736  * vpTranslate
737  *
738  * Multiply the current matrix by a translation matrix.
739  */
740 
741 vpResult
vpTranslate(vpc,tx,ty,tz)742 vpTranslate(vpc, tx, ty, tz)
743 vpContext *vpc;
744 double tx, ty, tz;
745 {
746     vpMatrix4 t, tmp;
747 
748     VPLoadTranslation(t, tx, ty, tz);
749     if (vpc->concat_left)
750 	vpMatrixMult4(tmp, t, vpc->transforms[vpc->current_matrix]);
751     else
752 	vpMatrixMult4(tmp, vpc->transforms[vpc->current_matrix], t);
753     bcopy(tmp, vpc->transforms[vpc->current_matrix], sizeof(vpMatrix4));
754     vpc->factored_view_ready = 0;
755     return(VP_OK);
756 }
757 
758 /*
759  * vpRotate
760  *
761  * Multiply the current matrix by a rotation matrix.
762  */
763 
764 vpResult
vpRotate(vpc,axis,degrees)765 vpRotate(vpc, axis, degrees)
766 vpContext *vpc;
767 int axis;
768 double degrees;
769 {
770     vpMatrix4 r, tmp;
771 
772     if (axis != VP_X_AXIS && axis != VP_Y_AXIS && axis != VP_Z_AXIS)
773 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
774     VPLoadRotation(r, axis, degrees);
775     if (vpc->concat_left)
776 	vpMatrixMult4(tmp, r, vpc->transforms[vpc->current_matrix]);
777     else
778 	vpMatrixMult4(tmp, vpc->transforms[vpc->current_matrix], r);
779     bcopy(tmp, vpc->transforms[vpc->current_matrix], sizeof(vpMatrix4));
780     vpc->factored_view_ready = 0;
781     return(VP_OK);
782 }
783 
784 /*
785  * vpScale
786  *
787  * Multiply the current matrix by a scale matrix.
788  */
789 
790 vpResult
vpScale(vpc,sx,sy,sz)791 vpScale(vpc, sx, sy, sz)
792 vpContext *vpc;
793 double sx, sy, sz;
794 {
795     vpMatrix4 s, tmp;
796 
797     VPLoadScale(s, sx, sy, sz);
798     if (vpc->concat_left)
799 	vpMatrixMult4(tmp, s, vpc->transforms[vpc->current_matrix]);
800     else
801 	vpMatrixMult4(tmp, vpc->transforms[vpc->current_matrix], s);
802     bcopy(tmp, vpc->transforms[vpc->current_matrix], sizeof(vpMatrix4));
803     vpc->factored_view_ready = 0;
804     return(VP_OK);
805 }
806 
807 /*
808  * vpWindow
809  *
810  * Set the projection matrix for a perspective or
811  * orthographic viewing volume.
812  */
813 
814 vpResult
vpWindow(vpc,type,left,right,bottom,top,near,far)815 vpWindow(vpc, type, left, right, bottom, top, near, far)
816 vpContext *vpc;
817 int type;
818 double left, right, bottom, top, near, far;
819 {
820     vpMatrix4 projectm, tmp;
821 
822     if (left >= right || bottom >= top || near >= far)
823 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
824     if (type == VP_PERSPECTIVE) {
825 	if (near <= 0 || far <= 0)
826 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
827     } else if (type != VP_PARALLEL) {
828 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
829     }
830 
831     vpIdentity4(projectm);
832     if (type == VP_PARALLEL) {
833 	projectm[0][0] = 2. / (right - left);
834 	projectm[1][1] = 2. / (top - bottom);
835 	projectm[2][2] = 2. / (far - near);
836 	projectm[0][3] = (left + right) / (left - right);
837 	projectm[1][3] = (bottom + top) / (bottom - top);
838 	projectm[2][3] = (near + far) / (near - far);
839     } else {
840 	/* XXX perspective rendering not available yet */
841 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
842 #ifdef notdef
843 	projectm[0][0] = 2. * near / (right - left);
844 	projectm[1][1] = 2. * near / (top - bottom);
845 	projectm[2][2] = (near + far) / (near - far);
846 	projectm[0][2] = (right + left) / (right - left);
847 	projectm[1][2] = (top + bottom) / (top - bottom);
848 	projectm[3][2] = -1.;
849 	projectm[2][3] = 2. * far * near / (near - far);
850 #endif
851     }
852     if (vpc->concat_left)
853 	vpMatrixMult4(tmp, projectm, vpc->transforms[VP_PROJECT]);
854     else
855 	vpMatrixMult4(tmp, vpc->transforms[VP_PROJECT], projectm);
856     bcopy(tmp, vpc->transforms[VP_PROJECT], sizeof(vpMatrix4));
857     vpc->factored_view_ready = 0;
858     return(VP_OK);
859 }
860 
861 /*
862  * vpWindowPHIGS
863  *
864  * Setting the projection matrix using a PHIGS view specification.
865  */
866 
867 vpResult
vpWindowPHIGS(vpc,vrp,vpn,vup,prp,viewport_umin,viewport_umax,viewport_vmin,viewport_vmax,viewport_front,viewport_back,projection_type)868 vpWindowPHIGS(vpc, vrp, vpn, vup, prp, viewport_umin, viewport_umax,
869 	      viewport_vmin, viewport_vmax, viewport_front, viewport_back,
870 	      projection_type)
871 vpContext *vpc;
872 vpVector3 vrp;
873 vpVector3 vpn;
874 vpVector3 vup;
875 vpVector3 prp;
876 double viewport_umin;
877 double viewport_umax;
878 double viewport_vmin;
879 double viewport_vmax;
880 double viewport_front;
881 double viewport_back;
882 int projection_type;
883 {
884     vpMatrix4 m1, m2, m3;
885     double cw_x, cw_y;	/* center of window */
886     double newz;
887 
888     if (viewport_umax <= viewport_umin || viewport_vmax <= viewport_vmin ||
889 	viewport_front <= viewport_back)
890 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
891     if (projection_type != VP_PARALLEL && projection_type != VP_PERSPECTIVE)
892 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
893 
894     /* perspective rendering not available yet */
895     if (projection_type == VP_PERSPECTIVE)
896 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
897 
898     /* translate view reference point to the origin */
899     VPLoadTranslation(m1, -vrp[0], -vrp[1], -vrp[2]);
900 
901     /* rotate VRC axes into world coordinate axes */
902     vpIdentity4(m2);
903     m2[2][0] = vpn[0];
904     m2[2][1] = vpn[1];
905     m2[2][2] = vpn[2];
906     if (vpNormalize3(m2[2]) != VP_OK)
907 	return(VPSetError(vpc, VPERROR_SINGULAR));
908     vpCrossProduct(m2[0], vup, m2[2]);
909     if (vpNormalize3(m2[0]) != VP_OK)
910 	return(VPSetError(vpc, VPERROR_SINGULAR));
911     vpCrossProduct(m2[1], m2[2], m2[0]);
912     vpMatrixMult4(m3, m2, m1);
913 
914     if (projection_type == VP_PERSPECTIVE) {
915 	/* translate center of projection to the origin */
916 	VPLoadTranslation(m1, -prp[0], -prp[1], -prp[2]);
917 	vpMatrixMult4(m2, m1, m3);
918 	bcopy(m2, m3, sizeof(vpMatrix4));
919     }
920 
921     /* shear to make DOP equal to the z axis */
922     if (fabs(prp[2]) < VP_EPS)
923 	return(VPSetError(vpc, VPERROR_SINGULAR));
924     vpIdentity4(m1);
925     cw_x = 0.5 * (viewport_umin + viewport_umax);
926     cw_y = 0.5 * (viewport_vmin + viewport_vmax);
927     m1[0][2] = (cw_x - prp[0]) / prp[2];
928     m1[1][2] = (cw_y - prp[1]) / prp[2];
929     vpMatrixMult4(m2, m1, m3);
930 
931     if (projection_type == VP_PARALLEL) {
932 	/* translate to clip origin */
933 	VPLoadTranslation(m3, -cw_x, -cw_y, -viewport_back);
934 	vpMatrixMult4(m1, m3, m2);
935 
936 	/* scale to clip coordinates */
937 	VPLoadScale(m2, 2. / (viewport_umax - viewport_umin),
938 		    2. / (viewport_vmax - viewport_vmin),
939 		    1. / (viewport_front - viewport_back));
940 	vpMatrixMult4(m3, m2, m1);
941     } else {
942 	/* scale into canonical perspective view volume */
943 	if (fabs(prp[2] - viewport_back) < VP_EPS)
944 	    return(VPSetError(vpc, VPERROR_SINGULAR));
945 	vpIdentity4(m3);
946 	m3[0][0] = 2*prp[2] / ((viewport_umax - viewport_umin) *
947 			       (prp[2] - viewport_back));
948 	m3[1][1] = 2*prp[2] / ((viewport_vmax - viewport_vmin) *
949 			       (prp[2] - viewport_back));
950 	m3[2][2] = 1. / (prp[2] - viewport_back);
951 	vpMatrixMult4(m1, m3, m2);
952 
953 	/* transform into clip coordinates */
954 	vpIdentity4(m2);
955 	newz = (prp[2] - viewport_front) / (viewport_back - prp[2]);
956 	m2[2][2] = 1. / (1. + newz);
957 	m2[2][3] = newz / (-1. - newz);
958 	m2[3][2] = -1.;
959 	m2[3][3] = 0.;
960 	vpMatrixMult4(m3, m2, m1);
961     }
962     if (vpc->concat_left)
963 	vpMatrixMult4(m1, m3, vpc->transforms[VP_PROJECT]);
964     else
965 	vpMatrixMult4(m1, vpc->transforms[VP_PROJECT], m3);
966     bcopy(m1, vpc->transforms[VP_PROJECT], sizeof(vpMatrix4));
967     vpc->factored_view_ready = 0;
968     return(VP_OK);
969 }
970 
971 /*
972  * vpSetImage
973  *
974  * Set the buffer to store the image into.
975  */
976 
977 vpResult
vpSetImage(vpc,image,width,height,bytes_per_scan,pixel_type)978 vpSetImage(vpc, image, width, height, bytes_per_scan, pixel_type)
979 vpContext *vpc;
980 unsigned char *image;
981 int width, height;
982 int bytes_per_scan;
983 int pixel_type;
984 {
985     int bytes_per_pixel;
986 
987     /* check for errors */
988     switch (pixel_type) {
989     case VP_ALPHA:
990     case VP_LUMINANCE:
991 	bytes_per_pixel = 1;
992 	break;
993     case VP_LUMINANCEA:
994 	bytes_per_pixel = 2;
995 	break;
996     case VP_RGB:
997     case VP_BGR:
998 	bytes_per_pixel = 3;
999 	break;
1000     case VP_RGBA:
1001     case VP_ABGR:
1002 	bytes_per_pixel = 4;
1003 	break;
1004     default:
1005 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1006     }
1007     if (bytes_per_scan < width * bytes_per_pixel)
1008 	return(VPSetError(vpc, VPERROR_BAD_SIZE));
1009 
1010     /* update context */
1011     if (width != vpc->image_width || height != vpc->image_height) {
1012 	vpc->image_width = width;
1013 	vpc->image_height = height;
1014 	vpc->factored_view_ready = 0;
1015     }
1016     vpc->image = image;
1017     vpc->image_bytes_per_scan = bytes_per_scan;
1018     vpc->pixel_type = pixel_type;
1019     return(VP_OK);
1020 }
1021 
1022 /*
1023  * vpSeti
1024  *
1025  * Set a rendering option with an integer value.
1026  */
1027 
1028 vpResult
vpSeti(vpc,option,value)1029 vpSeti(vpc, option, value)
1030 vpContext *vpc;
1031 int option;
1032 int value;
1033 {
1034     switch (option) {
1035     case VP_CONCAT_MODE:
1036 	if (value == VP_CONCAT_LEFT)
1037 	    vpc->concat_left = 1;
1038 	else if (value == VP_CONCAT_RIGHT)
1039 	    vpc->concat_left = 0;
1040 	else
1041 	    return(VPSetError(vpc, VPERROR_BAD_OPTION));
1042 	break;
1043     case VP_DEPTH_CUE_SIZE_HINT:
1044 	if (value < 0)
1045 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1046 	vpc->dc_table_len_hint = value;
1047 	break;
1048     case VP_INT_WIDTH_HINT:
1049 	if (value < 0)
1050 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1051 	vpc->int_image_width_hint = value;
1052 	break;
1053     case VP_INT_HEIGHT_HINT:
1054 	if (value < 0)
1055 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1056 	vpc->int_image_height_hint = value;
1057 	break;
1058     case VP_SHADOW_LIGHT:
1059 	if (value < VP_LIGHT0 || value > VP_LIGHT5)
1060 	    return(VPSetError(vpc, VPERROR_BAD_OPTION));
1061 	vpc->shadow_light_num = value;
1062 	break;
1063     case VP_SHADOW_WIDTH_HINT:
1064 	if (value < 0)
1065 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1066 	vpc->shadow_width_hint = value;
1067 	break;
1068     case VP_SHADOW_HEIGHT_HINT:
1069 	if (value < 0)
1070 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1071 	vpc->shadow_height_hint = value;
1072 	break;
1073     case VP_SHADOW_BIAS:
1074 	if (value < 0)
1075 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1076 	vpc->shadow_bias = value;
1077 	vpc->factored_view_ready = 0;
1078 	break;
1079     case VP_AXIS_OVERRIDE:
1080 	switch (value) {
1081 	case VP_X_AXIS:
1082 	case VP_Y_AXIS:
1083 	case VP_Z_AXIS:
1084 	case VP_NO_AXIS:
1085 	    vpc->axis_override = value;
1086 	    break;
1087 	default:
1088 	    return(VPSetError(vpc, VPERROR_BAD_OPTION));
1089 	    break;
1090 	}
1091 	vpc->factored_view_ready = 0;
1092 	break;
1093     case VP_TRACE_SHADOW_K:
1094 #ifdef DEBUG
1095 	vpc->trace_shadow_k = value;
1096 #endif
1097 	break;
1098     default:
1099 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1100     }
1101     return(VP_OK);
1102 }
1103 
1104 /*
1105  * vpSetd
1106  *
1107  * Set a rendering option with a double-precision value.
1108  */
1109 
1110 vpResult
vpSetd(vpc,option,value)1111 vpSetd(vpc, option, value)
1112 vpContext *vpc;
1113 int option;
1114 double value;
1115 {
1116     switch (option) {
1117     case VP_DEPTH_CUE_QUANTIZATION:
1118 	if (value <= 0. || value >= 1.)
1119 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1120 	vpc->dc_quantization = value;
1121 	VPResizeDepthCueTable(vpc, 0, 0);
1122 	break;
1123     case VP_MAX_RAY_OPACITY:
1124 	if (value < 0. || value > 1.)
1125 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1126 	vpc->max_opacity = value;
1127 	break;
1128     case VP_MIN_VOXEL_OPACITY:
1129 	if ((value < 0. || value > 1.) && value != -1.0)
1130 	    return(VPSetError(vpc, VPERROR_BAD_VALUE));
1131 	vpc->min_opacity = value;
1132 	break;
1133     default:
1134 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1135     }
1136     return(VP_OK);
1137 }
1138 
1139 /*
1140  * vpMinMaxOctreeThreshold
1141  *
1142  * Set the threshold of a parameter for constructing the min-max octree.
1143  */
1144 
1145 vpResult
vpMinMaxOctreeThreshold(vpc,param,range)1146 vpMinMaxOctreeThreshold(vpc, param, range)
1147 vpContext *vpc;
1148 int param;
1149 int range;
1150 {
1151     if (param >= vpc->num_clsfy_params)
1152 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
1153     vpc->param_maxrange[param] = range;
1154     return(VP_OK);
1155 }
1156 
1157 /*
1158  * vpSetCallback
1159  *
1160  * Set one of the callback functions.
1161  */
1162 
1163 vpResult
vpSetCallback(vpc,option,func)1164 vpSetCallback(vpc, option, func)
1165 vpContext *vpc;
1166 int option;
1167 void *func;
1168 {
1169     extern int read(), write();
1170 
1171     switch (option) {
1172     case VP_LOG_ALLOC_FUNC:
1173 	vpc->log_alloc_func = func;
1174 	break;
1175     case VP_LOG_FREE_FUNC:
1176 	vpc->log_free_func = func;
1177 	break;
1178     case VP_STATUS_FUNC:
1179 	vpc->status_func = func;
1180 	break;
1181     case VP_READ_FUNC:
1182 	if (func == NULL)
1183 	    vpc->read_func = read;
1184 	else
1185 	    vpc->read_func = func;
1186 	break;
1187     case VP_WRITE_FUNC:
1188 	if (func == NULL)
1189 	    vpc->write_func = write;
1190 	else
1191 	    vpc->write_func = func;
1192 	break;
1193     case VP_MMAP_FUNC:
1194 	vpc->mmap_func = func;
1195 	break;
1196     case VP_GRAY_SHADE_FUNC:
1197 	if (func == NULL) {
1198 	    vpc->shading_mode = LOOKUP_SHADER;
1199 	} else {
1200 	    vpc->color_channels = 1;
1201 	    vpc->shading_mode = CALLBACK_SHADER;
1202 	    vpc->shade_func = func;
1203 	}
1204 	break;
1205     case VP_RGB_SHADE_FUNC:
1206 	if (func == NULL) {
1207 	    vpc->shading_mode = LOOKUP_SHADER;
1208 	} else {
1209 	    vpc->color_channels = 3;
1210 	    vpc->shading_mode = CALLBACK_SHADER;
1211 	    vpc->shade_func = func;
1212 	}
1213 	break;
1214     default:
1215 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1216     }
1217     return(VP_OK);
1218 }
1219 
1220 /*
1221  * vpSetClientData
1222  *
1223  * Set the client_data hook.
1224  */
1225 
1226 vpResult
vpSetClientData(vpc,client_data)1227 vpSetClientData(vpc, client_data)
1228 vpContext *vpc;
1229 void *client_data;
1230 {
1231     vpc->client_data = client_data;
1232     return(VP_OK);
1233 }
1234 
1235 /*
1236  * vpSetDebug
1237  *
1238  * Set the value of a debugging flag.
1239  */
1240 
1241 vpResult
vpSetDebug(vpc,flag,value)1242 vpSetDebug(vpc, flag, value)
1243 vpContext *vpc;
1244 int flag;
1245 int value;
1246 {
1247     if (flag < 0 || flag >= VPDEBUG_COUNT)
1248 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1249 #ifdef DEBUG
1250     vpc->debug_enable[flag] = value;
1251 #endif
1252     return(VP_OK);
1253 }
1254 
1255 /*
1256  * vpTracePixel
1257  *
1258  * Trace one pixel of the intermediate image.
1259  */
1260 
1261 vpResult
vpTracePixel(vpc,trace_u,trace_v)1262 vpTracePixel(vpc, trace_u, trace_v)
1263 vpContext *vpc;
1264 int trace_u, trace_v;	/* pixel coordinates */
1265 {
1266 #ifdef DEBUG
1267     vpc->trace_u = trace_u;
1268     vpc->trace_v = trace_v;
1269 #endif
1270     return(VP_OK);
1271 }
1272 
1273 /*
1274  * vpGeti
1275  *
1276  * Retrieve an integer-valued piece of state.
1277  */
1278 
1279 vpResult
vpGeti(vpc,option,iptr)1280 vpGeti(vpc, option, iptr)
1281 vpContext *vpc;
1282 int option;
1283 int *iptr;
1284 {
1285     int c;
1286     int retcode;
1287 
1288     switch (option) {
1289     case VP_XLEN:
1290 	*iptr = vpc->xlen;
1291 	break;
1292     case VP_YLEN:
1293 	*iptr = vpc->ylen;
1294 	break;
1295     case VP_ZLEN:
1296 	*iptr = vpc->zlen;
1297 	break;
1298     case VP_BYTES_PER_VOXEL:
1299 	*iptr = vpc->raw_bytes_per_voxel;
1300 	break;
1301     case VP_VOXEL_FIELD_COUNT:
1302 	*iptr = vpc->num_voxel_fields;
1303 	break;
1304     case VP_SHADE_FIELD_COUNT:
1305 	*iptr = vpc->num_shade_fields;
1306 	break;
1307     case VP_FIELD_SIZES:
1308 	for (c = 0; c < vpc->num_voxel_fields; c++)
1309 	    iptr[c] = vpc->field_size[c];
1310 	break;
1311     case VP_FIELD_OFFSETS:
1312 	for (c = 0; c < vpc->num_voxel_fields; c++)
1313 	    iptr[c] = vpc->field_offset[c];
1314 	break;
1315     case VP_FIELD_MAXES:
1316 	for (c = 0; c < vpc->num_voxel_fields; c++)
1317 	    iptr[c] = vpc->field_max[c];
1318 	break;
1319     case VP_VOXEL_DATA_SIZE:
1320 	*iptr = vpc->raw_voxels_size;
1321 	break;
1322     case VP_VOXEL_XSTRIDE:
1323 	*iptr = vpc->xstride;
1324 	break;
1325     case VP_VOXEL_YSTRIDE:
1326 	*iptr = vpc->ystride;
1327 	break;
1328     case VP_VOXEL_ZSTRIDE:
1329 	*iptr = vpc->zstride;
1330 	break;
1331     case VP_CLASSIFY_FIELD_COUNT:
1332 	*iptr = vpc->num_clsfy_params;
1333 	break;
1334     case VP_CLASSIFY_FIELDS:
1335 	for (c = 0; c < vpc->num_clsfy_params; c++)
1336 	    iptr[c] = vpc->param_field[c];
1337 	break;
1338     case VP_CLASSIFY_TABLE_SIZES:
1339 	for (c = 0; c < vpc->num_clsfy_params; c++)
1340 	    iptr[c] = vpc->clsfy_table_size[c];
1341 	break;
1342     case VP_COLOR_CHANNELS:
1343 	*iptr = vpc->color_channels;
1344 	break;
1345     case VP_SHADE_COLOR_SIZE:
1346 	*iptr = vpc->shade_color_table_size;
1347 	break;
1348     case VP_SHADE_WEIGHT_SIZE:
1349 	*iptr = vpc->shade_weight_table_size;
1350 	break;
1351     case VP_MATERIAL_COUNT:
1352 	*iptr = vpc->num_materials;
1353 	break;
1354     case VP_SHADE_COLOR_FIELD:
1355 	*iptr = vpc->color_field;
1356 	break;
1357     case VP_SHADE_WEIGHT_FIELD:
1358 	*iptr = vpc->weight_field;
1359 	break;
1360     case VP_LIGHT0:
1361     case VP_LIGHT1:
1362     case VP_LIGHT2:
1363     case VP_LIGHT3:
1364     case VP_LIGHT4:
1365     case VP_LIGHT5:
1366 	*iptr = vpc->light_enable[option - VP_LIGHT0];
1367 	break;
1368     case VP_LIGHT_BOTH_SIDES:
1369 	*iptr = vpc->light_both_sides;
1370 	break;
1371     case VP_REVERSE_SURFACE_SIDES:
1372 	*iptr = vpc->reverse_surface_sides;
1373 	break;
1374     case VP_DEPTH_CUE:
1375 	*iptr = vpc->dc_enable;
1376 	break;
1377     case VP_DEPTH_CUE_TABLE_SIZE:
1378 	*iptr = vpc->dc_table_len;
1379 	break;
1380     case VP_DEPTH_CUE_SIZE_HINT:
1381 	*iptr = vpc->dc_table_len_hint;
1382 	break;
1383     case VP_CURRENT_MATRIX:
1384 	*iptr = vpc->current_matrix;
1385 	break;
1386     case VP_CONCAT_MODE:
1387 	if (vpc->concat_left)
1388 	    *iptr = VP_CONCAT_LEFT;
1389 	else
1390 	    *iptr = VP_CONCAT_RIGHT;
1391 	break;
1392     case VP_IMAGE_WIDTH:
1393 	*iptr = vpc->image_width;
1394 	break;
1395     case VP_IMAGE_HEIGHT:
1396 	*iptr = vpc->image_height;
1397 	break;
1398     case VP_IMAGE_SCAN_SIZE:
1399 	*iptr = vpc->image_bytes_per_scan;
1400 	break;
1401     case VP_VIEW_AXIS:
1402 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1403 	    return(retcode);
1404 	*iptr = vpc->best_view_axis;
1405 	break;
1406     case VP_INTERMEDIATE_WIDTH:
1407 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1408 	    return(retcode);
1409 	*iptr = vpc->intermediate_width;
1410 	break;
1411     case VP_INTERMEDIATE_HEIGHT:
1412 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1413 	    return(retcode);
1414 	*iptr = vpc->intermediate_height;
1415 	break;
1416     case VP_INTERMEDIATE_COLOR:
1417 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1418 	    return(retcode);
1419 	*iptr = vpc->intermediate_color_channels;
1420 	break;
1421     case VP_INT_WIDTH_HINT:
1422 	*iptr = vpc->int_image_width_hint;
1423 	break;
1424     case VP_INT_HEIGHT_HINT:
1425 	*iptr = vpc->int_image_height_hint;
1426 	break;
1427     case VP_VIEW_X_AXIS:
1428 	*iptr = !vpc->skip_rle_x;
1429 	break;
1430     case VP_VIEW_Y_AXIS:
1431 	*iptr = !vpc->skip_rle_y;
1432 	break;
1433     case VP_VIEW_Z_AXIS:
1434 	*iptr = !vpc->skip_rle_z;
1435 	break;
1436     case VP_VIEW_X_SIZE:
1437 	if (vpc->rle_x == NULL) {
1438 	    *iptr = 0;
1439 	} else {
1440 	    *iptr = sizeof(RLEVoxels) + vpc->rle_x->run_count +
1441 		    vpc->rle_x->data_count*vpc->rle_bytes_per_voxel +
1442 		    vpc->rle_x->klen*vpc->rle_x->scan_offsets_per_slice*
1443 			sizeof(ScanOffset);
1444 	}
1445 	break;
1446     case VP_VIEW_Y_SIZE:
1447 	if (vpc->rle_y == NULL) {
1448 	    *iptr = 0;
1449 	} else {
1450 	    *iptr = sizeof(RLEVoxels) + vpc->rle_y->run_count +
1451 		    vpc->rle_y->data_count*vpc->rle_bytes_per_voxel +
1452 		    vpc->rle_y->klen*vpc->rle_y->scan_offsets_per_slice*
1453 			sizeof(ScanOffset);
1454 	}
1455 	break;
1456     case VP_VIEW_Z_SIZE:
1457 	if (vpc->rle_z == NULL) {
1458 	    *iptr = 0;
1459 	} else {
1460 	    *iptr = sizeof(RLEVoxels) + vpc->rle_z->run_count +
1461 		    vpc->rle_z->data_count*vpc->rle_bytes_per_voxel +
1462 		    vpc->rle_z->klen*vpc->rle_z->scan_offsets_per_slice*
1463 			sizeof(ScanOffset);
1464 	}
1465 	break;
1466     case VP_MMOCTREE_THRESHOLDS:
1467 	for (c = 0; c < vpc->num_clsfy_params; c++)
1468 	    iptr[c] = vpc->param_maxrange[c];
1469 	break;
1470     case VP_MMOCTREE_SIZE:
1471 	if (vpc->mm_octree == NULL)
1472 	    *iptr = 0;
1473 	else
1474 	    *iptr = sizeof(MinMaxOctree) + vpc->mm_octree->octree_bytes;
1475 	break;
1476     case VP_SHADOW:
1477 	*iptr = vpc->enable_shadows;
1478 	break;
1479     case VP_SHADOW_LIGHT:
1480 	*iptr = vpc->shadow_light_num;
1481 	break;
1482     case VP_SHADOW_WIDTH_HINT:
1483 	*iptr = vpc->shadow_width_hint;
1484 	break;
1485     case VP_SHADOW_HEIGHT_HINT:
1486 	*iptr = vpc->shadow_height_hint;
1487 	break;
1488     case VP_SHADOW_WIDTH:
1489 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1490 	    return(retcode);
1491 	*iptr = vpc->shadow_width;
1492 	break;
1493     case VP_SHADOW_HEIGHT:
1494 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1495 	    return(retcode);
1496 	*iptr = vpc->shadow_height;
1497 	break;
1498     case VP_SHADOW_COLOR_SIZE:
1499 	*iptr = vpc->shadow_color_table_size;
1500 	break;
1501     case VP_SHADOW_BIAS:
1502 	*iptr = vpc->shadow_bias;
1503 	break;
1504     case VP_PIXEL_TYPE:
1505 	*iptr = vpc->pixel_type;
1506 	break;
1507     case VP_CLAMP_SHADE_TABLE:
1508 	*iptr = vpc->clamp_shade_table;
1509 	break;
1510     case VP_COMPOSITE_ORDER:
1511 	if ((retcode = VPFactorView(vpc)) != VP_OK)
1512 	    return(retcode);
1513 	if (vpc->reverse_slice_order)
1514 	    *iptr = -1;
1515 	else
1516 	    *iptr = 1;
1517 	break;
1518     default:
1519 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1520     }
1521     return(VP_OK);
1522 }
1523 
1524 /*
1525  * vpGetd
1526  *
1527  * Retrieve a double-precision-valued piece of state.
1528  */
1529 
1530 vpResult
vpGetd(vpc,option,dptr)1531 vpGetd(vpc, option, dptr)
1532 vpContext *vpc;
1533 int option;
1534 double *dptr;
1535 {
1536     int c;
1537 
1538     switch (option) {
1539     case VP_MIN_VOXEL_OPACITY:
1540 	*dptr = vpc->min_opacity;
1541 	break;
1542     case VP_DEPTH_CUE_FRONT:
1543 	*dptr = vpc->dc_front_factor;
1544 	break;
1545     case VP_DEPTH_CUE_DENSITY:
1546 	*dptr = vpc->dc_density;
1547 	break;
1548     case VP_DEPTH_CUE_QUANTIZATION:
1549 	*dptr = vpc->dc_quantization;
1550 	break;
1551     case VP_MAX_RAY_OPACITY:
1552 	*dptr = vpc->max_opacity;
1553 	break;
1554     default:
1555 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1556     }
1557     return(VP_OK);
1558 }
1559 
1560 /*
1561  * vpGetp
1562  *
1563  * Retrieve a pointer-valued piece of state.
1564  */
1565 
1566 vpResult
vpGetp(vpc,option,pptr)1567 vpGetp(vpc, option, pptr)
1568 vpContext *vpc;
1569 int option;
1570 void **pptr;
1571 {
1572     int c;
1573 
1574     switch (option) {
1575     case VP_VOXEL_DATA:
1576 	*pptr = vpc->raw_voxels;
1577 	break;
1578     case VP_CLASSIFY_TABLES:
1579 	for (c = 0; c < vpc->num_clsfy_params; c++)
1580 	    pptr[c] = vpc->clsfy_table[c];
1581 	break;
1582     case VP_SHADE_FUNC:
1583 	*pptr = vpc->shade_func;
1584 	break;
1585     case VP_SHADE_COLOR_TABLE:
1586 	*pptr = vpc->shade_color_table;
1587 	break;
1588     case VP_SHADE_WEIGHT_TABLE:
1589 	*pptr = vpc->shade_weight_table;
1590 	break;
1591     case VP_SHADOW_COLOR_TABLE:
1592 	*pptr = vpc->shadow_color_table;
1593 	break;
1594     case VP_IMAGE:
1595 	*pptr = vpc->image;
1596 	break;
1597     case VP_LOG_ALLOC_FUNC:
1598 	*pptr = vpc->log_alloc_func;
1599 	break;
1600     case VP_LOG_FREE_FUNC:
1601 	*pptr = vpc->log_free_func;
1602 	break;
1603     case VP_STATUS_FUNC:
1604 	*pptr = vpc->status_func;
1605 	break;
1606     case VP_READ_FUNC:
1607 	*pptr = vpc->read_func;
1608 	break;
1609     case VP_WRITE_FUNC:
1610 	*pptr = vpc->write_func;
1611 	break;
1612     case VP_MMAP_FUNC:
1613 	*pptr = vpc->mmap_func;
1614 	break;
1615     case VP_CLIENT_DATA:
1616 	*pptr = vpc->client_data;
1617 	break;
1618     default:
1619 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1620     }
1621     return(VP_OK);
1622 }
1623 
1624 /*
1625  * vpGetMaterial
1626  *
1627  * Get material parameters.
1628  */
1629 
1630 vpResult
vpGetMaterial(vpc,material,property,surface_side,r,g,b)1631 vpGetMaterial(vpc, material, property, surface_side, r, g, b)
1632 vpContext *vpc;
1633 int material;
1634 int property;
1635 int surface_side;
1636 double *r, *g, *b;
1637 {
1638     material -= VP_MATERIAL0;
1639     if (material < 0 || material >= vpc->num_materials)
1640 	return(VPSetError(vpc, VPERROR_BAD_VALUE));
1641     if (surface_side != VP_EXTERIOR && surface_side != VP_INTERIOR)
1642 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1643     switch (property) {
1644     case VP_AMBIENT:
1645 	if (surface_side == VP_EXTERIOR) {
1646 	    *r = vpc->matl_props[material][EXT_SURFACE][MATL_AMB_R] / 255.;
1647 	    *g = vpc->matl_props[material][EXT_SURFACE][MATL_AMB_G] / 255.;
1648 	    *b = vpc->matl_props[material][EXT_SURFACE][MATL_AMB_B] / 255.;
1649 	} else {
1650 	    *r = vpc->matl_props[material][INT_SURFACE][MATL_AMB_R] / 255.;
1651 	    *g = vpc->matl_props[material][INT_SURFACE][MATL_AMB_G] / 255.;
1652 	    *b = vpc->matl_props[material][INT_SURFACE][MATL_AMB_B] / 255.;
1653 	}
1654 	break;
1655     case VP_DIFFUSE:
1656 	if (surface_side == VP_EXTERIOR) {
1657 	    *r = vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_R] / 255.;
1658 	    *g = vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_G] / 255.;
1659 	    *b = vpc->matl_props[material][EXT_SURFACE][MATL_DIFF_B] / 255.;
1660 	} else {
1661 	    *r = vpc->matl_props[material][INT_SURFACE][MATL_DIFF_R] / 255.;
1662 	    *g = vpc->matl_props[material][INT_SURFACE][MATL_DIFF_G] / 255.;
1663 	    *b = vpc->matl_props[material][INT_SURFACE][MATL_DIFF_B] / 255.;
1664 	}
1665 	break;
1666     case VP_SPECULAR:
1667 	if (surface_side == VP_EXTERIOR) {
1668 	    *r = vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_R] / 255.;
1669 	    *g = vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_G] / 255.;
1670 	    *b = vpc->matl_props[material][EXT_SURFACE][MATL_SPEC_B] / 255.;
1671 	} else {
1672 	    *r = vpc->matl_props[material][INT_SURFACE][MATL_SPEC_R] / 255.;
1673 	    *g = vpc->matl_props[material][INT_SURFACE][MATL_SPEC_G] / 255.;
1674 	    *b = vpc->matl_props[material][INT_SURFACE][MATL_SPEC_B] / 255.;
1675 	}
1676 	break;
1677     case VP_SHINYNESS:
1678 	if (surface_side & VP_EXTERIOR)
1679 	    *r = vpc->matl_props[material][EXT_SURFACE][MATL_SHINY];
1680 	else
1681 	    *r = vpc->matl_props[material][INT_SURFACE][MATL_SHINY];
1682 	break;
1683     default:
1684 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1685     }
1686     return(VP_OK);
1687 }
1688 
1689 /*
1690  * vpGetLight
1691  *
1692  * Get the properties of a directional light source.
1693  */
1694 
1695 vpResult
vpGetLight(vpc,light_num,property,n0,n1,n2)1696 vpGetLight(vpc, light_num, property, n0, n1, n2)
1697 vpContext *vpc;
1698 int light_num;
1699 int property;
1700 double *n0, *n1, *n2;
1701 {
1702     light_num -= VP_LIGHT0;
1703     if (light_num < 0 || light_num >= VP_MAX_LIGHTS)
1704 	return(VPSetError(vpc, VPERROR_LIMIT_EXCEEDED));
1705     switch (property) {
1706     case VP_DIRECTION:
1707 	*n0 = vpc->light_vector[light_num][0];
1708 	*n1 = vpc->light_vector[light_num][1];
1709 	*n2 = vpc->light_vector[light_num][2];
1710 	break;
1711     case VP_COLOR:
1712 	*n0 = vpc->light_color[light_num][0];
1713 	*n1 = vpc->light_color[light_num][1];
1714 	*n2 = vpc->light_color[light_num][2];
1715 	break;
1716     default:
1717 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
1718     }
1719     return(VP_OK);
1720 }
1721 
1722 /*
1723  * vpGetImage
1724  *
1725  * Get one of the intermediate rendering buffers.
1726  */
1727 
1728 vpResult
vpGetImage(vpc,image,width,height,scan_bytes,pixel_type,image_type)1729 vpGetImage(vpc, image, width, height, scan_bytes, pixel_type, image_type)
1730 vpContext *vpc;		/* context */
1731 void *image;		/* buffer for storing result */
1732 int width;		/* expected width of image in buffer */
1733 int height;		/* expected height of image in buffer */
1734 int scan_bytes;		/* bytes per scanline in buffer */
1735 int pixel_type;		/* type of pixel to store in buffer */
1736 int image_type;		/* rendering buffer to extract from
1737 			   (VP_IMAGE_BUFFER or VP_SHADOW_BUFFER) */
1738 {
1739     int x, y;
1740     unsigned char *dst_ptr;
1741     GrayIntPixel *gray_pixel;
1742     RGBIntPixel *rgb_pixel;
1743     int value;
1744     int color_channels;
1745 
1746     switch (image_type) {
1747     case VP_IMAGE_BUFFER:
1748 	if (width != vpc->intermediate_width ||
1749 	    height != vpc->intermediate_height)
1750 	    return(VPSetError(vpc, VPERROR_BAD_SIZE));
1751 	color_channels = vpc->intermediate_color_channels;
1752 	dst_ptr = image;
1753 	switch (pixel_type) {
1754 	case VP_ALPHA:
1755 	    if (scan_bytes < width)
1756 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1757 	    if (color_channels == 1) {
1758 		for (y = 0; y < height; y++) {
1759 		    gray_pixel = vpc->int_image.gray_intim +
1760 			(vpc->pad_int_to_maxwidth ?
1761 			 vpc->max_intermediate_width*y :
1762 			 vpc->intermediate_width*y);
1763 		    dst_ptr = (unsigned char *)image + y * scan_bytes;
1764 		    for (x = 0; x < width; x++) {
1765 			value = (int)rint(gray_pixel->opcflt * 255.);
1766 			if (value > 255)
1767 			    *dst_ptr = 255;
1768 			else
1769 			    *dst_ptr = value;
1770 			dst_ptr++;
1771 			gray_pixel++;
1772 		    }
1773 		}
1774 	    } else {
1775 		for (y = 0; y < height; y++) {
1776 		    rgb_pixel = vpc->int_image.rgb_intim +
1777 			(vpc->pad_int_to_maxwidth ?
1778 			 vpc->max_intermediate_width*y :
1779 			 vpc->intermediate_width*y);
1780 		    dst_ptr = (unsigned char *)image + y * scan_bytes;
1781 		    for (x = 0; x < width; x++) {
1782 			value = (int)rint(rgb_pixel->opcflt * 255.);
1783 			if (value > 255)
1784 			    *dst_ptr = 255;
1785 			else
1786 			    *dst_ptr = value;
1787 			dst_ptr++;
1788 			rgb_pixel++;
1789 		    }
1790 		}
1791 	    }
1792 	    break;
1793 	case VP_LUMINANCE:
1794 	    if (color_channels != 1)
1795 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1796 	    if (scan_bytes < width)
1797 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1798 	    for (y = 0; y < height; y++) {
1799 		gray_pixel = vpc->int_image.gray_intim +
1800 		    (vpc->pad_int_to_maxwidth ?
1801 		     vpc->max_intermediate_width*y :
1802 		     vpc->intermediate_width*y);
1803 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1804 		for (x = 0; x < width; x++) {
1805 		    value = (int)rint(gray_pixel->clrflt);
1806 		    if (value > 255)
1807 			*dst_ptr = 255;
1808 		    else
1809 			*dst_ptr = value;
1810 		    dst_ptr++;
1811 		    gray_pixel++;
1812 		}
1813 	    }
1814 	    break;
1815 	case VP_LUMINANCEA:
1816 	    if (color_channels != 1)
1817 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1818 	    if (scan_bytes < 2*width)
1819 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1820 	    for (y = 0; y < height; y++) {
1821 		gray_pixel = vpc->int_image.gray_intim +
1822 		    (vpc->pad_int_to_maxwidth ?
1823 		     vpc->max_intermediate_width*y :
1824 		     vpc->intermediate_width*y);
1825 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1826 		for (x = 0; x < width; x++) {
1827 		    value = (int)rint(gray_pixel->clrflt);
1828 		    if (value > 255)
1829 			*dst_ptr = 255;
1830 		    else
1831 			*dst_ptr = value;
1832 		    dst_ptr++;
1833 		    value = (int)rint(gray_pixel->opcflt * 255.);
1834 		    if (value > 255)
1835 			*dst_ptr = 255;
1836 		    else
1837 			*dst_ptr = value;
1838 		    dst_ptr++;
1839 		    gray_pixel++;
1840 		}
1841 	    }
1842 	    break;
1843 	case VP_RGB:
1844 	    if (color_channels != 3)
1845 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1846 	    if (scan_bytes < 3*width)
1847 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1848 	    for (y = 0; y < height; y++) {
1849 		rgb_pixel = vpc->int_image.rgb_intim +
1850 		    (vpc->pad_int_to_maxwidth ?
1851 		     vpc->max_intermediate_width*y :
1852 		     vpc->intermediate_width*y);
1853 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1854 		for (x = 0; x < width; x++) {
1855 		    value = (int)rint(rgb_pixel->rclrflt);
1856 		    if (value > 255)
1857 			*dst_ptr = 255;
1858 		    else
1859 			*dst_ptr = value;
1860 		    dst_ptr++;
1861 		    value = (int)rint(rgb_pixel->gclrflt);
1862 		    if (value > 255)
1863 			*dst_ptr = 255;
1864 		    else
1865 			*dst_ptr = value;
1866 		    dst_ptr++;
1867 		    value = (int)rint(rgb_pixel->bclrflt);
1868 		    if (value > 255)
1869 			*dst_ptr = 255;
1870 		    else
1871 			*dst_ptr = value;
1872 		    dst_ptr++;
1873 		    rgb_pixel++;
1874 		}
1875 	    }
1876 	    break;
1877 	case VP_RGBA:
1878 	    if (color_channels != 3)
1879 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1880 	    if (scan_bytes < 4*width)
1881 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1882 	    for (y = 0; y < height; y++) {
1883 		rgb_pixel = vpc->int_image.rgb_intim +
1884 		    (vpc->pad_int_to_maxwidth ?
1885 		     vpc->max_intermediate_width*y :
1886 		     vpc->intermediate_width*y);
1887 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1888 		for (x = 0; x < width; x++) {
1889 		    value = (int)rint(rgb_pixel->rclrflt);
1890 		    if (value > 255)
1891 			*dst_ptr = 255;
1892 		    else
1893 			*dst_ptr = value;
1894 		    dst_ptr++;
1895 		    value = (int)rint(rgb_pixel->gclrflt);
1896 		    if (value > 255)
1897 			*dst_ptr = 255;
1898 		    else
1899 			*dst_ptr = value;
1900 		    dst_ptr++;
1901 		    value = (int)rint(rgb_pixel->bclrflt);
1902 		    if (value > 255)
1903 			*dst_ptr = 255;
1904 		    else
1905 			*dst_ptr = value;
1906 		    dst_ptr++;
1907 		    value = (int)rint(rgb_pixel->opcflt*255.);
1908 		    if (value > 255)
1909 			*dst_ptr = 255;
1910 		    else
1911 			*dst_ptr = value;
1912 		    dst_ptr++;
1913 		    rgb_pixel++;
1914 		}
1915 	    }
1916 	    break;
1917 	case VP_BGR:
1918 	    if (color_channels != 3)
1919 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1920 	    if (scan_bytes < 3*width)
1921 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1922 	    for (y = 0; y < height; y++) {
1923 		rgb_pixel = vpc->int_image.rgb_intim +
1924 		    (vpc->pad_int_to_maxwidth ?
1925 		     vpc->max_intermediate_width*y :
1926 		     vpc->intermediate_width*y);
1927 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1928 		for (x = 0; x < width; x++) {
1929 		    value = (int)rint(rgb_pixel->bclrflt);
1930 		    if (value > 255)
1931 			*dst_ptr = 255;
1932 		    else
1933 			*dst_ptr = value;
1934 		    dst_ptr++;
1935 		    value = (int)rint(rgb_pixel->gclrflt);
1936 		    if (value > 255)
1937 			*dst_ptr = 255;
1938 		    else
1939 			*dst_ptr = value;
1940 		    dst_ptr++;
1941 		    value = (int)rint(rgb_pixel->rclrflt);
1942 		    if (value > 255)
1943 			*dst_ptr = 255;
1944 		    else
1945 			*dst_ptr = value;
1946 		    dst_ptr++;
1947 		    rgb_pixel++;
1948 		}
1949 	    }
1950 	    break;
1951 	case VP_ABGR:
1952 	    if (color_channels != 3)
1953 		return(VPSetError(vpc, VPERROR_BAD_OPTION));
1954 	    if (scan_bytes < 4*width)
1955 		return(VPSetError(vpc, VPERROR_BAD_SIZE));
1956 	    for (y = 0; y < height; y++) {
1957 		rgb_pixel = vpc->int_image.rgb_intim +
1958 		    (vpc->pad_int_to_maxwidth ?
1959 		     vpc->max_intermediate_width*y :
1960 		     vpc->intermediate_width*y);
1961 		dst_ptr = (unsigned char *)image + y * scan_bytes;
1962 		for (x = 0; x < width; x++) {
1963 		    value = (int)rint(rgb_pixel->opcflt*255.);
1964 		    if (value > 255)
1965 			*dst_ptr = 255;
1966 		    else
1967 			*dst_ptr = value;
1968 		    dst_ptr++;
1969 		    value = (int)rint(rgb_pixel->bclrflt);
1970 		    if (value > 255)
1971 			*dst_ptr = 255;
1972 		    else
1973 			*dst_ptr = value;
1974 		    dst_ptr++;
1975 		    value = (int)rint(rgb_pixel->gclrflt);
1976 		    if (value > 255)
1977 			*dst_ptr = 255;
1978 		    else
1979 			*dst_ptr = value;
1980 		    dst_ptr++;
1981 		    value = (int)rint(rgb_pixel->rclrflt);
1982 		    if (value > 255)
1983 			*dst_ptr = 255;
1984 		    else
1985 			*dst_ptr = value;
1986 		    dst_ptr++;
1987 		    rgb_pixel++;
1988 		}
1989 	    }
1990 	    break;
1991 	default:
1992 	    return(VPSetError(vpc, VPERROR_BAD_OPTION));
1993 	}
1994 	break;
1995     case VP_SHADOW_BUFFER:
1996 	if (pixel_type != VP_ALPHA)
1997 	    return(VPSetError(vpc, VPERROR_BAD_OPTION));
1998 	if (width != vpc->shadow_width || height != vpc->shadow_height)
1999 	    return(VPSetError(vpc, VPERROR_BAD_SIZE));
2000 	if (scan_bytes < width)
2001 	    return(VPSetError(vpc, VPERROR_BAD_SIZE));
2002 	for (y = 0; y < height; y++) {
2003 	    gray_pixel = vpc->shadow_buffer + (vpc->pad_shadow_to_maxwidth ?
2004 			vpc->max_shadow_width*y : vpc->shadow_width*y);
2005 	    dst_ptr = (unsigned char *)image + y * scan_bytes;
2006 	    for (x = 0; x < width; x++) {
2007 		value = (int)rint(gray_pixel->opcflt * 255.);
2008 		if (value > 255)
2009 		    *dst_ptr = 255;
2010 		else
2011 		    *dst_ptr = value;
2012 		dst_ptr++;
2013 		gray_pixel++;
2014 	    }
2015 	}
2016 	break;
2017     default:
2018 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
2019     }
2020     return(VP_OK);
2021 }
2022 
2023 /*
2024  * vpGetTimer
2025  *
2026  * Get the value of one of the timers.
2027  */
2028 
2029 vpResult
vpGetTimer(vpc,option,iptr)2030 vpGetTimer(vpc, option, iptr)
2031 vpContext *vpc;
2032 int option;
2033 int *iptr;
2034 {
2035     if (option < 0 || option >= VPTIMER_COUNT)
2036 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
2037 #ifdef USE_TIMER
2038     *iptr = (int)(vpc->timer_ticks[option] * vpc->timer_usec_per_tick);
2039 #else
2040     *iptr = 0;
2041 #endif
2042     return(VP_OK);
2043 }
2044 
2045 /*
2046  * vpClearTimer
2047  *
2048  * Reset the value of one of the timers to zero.
2049  */
2050 
2051 vpResult
vpClearTimer(vpc,option)2052 vpClearTimer(vpc, option)
2053 vpContext *vpc;
2054 int option;
2055 {
2056     if (option < 0 || option >= VPTIMER_COUNT)
2057 	return(VPSetError(vpc, VPERROR_BAD_OPTION));
2058 #ifdef USE_TIMER
2059     vpc->timer_ticks[option] = 0;
2060 #endif
2061     return(VP_OK);
2062 }
2063 
2064 #ifdef HAVE_HIRES_TIMER
2065 /*
2066  * StartHiResTimer
2067  *
2068  * Initialize the high-resolution memory mapped timer (available on
2069  * some models of SGI hardware).  On machines with a 64-bit timer
2070  * (e.g. Challenge or ONYX), HAVE_64BIT_TIMER must be defined for
2071  * proper operation.
2072  */
2073 
2074 static void
StartHiResTimer(vpc)2075 StartHiResTimer(vpc)
2076 vpContext *vpc;
2077 {
2078     volatile unsigned timer_resolution; /* resolution of timer in psec. */
2079     unsigned phys_addr;		/* hardware address of timer */
2080     unsigned page_addr;		/* address of page containing timer */
2081     int fd;			/* file descriptor for file to be mapped */
2082     volatile unsigned *timer_addr; /* memory-mapped address of timer */
2083 
2084 
2085     /* set values to harmless defaults in case hardware doesn't really
2086        support a high-resolution timer */
2087     vpc->timer_usec_per_tick = 0.;
2088     vpc->timer_addr = &vpc->dummy_timer;
2089     vpc->dummy_timer = 0;
2090 
2091     phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &timer_resolution);
2092     if ((int)phys_addr == -1)
2093 	return;
2094     if ((fd = open("/dev/mmem", O_RDONLY)) < 0)
2095 	return;
2096     page_addr = phys_addr & ~POFFMASK;
2097     timer_addr = (volatile unsigned *)mmap(0, POFFMASK, PROT_READ,
2098 					   MAP_PRIVATE, fd, (int)page_addr);
2099     close(fd);
2100     if ((int)timer_addr == -1)
2101 	return;
2102     vpc->timer_addr = (unsigned *)((unsigned)timer_addr + poff(phys_addr));
2103 #ifdef HAVE_64BIT_TIMER
2104     vpc->timer_addr++;
2105     printf("Timer configured for 64 bits.\n");
2106 #endif
2107     vpc->timer_usec_per_tick = timer_resolution * 1.0e-6;
2108     printf("Timer resolution is %d psec.\n", timer_resolution);
2109 }
2110 #endif /* HAVE_HIRES_TIMER */
2111