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