/* * $Header: /home/barad-dur/vision/forsyth/schenney/sced-0.94/c/RCS/rayshade.c,v 1.0 1997/05/06 20:30:22 schenney Exp $ * * $Log: rayshade.c,v $ * Revision 1.0 1997/05/06 20:30:22 schenney * Initial revision * */ #define PATCHLEVEL 0 /* ** ScEd: A Constraint Based Scene Editor. ** Copyright (C) 1994-1998 Stephen Chenney (schenney@cs.berkeley.edu) ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ** sced: A Constraint Based Object Scene Editor ** ** rayshade.c : export functions for rayshade. ** ** External function (there's just one). ** ** void ** Export_Rayshade(FILE *outfile) ** Exports all the relevant info into outfile. */ #include #include #include #include #include #include #include #include #include static int Export_Camera(FILE*, Camera); static int Export_Light(FILE*, ObjectInstancePtr, TransformPtr, AttributePtr); static int Export_Basetypes(FILE*, BaseObjectPtr, TransformPtr); static int Export_CSG_Tree(FILE*, CSGNodePtr); static int Export_Wireframe(FILE*, WireframePtr); static int Export_Instances(FILE*, InstanceList, TransformPtr, AttributePtr, Boolean); static void Export_Object_Type(FILE*, ObjectInstancePtr, AttributePtr); static void Export_Transformation(FILE*, ObjectInstancePtr, TransformPtr); static void Export_Attributes(FILE*, AttributePtr); static void Export_Texture(FILE*, ObjectInstancePtr, TransformPtr,AttributePtr); static int Export_Declarations(FILE*); static HashTable base_hash; static Transformation identity = { { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }, { 0, 0, 0 } }; /* int ** Export_Rayshade(FILE *outfile, ScenePtr scene) ** Exports all the relevant info into outfile. */ int Export_Rayshade(FILE *outfile, ScenePtr scene) { time_t current_time; time(¤t_time); base_hash = Hash_New_Table(); if ( fprintf(outfile, "/* File generated by sced */\n") < 0 || fprintf(outfile, "/* %s */\n\n", ctime(¤t_time)) < 0 || fprintf(outfile, "\nname my_cylinder list\n") < 0 || fprintf(outfile, "\tcylinder 1 0.0 0.0 -1.0 0.0 0.0 1.0\n") < 0 || fprintf(outfile, "\tdisc 1 0.0 0.0 1.0 0.0 0.0 1.0\n") < 0 || fprintf(outfile, "\tdisc 1 0.0 0.0 -1.0 0.0 0.0 -1.0\n") < 0 || fprintf(outfile, "end\n\n") < 0 || fprintf(outfile, "\nname my_cone list\n") < 0 || fprintf(outfile, "\tcone 1 0.0 0.0 -1.0 0.0 0.0 0.0 1.0\n") < 0 || fprintf(outfile, "\tdisc 1 0.0 0.0 -1.0 0.0 0.0 -1.0\n") < 0 || fprintf(outfile, "end\n\n") < 0 || Export_Camera(outfile, scene->camera) < 0 || fprintf(outfile, "light %g %g %g ambient\n\n", scene->ambient.red, scene->ambient.green, scene->ambient.blue) < 0 || Export_Declarations(outfile) < 0 || ( scene->light && Export_Light(outfile, scene->light, &identity, scene->light->o_attribs) < 0 ) || Export_Instances(outfile, scene->instances, &identity, &(sced_preferences.default_attributes), TRUE) < 0) { Popup_Error("Write Failed!", main_window.shell, "Error"); return 0; } Hash_Free(base_hash); return 1; } static int Export_Camera(FILE *outfile, Camera cam) { if ( ! cam.defined ) return 1; /* Rayshade camera info just goes at the top. */ fprintf(outfile, "/* Camera definitions. */\n"); fprintf(outfile, "screen %d %d\n", cam.scr_width, cam.scr_height); fprintf(outfile, "eyep "); VPrint(outfile, cam.location); fprintf(outfile, "lookp "); VPrint(outfile, cam.look_at); fprintf(outfile, "up "); VPrint(outfile, cam.look_up); fprintf(outfile, "fov %g %g\n", cam.horiz_fov, cam.vert_fov); fprintf(outfile, "focaldist %g\n", cam.eye_dist); return fprintf(outfile, "\n"); } static int Export_Light(FILE *outfile, ObjectInstancePtr light, TransformPtr add_trans, AttributePtr attribs) { double radius; double cos_rad; Vector vect1, vect2, temp_v; Vector direction; if ( ! light ) return 1; fprintf(outfile, "light "); fprintf(outfile, "%g %g %g ", attribs->intensity.red, attribs->intensity.green, attribs->intensity.blue); if ( light->o_parent->b_class == light_obj ) { fprintf(outfile, "point "); Transform_Vector(*add_trans, light->o_transform.displacement, temp_v); VPrint(outfile, temp_v); } if ( light->o_parent->b_class == spotlight_obj ) { Vector v0, v8, v9; Transform_Vector(*add_trans, light->o_world_verts[0], v0); Transform_Vector(*add_trans, light->o_world_verts[8], v8); Transform_Vector(*add_trans, light->o_world_verts[9], v9); /* Calculate the radius. */ VSub(v0, v9, vect1); VSub(v8, v9, vect2); VUnit(vect1, radius, vect1); VUnit(vect2, radius, vect2); cos_rad = VDot(vect1, vect2); radius = acos(cos_rad) * 180 / M_PI; if ( attribs->invert ) { /* Invert it. */ /* vect2 still points toward direction. */ VScalarMul(vect2, -1.0, vect2); VAdd(vect2, v9, direction); radius += 90.0; } else direction = v8; fprintf(outfile, "spot "); VPrint(outfile, light->o_transform.displacement); fprintf(outfile, "\t"); VPrint(outfile, direction); fprintf(outfile, "\t%g %g %g\n", attribs->tightness, radius, radius * attribs->radius); } if ( light->o_parent->b_class == arealight_obj ) { Vector v0, v1, v2; Transform_Vector(*add_trans, light->o_world_verts[0], v0); Transform_Vector(*add_trans, light->o_world_verts[1], v1); Transform_Vector(*add_trans, light->o_world_verts[2], v2); fprintf(outfile, "\tarea "); VPrint(outfile, v1); fprintf(outfile, "\t"); VPrint(outfile, v0); fprintf(outfile, "\t%d\n\t", attribs->samples & 0xFF); VPrint(outfile, v2); fprintf(outfile, "\t%d\n", (attribs->samples >> 8 ) & 0XFF); } if ( light->o_parent->b_class == dirlight_obj ) { Vector v0, v5; Transform_Vector(*add_trans, light->o_world_verts[0], v0); Transform_Vector(*add_trans, light->o_world_verts[5], v5); fprintf(outfile, "\tdirectional "); VSub(light->o_world_verts[5], light->o_world_verts[0], vect1); VPrint(outfile, vect1); } return fprintf(outfile, "\n"); } static void Export_CSG_Bases(FILE *outfile, CSGNodePtr tree) { if ( ! tree ) return; if ( tree->csg_op == csg_leaf_op ) { if ( tree->csg_instance->o_parent->b_class == csg_obj || tree->csg_instance->o_parent->b_class == wireframe_obj || tree->csg_instance->o_parent->b_class == aggregate_obj ) Export_Basetypes(outfile, tree->csg_instance->o_parent, &identity); } else { Export_CSG_Bases(outfile, tree->csg_left_child); Export_CSG_Bases(outfile, tree->csg_right_child); } } static void Export_Aggregate_Bases(FILE *outfile, InstanceList insts,TransformPtr add_trans) { InstanceList inst_elmt; Transformation new_trans; for ( inst_elmt = insts ; inst_elmt != NULL ; inst_elmt = inst_elmt->next ) if ( Obj_Is_Derived(inst_elmt->the_instance) ) { Concat_Transform(*add_trans, inst_elmt->the_instance->o_transform, new_trans); Export_Basetypes(outfile, inst_elmt->the_instance->o_parent, &new_trans); } } static int Export_Aggregate_Object(FILE *outfile, InstanceList insts) { return Export_Instances(outfile, insts, &identity, NULL, FALSE); } static int Export_Basetypes(FILE *outfile, BaseObjectPtr base_obj, TransformPtr add_trans) { CSGNodePtr new_tree; int gridsize; Boolean did_grid = FALSE; InstanceList agg_lights; if ( base_obj->b_class == aggregate_obj && ( agg_lights = Aggregate_Contains_Light(base_obj, TRUE) ) ) { Export_Instances(outfile, agg_lights, add_trans, &(sced_preferences.default_attributes), TRUE); Free_Selection_List(agg_lights); } if ( Hash_Get_Value(base_hash, (unsigned long)base_obj) != (void*)-1 ) return 1; if ( base_obj->b_class == csg_obj ) { new_tree = CSG_Contract_Tree((CSGNodePtr)base_obj->b_struct); Export_CSG_Bases(outfile, new_tree); } else if ( base_obj->b_class == aggregate_obj ) { Export_Aggregate_Bases(outfile, ((AggregatePtr)base_obj->b_struct)->children, add_trans); } fprintf(outfile, "name %s\n", base_obj->b_label); if ( base_obj->b_class == csg_obj ) { gridsize = (int)floor(pow((double)CSG_Count_Tree_Size(new_tree), 0.3333)); if ( gridsize > 1 ) { did_grid = TRUE; fprintf(outfile, "grid %d %d %d\n", gridsize, gridsize, gridsize); } Export_CSG_Tree(outfile, new_tree); CSG_Delete_Tree(new_tree, FALSE); } else if ( base_obj->b_class == wireframe_obj ) { gridsize = (int)floor(pow((double)base_obj->b_major_wires[0]->num_faces, 0.3333)); if ( gridsize > 1 ) fprintf(outfile, "grid %d %d %d\n", gridsize, gridsize, gridsize); else fprintf(outfile, "list\n"); did_grid = TRUE; Export_Wireframe(outfile, base_obj->b_major_wires[0]); } else if ( base_obj->b_class == aggregate_obj ) { gridsize = (int)floor( pow((double)Instance_List_Length( ((AggregatePtr)base_obj->b_struct)->children), 0.3333)); if ( gridsize > 1 ) fprintf(outfile, "grid %d %d %d\n", gridsize, gridsize, gridsize); else fprintf(outfile, "list\n"); did_grid = TRUE; Export_Aggregate_Object(outfile, ((AggregatePtr)base_obj->b_struct)->children); } if ( did_grid ) fprintf(outfile, "end\n"); Hash_Insert(base_hash, (unsigned long)base_obj, (void*)base_obj); return fprintf(outfile, "\n"); } static int Export_CSG_Tree(FILE *outfile, CSGNodePtr tree) { if ( ! tree ) return 1; if ( tree->csg_op == csg_leaf_op ) { fprintf(outfile, "/* %s */\n", tree->csg_instance->o_label); Export_Object_Type(outfile, tree->csg_instance, tree->csg_instance->o_attribs->defined ? tree->csg_instance->o_attribs : NULL); Export_Transformation(outfile, tree->csg_instance, &identity); if ( tree->csg_instance->o_attribs->defined && tree->csg_instance->o_attribs->use_extension && tree->csg_instance->o_attribs->extension[Rayshade]) Export_Texture(outfile, tree->csg_instance, &identity, tree->csg_instance->o_attribs); } else { switch ( tree->csg_op ) { case csg_union_op: fprintf(outfile, "union\n"); break; case csg_intersection_op: fprintf(outfile, "intersect\n"); break; case csg_difference_op: fprintf(outfile, "difference\n"); break; default:; } Export_CSG_Tree(outfile, tree->csg_left_child); Export_CSG_Tree(outfile, tree->csg_right_child); return fprintf(outfile, "end\n"); } return 1; } static void Export_Face(FILE *outfile, WireframePtr src, FacePtr face) { Vector temp_v1, temp_v2, norm; VSub(src->vertices[face->vertices[0]], src->vertices[face->vertices[1]], temp_v1); VSub(src->vertices[face->vertices[0]], src->vertices[face->vertices[2]], temp_v2); VCross(temp_v1, temp_v2, norm); if ( VZero(norm) ) return; fprintf(outfile, "triangle\n"); if ( face->face_attribs && face->face_attribs->defined ) Export_Attributes(outfile, face->face_attribs); VPrint(outfile, src->vertices[face->vertices[0]]); VPrint(outfile, src->normals[face->normals[0]]); VPrint(outfile, src->vertices[face->vertices[2]]); VPrint(outfile, src->normals[face->normals[2]]); VPrint(outfile, src->vertices[face->vertices[1]]); VPrint(outfile, src->normals[face->normals[1]]); if ( face->face_attribs && face->face_attribs->defined && face->face_attribs->use_extension && face->face_attribs->extension[Rayshade] ) fprintf(outfile, "\t%s\n", face->face_attribs->extension[Rayshade]); } static int Export_Wireframe(FILE *outfile, WireframePtr wire) { int i; for ( i = 0 ; i < wire->num_faces ; i++ ) Export_Face(outfile, wire, wire->faces + i); return 1; } static int Export_Aliased_Object(FILE *outfile, ObjectInstancePtr obj, TransformPtr add_trans) { char *alias = (char*)obj->o_aliases[Rayshade]; int index; fprintf(outfile, "/* %s */\n", obj->o_label); index = 0; while ( alias[index] != '\0' ) { if ( alias[index] == '(' && alias[index + 1] == '*' ) { if ( ! strncmp(alias + index, "(*transform*)", 13) ) { Export_Transformation(outfile, obj, add_trans); index += 13; } else fputc((int)alias[index++], outfile); } else fputc((int)alias[index++], outfile); } return 1; } static int Export_Instances(FILE *outfile, InstanceList insts, TransformPtr add_trans, AttributePtr def_attribs, Boolean do_lights) { InstanceList inst_elmt; ObjectInstancePtr inst; AttributePtr attribs; Transformation new_trans; for ( inst_elmt = insts ; inst_elmt != NULL ; inst_elmt = inst_elmt->next ) { inst = inst_elmt->the_instance; if ( Obj_Is_Construction(inst) ) continue; attribs = inst->o_attribs->defined ? inst->o_attribs : def_attribs; if ( Obj_Is_Light(inst) ) { if ( do_lights ) Export_Light(outfile, inst, add_trans, attribs); } else if ( Obj_Is_Aliased(inst, Rayshade) ) Export_Aliased_Object(outfile, inst, add_trans); else { if ( Obj_Is_Derived(inst) ) { Concat_Transform(*add_trans, inst->o_transform, new_trans); Export_Basetypes(outfile, inst->o_parent, &new_trans); } fprintf(outfile, "/* %s */\n", inst->o_label); Export_Object_Type(outfile, inst, attribs); Export_Transformation(outfile, inst, add_trans); if ( inst->o_attribs->defined && inst->o_attribs->use_extension && inst->o_attribs->extension[Rayshade] ) Export_Texture(outfile, inst, add_trans, attribs); } } return fprintf(outfile, "\n"); } static void Export_Object_Type(FILE *outfile, ObjectInstancePtr inst, AttributePtr attribs) { WireframePtr bezier_wire; switch ( inst->o_parent->b_class ) { case sphere_obj: fprintf(outfile, "sphere\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); fprintf(outfile, "1 0.0 0.0 0.0\n"); break; case cylinder_obj: if ( attribs && attribs->defined && attribs->open ) fprintf(outfile, "\tcylinder\n"); else fprintf(outfile, "object\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); if ( attribs && attribs->defined && attribs->open) fprintf(outfile, "\t1 0.0 0.0 -1.0 0.0 0.0 1.0\n"); else fprintf(outfile, "\tmy_cylinder\n"); break; case cone_obj: if ( attribs && attribs->defined && attribs->open) fprintf(outfile, "\tcone\n"); else fprintf(outfile, "object\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); if ( attribs && attribs->defined && attribs->open) fprintf(outfile, "\t1 0.0 0.0 -1.0 0.0 0.0 0.0 1.0\n"); else fprintf(outfile, "\tmy_cone\n"); break; case cube_obj: fprintf(outfile, "box\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); fprintf(outfile, "-1 -1 -1 1 1 1\n"); break; case torus_obj: fprintf(outfile, "torus\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); fprintf(outfile, "%1.15g 1.0 0 0 0 0 0 1\n", ((TorusPtr)inst->o_hook)->major_radius); break; case plane_obj: fprintf(outfile, "plane\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); fprintf(outfile, "0 0 0 0 0 1\n"); break; case triangle_obj: fprintf(outfile, "poly\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); VPrint(outfile, control_part(inst)->control_verts[2]); VPrint(outfile, control_part(inst)->control_verts[1]); VPrint(outfile, control_part(inst)->control_verts[0]); break; case csg_obj: case wireframe_obj: case aggregate_obj: fprintf(outfile, "object\n"); if ( attribs && attribs->defined ) Export_Attributes(outfile, attribs); fprintf(outfile, "\t%s\n", inst->o_parent->b_label); break; case bezier_obj: fprintf(outfile, "grid %d %d 1\n", Wireframe_Density_Level(inst) + 2, Wireframe_Density_Level(inst) + 2); bezier_wire = Object_To_Wireframe(inst, FALSE); Export_Wireframe(outfile, bezier_wire); Wireframe_Destroy(bezier_wire); fprintf(outfile, "end\n\n"); break; default:; } } static void Export_Transformation(FILE *outfile, ObjectInstancePtr inst, TransformPtr add) { Transformation total; Matrix transp; MVMul(add->matrix, inst->o_transform.displacement, total.displacement); VAdd(total.displacement, add->displacement, total.displacement); total.matrix = MMMul(&(add->matrix), &(inst->o_transform.matrix)); MTrans(total.matrix, transp); fprintf(outfile, "\ttransform\n"); fprintf(outfile, "\t"); VPrint(outfile, transp.x); fprintf(outfile, "\t"); VPrint(outfile, transp.y); fprintf(outfile, "\t"); VPrint(outfile, transp.z); fprintf(outfile, "\t"); VPrint(outfile, total.displacement); } static void Export_Attributes(FILE *outfile, AttributePtr attribs) { fprintf(outfile, "\tambient %g %g %g\n", attribs->color.red, attribs->color.green, attribs->color.blue); fprintf(outfile, "\tdiffuse %g %g %g\n", attribs->color.red * attribs->diff_coef, attribs->color.green * attribs->diff_coef, attribs->color.blue * attribs->diff_coef); fprintf(outfile, "\tspecular %g %g %g\n", attribs->color.red * attribs->spec_coef, attribs->color.green * attribs->spec_coef, attribs->color.blue * attribs->spec_coef); fprintf(outfile, "\tspecpow %g\n", attribs->spec_power); fprintf(outfile, "\treflect %g\n", attribs->reflect_coef); fprintf(outfile, "\ttransp %g\n", attribs->transparency); fprintf(outfile, "\tindex %g\n", attribs->refract_index); } static void Export_Texture(FILE *outfile, ObjectInstancePtr inst, TransformPtr trans, AttributePtr attribs) { fprintf(outfile, "\t%s\n", attribs->extension[Rayshade]); if ( attribs->use_obj_trans ) Export_Transformation(outfile, inst, trans); } static int Export_Declarations(FILE *outfile) { if ( declarations[Rayshade] ) return fprintf(outfile, "%s\n", declarations[Rayshade]); return 1; }