indexing description: "[ saves a scene, given the scene and the file name. ]" date: "$Date$" revision: "$Revision$" class SCENE_SAVER inherit KL_SHARED_FILE_SYSTEM export {NONE} all end create make, make_from_absolute, make_empty feature -- Initialization make (a_scene: SCENE; a_path, a_file: STRING) is -- creates a SCENE_SAVER object require a_scene_not_void: a_scene /= Void a_path_not_void: a_path /= Void a_file_not_void: a_file /= Void do scene := a_scene file := File_system.pathname (a_path, a_file) ensure scene_set: scene = a_scene end make_from_absolute (a_scene: SCENE; a_file: STRING) is -- creates a SCENE_SAVER object require a_scene_not_void: a_scene /= Void a_file_not_void: a_file /= Void do scene := a_scene file := a_file ensure scene_set: scene = a_scene end make_empty is -- Create empty scene saver do scene := create {SCENE}.make file := "no file" end feature -- Access scene: SCENE -- current scene file: STRING -- current file name (absolute path) error_type: INTEGER -- saves the `error_type' -- 0: no error is_file_valid: INTEGER is -- returns status of `file' -- 0: invalid path -- 1: has to be created -- 2: already exists -- 3: exists, but is not readable local fp: KL_TEXT_OUTPUT_FILE do create fp.make (file) if fp.exists then if not fp.is_readable then Result := 3 else Result := 2 end else -- file does not exist, check if the path is valid if file_system.directory_exists (file_system.absolute_parent_directory (file)) then -- directory exists -> file can be created Result := 1 else -- directory does not exist Result := 0 end end end export_types: DS_LINKED_LIST [EXPORTER] is -- lists all implemented export types once create Result.make -- Export type 1: Result.force_last (create {EXPORT_TO_EIFFEL_COLLISION_DETECTION}.make (scene)) end feature {NONE} -- Export Types export_from_image_pane (index: INTEGER; pane: IMAGE_PANE): STRING is -- takes the export type index and an image pane do create Result.make_empty if index = 1 then -- image panes wont be needed for collision detection Result := "" end end export_from_object (index: INTEGER; obj: OBJECT): STRING is -- takes the export type index and an object do create Result.make_empty if index = 1 then Result := "" end end feature -- Element Change set_file (a_path, a_file: STRING) is -- sets `file' require a_path_not_void: a_path /= Void a_file_not_void: a_file /= Void do file := File_system.pathname (a_path, a_file) end feature -- Computation save is -- saves the file, if possible, otherwise sets `error_type' require file_path_valid: is_file_valid = 1 or is_file_valid = 2 local fp: KL_TEXT_OUTPUT_FILE do create fp.make (file) fp.open_write check fp.is_open_write end if fp.is_open_write then -- write data to the file fp.put_string (scene_to_string) fp.close end check fp.is_closed end end open is -- opens the file and generates `image_panes' and `objects' -- if the file format is invalid image_panes and objects will be set to void require file_path_valid: is_file_valid = 2 local fp: KL_TEXT_INPUT_FILE str_list: LINKED_LIST [STRING] vertex_list: DS_LINKED_LIST [EM_VECTOR_2D] t, x1, y1: DOUBLE phase, i, xi, yi, xj, yj: INTEGER command: IMPORT_IMAGE line_error: BOOLEAN poly: POLYGON do create fp.make (file) fp.open_read check fp.is_open_read end -- parse file and add elements to `scene' from until fp.end_of_file or fp.end_of_input loop fp.read_line if fp.last_string.is_equal ("IMAGE PANES") then phase := 1 elseif fp.last_string.is_equal ("CIRCLES") then phase := 2 elseif fp.last_string.is_equal ("RECTANGLES") then phase := 3 elseif fp.last_string.is_equal ("POLYGONS") then phase := 4 elseif not fp.last_string.is_equal ("") then create str_list.make str_list.append (fp.last_string.split (delimiter_char)) str_list.start line_error := False if phase = 1 then -- load image panes create command.make command.scene_saver_execute (str_list.item) if command.execute_successful and str_list.count = elements_pane then line_error := False str_list.remove if str_list.item.is_double then t := str_list.item.to_double else line_error := True end str_list.remove if not line_error and str_list.item.is_double then command.pane.set_true_x_y (t, str_list.item.to_double) else line_error := True end str_list.remove if not line_error and str_list.item.is_double then t := str_list.item.to_double if t <= 0 then line_error := True end else line_error := True end str_list.remove if str_list.item.is_double and then str_list.item.to_double > 0 then t := str_list.item.to_double else line_error := True end if not line_error and str_list.item.is_double then command.pane.set_scale (t, str_list.item.to_double) str_list.remove if str_list.item.is_integer then i := str_list.item.to_integer if i < 0 or i > 255 then line_error := True else command.pane.set_transparency (i) end end str_list.remove if not line_error and then str_list.item.is_integer then i := str_list.item.to_integer command.pane.set_z_index (i) scene.image_panes.put (command.pane) end else line_error := True end end elseif phase = 2 then -- load circles if str_list.count = 3 then if str_list.item.is_double then x1 := str_list.item.to_double else line_error := True end str_list.remove if str_list.item.is_double and not line_error then y1 := str_list.item.to_double else line_error := True end str_list.remove if str_list.item.is_double and not line_error then t := str_list.item.to_double else line_error := True end if t > 0 and not line_error then scene.circles.force_last (create {CIRCLE}.make_obj (create {EM_VECTOR_2D}.make (x1, y1), t, scene)) end end elseif phase = 3 then -- load rectangles if str_list.count = 4 then if str_list.item.is_integer then xi := str_list.item.to_integer else line_error := True end str_list.remove if str_list.item.is_integer and not line_error then yi := str_list.item.to_integer else line_error := True end str_list.remove if str_list.item.is_integer and not line_error then xj := str_list.item.to_integer else line_error := True end str_list.remove if str_list.item.is_integer and not line_error then yj := str_list.item.to_integer else line_error := True end if (xi-xj).abs > 0 and (yi-yj).abs > 0 and not line_error then scene.rectangles.force_last (create {RECTANGLE}.make_obj (create {EM_VECTOR_2D}.make (xi, yi), create {EM_VECTOR_2D}.make (xj, yj), scene)) end end elseif phase = 4 then -- load polygons if str_list.count = 2 then if str_list.item.is_integer then xj := str_list.item.to_integer else line_error := True end str_list.remove if str_list.item.is_integer and not line_error then yj := str_list.item.to_integer create poly.make_obj (create {EM_VECTOR_2D}.make (xj, yj), scene) else line_error := True end else line_error := True end -- line 2 fp.read_line create str_list.make str_list.append (fp.last_string.split (delimiter_char)) str_list.start if not line_error then -- load positions and extend polygon create vertex_list.make from until str_list.count < 2 loop if str_list.item.is_double then x1 := str_list.item.to_double str_list.remove if str_list.item.is_double then y1 := str_list.item.to_double str_list.remove vertex_list.force_last (create {EM_VECTOR_2D}.make (x1, y1)) else line_error := True end else line_error := True end end if vertex_list.count > 2 and not line_error then poly.set_true_values_internal (xj, yj, xj, yj, vertex_list, vertex_list) end end -- line 3 fp.read_line create str_list.make str_list.append (fp.last_string.split (delimiter_char)) str_list.start if not line_error then -- load positions and extend polygon from until str_list.count < 2 loop if str_list.item.is_integer then xi := str_list.item.to_integer str_list.remove if str_list.item.is_integer then yi := str_list.item.to_integer str_list.remove if xi > 0 and xi <= poly.count and yi > 0 and yi <= poly.count then poly.splitting_lines.force_last (create {EM_PAIR [INTEGER, INTEGER]}.make (xi, yi)) end else line_error := True end else line_error := True end end end if not line_error and poly /= Void then poly.set_changed poly.recreate_collidable scene.polygons.force_last (poly) end end end end fp.close check fp.is_closed end end export_overwrite (exp: EXPORTER) is -- export the file with the selected export type (`index') require file_path_valid: is_file_valid = 1 or is_file_valid = 2 local fp: KL_TEXT_OUTPUT_FILE do create fp.make (file) fp.open_write exp.set_scene (scene) check fp.is_open_write end if fp.is_open_write then -- write data to the file fp.put_string (exp.scene_to_string) fp.close end check fp.is_closed end end feature {NONE} -- Implementation scene_to_string: STRING is -- returns a string of the scenes information. -- used to save scenes. local panes, objectstr, d: STRING p: IMAGE_PANE c: CIRCLE r: RECTANGLE po: POLYGON do create panes.make_empty d := delimiter panes.append ("IMAGE PANES%N") -- format: -- image_file_path;x;y;scale_x;scale_y;transparency;z_index from scene.image_panes.start until scene.image_panes.off loop p := scene.image_panes.item_for_iteration panes.append (p.image_file_path+d+p.true_x.out+d+p.true_y.out+d+p.scale_x.out+d+p.scale_y.out+d+p.transparency.out+d+p.z_index.out+nl) scene.image_panes.forth end create objectstr.make_empty objectstr.append ("CIRCLES%N") -- format: -- center_x;center_y;radius from scene.circles.start until scene.circles.off loop c := scene.circles.item_for_iteration objectstr.append (c.center.x.out+d+c.center.y.out+d+c.radius.out+nl) scene.circles.forth end objectstr.append ("RECTANGLES%N") -- format: -- x1;y1;x2;y2 from scene.rectangles.start until scene.rectangles.off loop r := scene.rectangles.item_for_iteration objectstr.append (r.point_a.x.out+d+r.point_a.y.out+d+r.point_b.x.out+d+r.point_b.y.out+nl) scene.rectangles.forth end objectstr.append ("POLYGONS%N") -- format (3 lines per polygon): -- center_x;center_y; (x/y: INTEGER) -- [x;y;]* (vertexes: DOUBLE) -- [from_index;to_index;]* (splitting_lines: INTEGER) from scene.polygons.start until scene.polygons.off loop po := scene.polygons.item_for_iteration objectstr.append (po.x.out+d+po.y.out+nl) from po.start until po.off loop objectstr.append (po.item_for_iteration.x.out+d+po.item_for_iteration.y.out+d) po.forth end if po.count > 0 then objectstr.remove_tail (1) end objectstr.append (nl) from po.splitting_lines.start until po.splitting_lines.off loop objectstr.append (po.splitting_lines.item_for_iteration.first.out+d+po.splitting_lines.item_for_iteration.second.out+d) po.splitting_lines.forth end if po.splitting_lines.count > 0 then objectstr.remove_tail (1) end objectstr.append (nl) scene.polygons.forth end Result := panes + objectstr ensure result_not_void: Result /= Void end delimiter: STRING is ";" -- delimiter for the save-format delimiter_char: CHARACTER is ';' -- delimiter saved as character nl: STRING is "%N" -- new line elements_pane: INTEGER is 7 -- number of elements in the pane delimiter-list invariant scene_not_void: scene /= Void file_not_void: file /= Void end