indexing description: "3D Component for the elfractal example" author: "Lars Krapf" date: "$Date$" revision: "$Revision$" class EF_3D_DISPLAY inherit EM_3D_COMPONENT EMGL_BASIC_RENDERER EM_TIME_SINGLETON DOUBLE_MATH export {NONE} all end create make_from_dimension feature {NONE} -- Initialisation make_from_dimension(a_width: INTEGER; a_height: INTEGER) is -- Initialise default values. require valid_dimension: a_width > 0 and a_height > 0 do make_3d_component set_max_view_distance(10000.0) set_dimension(a_width, a_height) set_tooltip ("left-drag to rotate, right-drag to zoom") longitude := 10 latitude := 20 distance := 100 angle := 0.6 create l_system.make_empty -- Prepare Usercommands create user_commands_string.make_empty create user_commands.make (19) -- Event registration mouse_dragged_event.subscribe (agent handle_mouse_dragged) mouse_wheel_up_event.subscribe (agent handle_mouse_wheel_up) mouse_wheel_down_event.subscribe (agent handle_mouse_wheel_down) emgl_enable(em_gl_blend) emgl_blend_func (em_gl_src_alpha, em_gl_one_minus_src_alpha) ensure system_exists: l_system /= Void end feature -- Element Change set_stereoscopic(a_bool: BOOLEAN) is -- set stereoscopic view and recreate emgl_list do stereoscopic := a_bool create_script end set_angle(an_angle: INTEGER) is do angle := pi*an_angle/180 end set_user_commands_string(a_string: STRING) is -- Set the String representing the user definitions for the l-system require user_commands_valid: a_string /= Void do user_commands_string := a_string parse_user_commands ensure user_commands_set: user_commands_string /= Void end set_system_string(a_string: STRING) is -- Set the String representing the system to execute require a_string_not_void: a_string /= Void do l_system := a_string ensure system_valid: l_system /= Void end set_iterations(n: INTEGER) is -- Set the number of iterations require atleast_one_iteration: n >= 0 do iterations := n ensure iterations_valid: iterations >= 0 end set_simple_mode(mode: BOOLEAN) is -- Set simple mode do simple_mode := mode end feature -- Access longitude: REAL -- Longitude of the eye (in degree) around center (0,0,0) latitude: REAL -- Latitude of the eye (in degree) around center (0,0,0) distance: REAL -- Distance of the eye to center (0,0,0) user_commands_string: STRING -- string representation of the user commands feature -- Basic operations create_script is -- Create the emgl_Script and redraw local state: EF_STATE do iterations_count := 0 emgl_new_list(script, EM_GL_COMPILE) state := draw_lines(l_system, create {EF_STATE}.make,iterations) emgl_end_list end set_animated(status: BOOLEAN) is -- set animated status do animated := status create_script end feature -- Drawing draw is -- Draw the compiled GLList do if animated then angle := angle + 0.005 max_iterations := 4000 create_script else max_iterations := 50000 end if stereoscopic then -- draw left eye emgl_load_identity emglu_look_at (-1.0,0,-distance,0,0,0,0,1,0) emgl_rotatef (-longitude, 0, 1, 0) emgl_rotatef (latitude, cosine (-longitude / 180 * pi),0,sine (-longitude / 180 * pi)) emgl_begin(EM_GL_LINES) emgl_color4f(0.7,0,0,0.6) emgl_call_list(script) emgl_end -- draw right eye emgl_load_identity emglu_look_at (1.0,0,-distance,0,0,0,0,1,0) emgl_rotatef (-longitude, 0, 1, 0) emgl_rotatef (latitude, cosine (-longitude / 180 * pi),0,sine (-longitude / 180 * pi)) emgl_begin(EM_GL_LINES) emgl_color4f(0.0,0.7,0,0.6) emgl_call_list(script) emgl_end else emgl_load_identity emglu_look_at (0,0,-distance,0,0,0,0,1,0) emgl_rotatef (-longitude, 0, 1, 0) emgl_rotatef (latitude, cosine (-longitude / 180 * pi),0,sine (-longitude / 180 * pi)) emgl_begin(EM_GL_LINES) emgl_call_list(script) emgl_end end -- Set up eye position -- Draw List end feature {NONE} -- Mouse management handle_mouse_dragged (event: EM_MOUSEMOTION_EVENT) is -- Handle mouse dragged event. do if event.button_state_left then longitude := longitude - event.motion.x latitude := latitude + event.motion.y if latitude > 90 then latitude := 90 elseif latitude < -90 then latitude := -90 end end if event.button_state_right then distance := distance + event.motion.y if distance < 0 then distance := 0 end if distance > 2000 then distance := 2000 end end end handle_mouse_wheel_up is -- Handle mouse wheel up event. do angle := angle + 0.02 create_script end handle_mouse_wheel_down is -- Handle mouse wheel down event. do angle := angle - 0.02 create_script end feature {NONE} -- Implementation max_iterations: INTEGER -- the maximum number of iterations parse_user_commands is -- Go to user definitions and fill hash_table local lines: LIST [STRING] line: LIST [STRING] do user_commands.clear_all -- go through user_command_string line by line lines := user_commands_string.split('%N') from lines.start until lines.after loop -- split definition on '=' and store it into hashtable line := lines.item.split('=') if line.count = 2 then user_commands.put (line.i_th(2), line.i_th(1)) end lines.forth end end is_builtin(a_char: CHARACTER):BOOLEAN is -- check if a_char is a special character do Result := a_char.is_equal('[') or a_char.is_equal(']') end draw_lines(system: STRING; a_state: EF_STATE; iteration: INTEGER;):EF_STATE is local i,j: INTEGER state, old_state: EF_STATE token: STRING do iterations_count := iterations_count + 1 state := a_state.twin if iterations_count < max_iterations then -- Go through Systemstring, char by char and parse tokens from i := 2 j := 1 until j > system.count loop -- found end of current token? if i > system.count or system.item(i).is_upper or is_builtin(system.item(i)) then token := system.substring(j,i-1) j := i -- token recognized? if user_commands.has(token) then if iteration > 0 then -- execute user defined command state := draw_lines(user_commands[token], state, iteration-1) else if not stereoscopic then if simple_mode then -- use colors based on current coordinates emgl_color3f(1-state.x*0.02,1-state.y*0.02,1-state.z*0.02) else -- use colors from state emgl_color3f(state.r, state.g, state.b) end end -- draw a line in current direction emgl_vertex3f(state.x, state.y, state.z) state.set_coordinates(state.x-sine(state.phi)*cosine(state.rho),state.y+sine(state.rho),state.z+cosine(state.rho)*cosine(state.phi)) emgl_vertex3f(state.x, state.y, state.z) end end -- color Builtins if token.is_equal("Red+") then state.set_colors(state.r + 0.05, state.g, state.b) end if token.is_equal("Red-") then state.set_colors(state.r - 0.05, state.g, state.b) end if token.is_equal("Green+") then state.set_colors(state.r, state.g + 0.05, state.b) end if token.is_equal("Green-") then state.set_colors(state.r, state.g - 0.05, state.b) end if token.is_equal("Blue+") then state.set_colors(state.r, state.g, state.b + 0.05) end if token.is_equal("Blue-") then state.set_colors(state.r, state.g, state.b - 0.05) end -- step forward if token.is_equal("F") then if iteration = 0 then -- if no more iterations left if not stereoscopic then if simple_mode then -- use colors based on current coordinates emgl_color3f(1-state.x*0.02,1-state.y*0.02,1-state.z*0.02) else -- use colors from state emgl_color3f(state.r, state.g, state.b) end end -- draw a line in current direction emgl_vertex3f(state.x, state.y, state.z) state.set_coordinates(state.x-sine(state.phi)*cosine(state.rho),state.y+sine(state.rho),state.z+cosine(state.rho)*cosine(state.phi)) emgl_vertex3f(state.x, state.y, state.z) else -- otherwise reiterate into current system state := draw_lines(system, state, iteration-1) end end -- directional builtins if token.is_equal("D") then state.set_angles(state.phi+angle, state.rho) end if token.is_equal("U") then state.set_angles(state.phi-angle, state.rho) end if token.is_equal("R") then state.set_angles(state.phi, state.rho+angle) end if token.is_equal("L") then state.set_angles(state.phi, state.rho-angle) end -- special builtins if token.is_equal("[") then -- store current state old_state := state.twin end if token.is_equal("]") then -- restore state if old_state /= Void then state := old_state.twin end end end i := i + 1 end end Result := state end iterations: INTEGER -- the number of iterations angle: DOUBLE -- the default angle of commands U,D,L and R script: INTEGER is 1 -- the opengl list to use l_system: STRING -- a string representation of the l-type system user_commands: HASH_TABLE [STRING, STRING] -- a hashtable containing user-defined commands animated: BOOLEAN -- animate angles? simple_mode: BOOLEAN -- simple mode? stereoscopic: BOOLEAN iterations_count: INTEGER end