/* sphere.c 1.2 */ /* Copyright 1992, 1993 O'Reilly and Associates, Inc. Permission to use, copy, and modify this program is hereby granted, as long as this copyright notice appears in each copy of the program source code. */ /* 12/15/92, version 1.2: Specified facet normals for plane and */ /* sphere to accound for servers that compute facingness */ /* incorrectly. */ #include "book_utils.h" /* Globals. */ static PEXStructure model; static Display *dpy; static Window window; static PEXRenderer renderer; static void normalize(); static PEXStructure build_plane(), build_sphere(); #define AMBIENT_LIGHT 1 #define DIRECTIONAL_LIGHT 2 #define POINT_LIGHT 3 #define SPOT_LIGHT 4 static void initialize_lights( light_table ) PEXLookupTable light_table; { PEXLightEntry lights[4]; /* Define the ambient light. */ lights[0].type = PEXLightAmbient; lights[0].color.type = PEXColorTypeRGB; lights[0].color.value.rgb.red = .3; lights[0].color.value.rgb.green = .3; lights[0].color.value.rgb.blue = .3; /* Define the directional light. */ lights[1].type = PEXLightWCVector; lights[1].direction.x = 1; lights[1].direction.y = 0; lights[1].direction.z = 0; lights[1].color.type = PEXColorTypeRGB; lights[1].color.value.rgb.red = 0.4; lights[1].color.value.rgb.green = 0.4; lights[1].color.value.rgb.blue = 0.4; /* Define the point light. */ lights[2].type = PEXLightWCPoint; lights[2].point.x = 0.5; lights[2].point.y = 0.5; lights[2].point.z = 0.5; lights[2].attenuation1 = 1; lights[2].attenuation2 = 1; lights[2].color.type = PEXColorTypeRGB; lights[2].color.value.rgb.red = 0.6; lights[2].color.value.rgb.green = 0.4; lights[2].color.value.rgb.blue = 0.0; /* Define the spot light. */ lights[3].type = PEXLightWCSpot; lights[3].point.x = 1; lights[3].point.y = 1; lights[3].point.z = 1; lights[3].direction.x = -1; lights[3].direction.y = -1; lights[3].direction.z = -1; normalize( &lights[3].direction ); lights[3].concentration = 75; lights[3].spread_angle = M_PI/4; lights[3].attenuation1 = 1; lights[3].attenuation2 = 0.2; lights[3].color.type = PEXColorTypeRGB; lights[3].color.value.rgb.red = 0.7; lights[3].color.value.rgb.green = 0.7; lights[3].color.value.rgb.blue = 0.7; /* Add the lights to the light table. */ PEXSetTableEntries( dpy, light_table, 1, 4, PEXLUTLight, lights ); } void create_model() { PEXStructure plane, sphere; PEXColor color; PEXTableIndex lights_on[4]; /* Create the top-level structure. */ model = PEXCreateStructure( dpy ); /* Set the interior style. */ PEXSetInteriorStyle( dpy, model, PEXOCStore, PEXInteriorStyleSolid ); /* Have PEX compute all lighting effects. */ PEXSetReflectionModel( dpy, model, PEXOCStore, PEXReflectionSpecular ); /* Use Gouraud shading. */ PEXSetSurfaceInterpMethod( dpy, model, PEXOCStore, PEXSurfaceInterpColor ); /* Cull back faces. */ PEXSetFacetCullingMode( dpy, model, PEXOCStore, PEXBackFaces ); /* Turn the lights on. */ lights_on[0] = AMBIENT_LIGHT; lights_on[1] = DIRECTIONAL_LIGHT; lights_on[2] = POINT_LIGHT; lights_on[3] = SPOT_LIGHT; PEXSetLightSourceState( dpy, model, PEXOCStore, 4, lights_on, 0, (PEXTableIndex*)NULL ); /* Execute the structures containing the primitives. */ plane = build_plane(); PEXExecuteStructure( dpy, model, PEXOCStore, plane ); sphere = build_sphere(); PEXExecuteStructure( dpy, model, PEXOCStore, sphere ); } #define NUM_X_POINTS 30 #define NUM_Y_POINTS 30 static PEXStructure build_plane() { PEXStructure struct_id; PEXColor color; PEXCoord verts[NUM_X_POINTS * NUM_Y_POINTS]; PEXArrayOfVertex plane; PEXArrayOfFacetData facet_data; PEXVector facet_normals[(NUM_X_POINTS-1)*(NUM_Y_POINTS-1)]; unsigned int facet_data_flag, vertex_data_flag; int i, j, index; struct_id = PEXCreateStructure( dpy ); for ( j = 0; j < NUM_Y_POINTS; j++ ) { for ( i = 0; i < NUM_X_POINTS; i++ ) { index = j * NUM_X_POINTS + i; verts[index].x = 0.1 + i * 0.8/(NUM_X_POINTS - 1); verts[index].y = 0.9 - j * 0.8/(NUM_Y_POINTS - 1); verts[index].z = 0; } } /* Specify facet normals so that the front faces are the faces */ /* toward us. */ for ( i = 0; i < sizeof(facet_normals)/sizeof(PEXVector); i++ ) { facet_normals[i].x = facet_normals[i].y = 0; facet_normals[i].z = 1; } /* Create the quadrilateral mesh. */ SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetSurfaceColor( dpy, struct_id, PEXOCStore, PEXColorTypeRGB, &color ); facet_data_flag = PEXGANormal; vertex_data_flag = PEXGANone; facet_data.normal = facet_normals; plane.no_data = verts; PEXQuadrilateralMesh( dpy, struct_id, PEXOCStore, PEXShapeConvex, facet_data_flag, vertex_data_flag, PEXColorTypeRGB, facet_data, NUM_X_POINTS, NUM_Y_POINTS, plane ); return struct_id; } #define NUM_LONG_FACETS 60 #define NUM_LAT_FACETS 30 #define NUM_LONG_POINTS (NUM_LONG_FACETS + 1) #define NUM_LAT_POINTS (NUM_LAT_FACETS + 1) #define RADIUS 0.2 static PEXStructure build_sphere() { PEXStructure struct_id; PEXColor color; PEXVertexNormal verts[NUM_LONG_POINTS * NUM_LAT_POINTS]; PEXArrayOfVertex sphere; PEXArrayOfFacetData facet_data; PEXVector facet_normals[NUM_LONG_FACETS * NUM_LAT_FACETS]; unsigned int facet_data_flag, vertex_data_flag; PEXVector location; PEXMatrix transform; double theta = 0, phi = 0; int i, j, index; for ( i = 0; i < NUM_LAT_POINTS; i++ ) { for ( j = 0; j < NUM_LONG_FACETS; j++ ) { index = i * NUM_LONG_POINTS + j; verts[index].point.x = RADIUS * sin(phi) * sin(theta); verts[index].point.y = RADIUS * cos(phi); verts[index].point.z = RADIUS * sin(phi) * cos(theta); /* The normal is just the vector to the point. */ verts[index].normal.x = verts[index].point.x; verts[index].normal.y = verts[index].point.y; verts[index].normal.z = verts[index].point.z; normalize( &verts[index].normal ); theta += (2 * M_PI) / NUM_LONG_FACETS; } phi += M_PI / NUM_LAT_FACETS; /* Close the circle. */ index = i * NUM_LONG_POINTS + NUM_LONG_FACETS; verts[index].point = verts[index - NUM_LONG_FACETS].point; verts[index].normal = verts[index - NUM_LONG_FACETS].normal; } theta = M_PI / NUM_LONG_FACETS; phi = 0.5 * M_PI / NUM_LAT_FACETS; index = 0; for ( i = 0; i < NUM_LAT_FACETS; i++ ) { for ( j = 0; j < NUM_LONG_FACETS; j++ ) { facet_normals[index].x = sin(phi) * sin(theta); facet_normals[index].y = cos(phi); facet_normals[index].z = sin(phi) * cos(theta); normalize( &facet_normals[i] ); ++index; theta += (2 * M_PI) / NUM_LONG_FACETS; } phi += M_PI / NUM_LAT_FACETS; } struct_id = PEXCreateStructure( dpy ); /* Position the center of the sphere at the point (0.5,0.5,0.5). */ location.x = location.y = location.z = 0.5; PEXTranslate( &location, transform ); PEXSetLocalTransform( dpy, struct_id, PEXOCStore, PEXReplace, transform ); #ifdef SPHERE2 { /* Set the reflection attributes. */ PEXReflectionAttributes attrs; attrs.ambient = 1; attrs.diffuse = 1; attrs.transmission = 0; attrs.specular = 1; attrs.specular_conc = 200; attrs.specular_color.type = PEXColorTypeRGB; attrs.specular_color.value.rgb.red = 1; attrs.specular_color.value.rgb.green = 1; attrs.specular_color.value.rgb.blue = 1; PEXSetReflectionAttributes( dpy, struct_id, PEXOCStore, &attrs ); } #endif /* Create the quadrilateral mesh. */ SET_COLOR( 1, 1, 1, color ); /* white */ PEXSetSurfaceColor( dpy, struct_id, PEXOCStore, PEXColorTypeRGB, &color ); facet_data_flag = PEXGANormal; vertex_data_flag = PEXGANormal; sphere.normal = verts; facet_data.normal = facet_normals; PEXQuadrilateralMesh( dpy, struct_id, PEXOCStore, PEXShapeConvex, facet_data_flag, vertex_data_flag, PEXColorTypeRGB, facet_data, NUM_LONG_POINTS, NUM_LAT_POINTS, sphere ); return struct_id; } static void normalize( vector ) PEXVector *vector; { float r; /* Transform a vector to a unit vector. */ r = vector->x * vector->x + vector->y * vector->y + vector->z * vector->z; if ( r > 0 ) { r = 1.0 / sqrt( r ); vector->x *= r; vector->y *= r; vector->z *= r; } } static void redraw() { XClearWindow( dpy, window ); PEXRenderNetwork( dpy, window, renderer, model ); XFlush( dpy ); } #define WIN_GEOM "500x500+50+50" main( argc, argv ) int argc; char *argv[]; { XEvent event; XVisualInfo vis_info; XColor bkgd_color; XStandardColormap cmap_info; PEXColorApproxEntry capx_info; PEXRendererAttributes rattrs; PEXExtensionInfo *pexinfo; int done = 0; char err[80]; /* Open a display and initialize PEX. */ dpy = ora_init_pex( argv, &pexinfo ); if ( !dpy ) exit(1); /* Determine the best visual to use. */ ora_find_best_visual( dpy, &vis_info ); #ifdef USE_BEST_COLORMAP ora_create_colormap( dpy, &vis_info, &cmap_info, &capx_info ); #else /* Get a standard colormap for the visual. */ if ( !ora_get_standard_colormap( dpy, &vis_info, &cmap_info ) ) { fprintf ( stderr, "Cannot find a standard colormap\n" ); exit(1); } ora_set_stdcmap_approx( &vis_info, &cmap_info, &capx_info ); #endif /* Create the window. */ bkgd_color.red = bkgd_color.green = bkgd_color.blue = 0; bkgd_color.flags = DoRed | DoGreen | DoBlue; window = ora_create_window( dpy, &vis_info, &cmap_info, WIN_GEOM, &bkgd_color ); /* Set up the PEX renderer. */ if ( STRUCTURE_SPT( pexinfo ) ) { renderer = ora_setup_renderer( dpy, window, &capx_info, &rattrs ); } else { fprintf( stderr, "Structure not supported.\n" ); exit(1); } create_model(); initialize_lights( rattrs.light_table ); /* Turn Z-buffering on if available. */ if ( ora_enum_type_supported( dpy, window, PEXETHLHSRMode, PEXHLHSRZBuffer ) ) { rattrs.hlhsr_mode = PEXHLHSRZBuffer; PEXChangeRenderer( dpy, renderer, PEXRAHLHSRMode, &rattrs ); } /* Read and respond to X events. */ XSelectInput( dpy, window, ButtonPressMask | ExposureMask ); while ( !done ) { XNextEvent( dpy, &event ); switch ( event.type ) { case ButtonPress: done = 1; break; case Expose: /* Flush remaining Expose events, then redraw. */ while ( XCheckTypedWindowEvent( dpy, window, Expose, &event ) ) ; /* empty statement */ redraw(); break; } } XCloseDisplay( dpy ); return 0; }