indexing description: "[ Rendering facilities for Viz with support for antialiasing. Encapsulates OpenGL rendering commands and only exports those deemed useful for Viz rendering. Subclasses should use the vz_* commands instead of emgl_* ones. Antialiasing is currently a bit of a hack for polygons. ]" author: "" date: "$Date$" revision: "$Revision$" class EM_VIZ_RENDERER inherit EM_SHARED_VIZ_OPTIONS export {EM_VIZ_RENDERER} all end EMGL_VIEW rename emgl_rotate as vz_rotate, emgl_rotated as vz_rotated, emgl_translate as vz_translate, emgl_translated as vz_translated, emgl_scale as vz_scale, emgl_scaled as vz_scaled, emgl_push_matrix as vz_push_frame, emgl_pop_matrix as vz_pop_frame, emgl_mult_matrix as vz_mult_frame export {NONE} all {EM_VIZ_RENDERER} vz_rotate, vz_rotated, vz_translate, vz_translated, vz_scale, vz_scaled, vz_push_frame, vz_pop_frame, vz_mult_frame end EMGL_SETTINGS rename emgl_front_face as vz_set_front_face, emgl_point_size as vz_set_point_size, emgl_line_width as vz_set_line_width, emgl_push_attrib as vz_push_attributes, emgl_pop_attrib as vz_pop_attributes, Em_gl_front as Vz_front, Em_gl_back as Vz_back, Em_gl_front_and_back as Vz_front_and_back, Em_gl_ccw as Vz_counter_clockwise, Em_gl_cw as Vz_clockwise, Em_gl_line_bit as Vz_line_bit, Em_gl_polygon_bit as Vz_polygon_bit, Em_gl_point_bit as Vz_point_bit, Em_gl_depth_buffer_bit as Vz_depth_buffer_bit, Em_gl_color_buffer_bit as Vz_color_buffer_bit, Em_gl_lighting_bit as Vz_lighting_bit, Em_gl_transform_bit as Vz_transform_bit, Em_gl_clip_plane0 as Vz_clip_plane0, Em_gl_clip_plane1 as Vz_clip_plane1, Em_gl_clip_plane2 as Vz_clip_plane2, Em_gl_clip_plane3 as Vz_clip_plane3, Em_gl_clip_plane4 as Vz_clip_plane4, Em_gl_clip_plane5 as Vz_clip_plane5, Em_gl_points as Vz_points, Em_gl_lines as Vz_lines, Em_gl_line_strip as Vz_line_strip, Em_gl_line_loop as Vz_line_loop, Em_gl_triangles as Vz_triangles, Em_gl_triangle_strip as Vz_triangle_strip, Em_gl_triangle_fan as Vz_triangle_fan, Em_gl_quads as Vz_quads, Em_gl_quad_strip as Vz_quad_strip, Em_gl_polygon as Vz_polygon export {NONE} all {EM_VIZ_RENDERER} -- The reason functions to access the state (like emgl_get*) -- are not exported is because this could possibly -- eff up display list support vz_set_front_face, vz_set_point_size, vz_set_line_width, vz_push_attributes, vz_pop_attributes, -- Culling Vz_front, Vz_back, Vz_front_and_back, Vz_counter_clockwise, Vz_clockwise, -- Attributes Vz_point_bit, Vz_line_bit, Vz_polygon_bit, Vz_depth_buffer_bit, Vz_color_buffer_bit, Vz_transform_bit, Vz_lighting_bit, -- Clipping planes Vz_clip_plane0, Vz_clip_plane1, Vz_clip_plane2, Vz_clip_plane3, Vz_clip_plane4, Vz_clip_plane5, -- Primitives Vz_points, Vz_lines, Vz_line_strip, Vz_line_loop, Vz_triangles, Vz_triangle_strip, Vz_triangle_fan, Vz_quads, Vz_quad_strip, Vz_polygon end EMGL_BASIC_RENDERER export {NONE} all end feature {EM_VIZ_RENDERER} -- Transformation vz_snap_point (point: EM_VECTOR3D): EM_VECTOR3D -- Snap a point so it's in integral window coordinates (used for font rendering) -- Result can have fractional values. But transformed point should be integral! local -- FIXME: If these two are EM_MATRIX44, the program randomly crashes on Mac OS X, x86 -- (The only platform I have access to) -- I have absolutely no idea why, it's always something deep inside of Eiffel. But -- if I'd had to guess, I'd say that somewhere along the way, there's a buffer overflow. -- Especially because occurrences are seemingly random and it's mostly bus-errors. -- And the occasional stack corruption is a pretty good indicator, too. mvm, invmvm: EM_MATRIX44_REF wc, rwc: EM_VECTOR4D do if Viz_options.use_point_snapping then -- This could be sped up by buffering the modelview matrix and its inverse! mvm := emgl_get_modelview_matrix invmvm := mvm.inversed wc := mvm.mult ([point.x, point.y, point.z, 1.0]) rwc.set (wc.x.rounded, wc.y.rounded, wc.z , 1.0) Result := invmvm.mult (rwc).to_vector3d else Result := point end end feature {EM_VIZ_RENDERER} -- Rendering commands vz_color (c: EM_COLOR) is -- Set current color do vz_color4ub (c.red, c.green, c.blue, c.alpha) end vz_color3ub (r, g, b: INTEGER) is -- Set current color (replaces emgl_color3ub) do vz_color4ub (r, g, b, 255) end vz_color4ub (r, g, b, a: INTEGER) is -- Set current color (replaces emgl_color4ub) do gl_current_color.set (r/255, g/255, b/255, a/255) end vz_color3d (r, g, b: DOUBLE) is -- Set current color (replaces emgl_color3d) do vz_color4d (r, g, b, 1.0) end vz_color4d (r, g, b, a: DOUBLE) is -- Set current color (replaces emgl_color4d) do gl_current_color.set (r, g, b, a) end vz_normal (v: EM_VECTOR3D) is -- Set current normal do gl_current_normal := v end vz_normal3d (x, y, z: DOUBLE) is -- Set current normal (replaces emgl_normal3d) do gl_current_normal.set (x, y, z) end vz_vertex (v: EM_VECTOR3D) is -- Set current vertex do gl_current_vertex := v gl_flush_vertex end vz_vertex2d (x, y: DOUBLE) is -- Set current vertex (replaces emgl_vertex2d) do gl_current_vertex.set (x, y, 0.0) gl_flush_vertex end vz_vertex3d (x, y, z: DOUBLE) is -- Set current vertex (replaces emgl_vertex3d) do gl_current_vertex.set (x, y, z) gl_flush_vertex end feature {EM_VIZ_RENDERER} -- Rendering primitives vz_begin_points is do vz_begin (Vz_points) end -- Shortcut for vz_begin (Vz_points) vz_begin_lines is do vz_begin (Vz_lines) end -- Shortcut for vz_begin (Vz_lines) vz_begin_line_strip is do vz_begin (Vz_line_strip) end -- Shortcut for vz_begin (Vz_line_strip) vz_begin_line_loop is do vz_begin (Vz_line_loop) end -- Shortcut for vz_begin (Vz_line_loop) vz_begin_triangles is do vz_begin (Vz_triangles) end -- Shortcut for vz_begin (Vz_triangles) vz_begin_triangle_strip is do vz_begin (Vz_triangle_strip) end -- Shortcut for vz_begin (Vz_triangle_strip) vz_begin_triangle_fan is do vz_begin (Vz_triangle_fan) end -- Shortcut for vz_begin (Vz_triangle_fan) vz_begin_quads is do vz_begin (Vz_quads) end -- Shortcut for vz_begin (Vz_quads) vz_begin_quad_strip is do vz_begin (Vz_quad_strip) end -- Shortcut for vz_begin (Vz_quad_strip) vz_begin_polygon is do vz_begin (Vz_polygon) end -- Shortcut for vz_begin (Vz_polygon) vz_begin (mode: INTEGER) is -- Replaces emgl_begin do gl_globals.mode := mode gl_globals.save := False if gl_globals.aa_hack then if mode = Vz_triangles or else mode = Vz_triangle_strip or else mode = Vz_triangle_fan or else mode = Vz_quads or else mode = Vz_quad_strip or else mode = Vz_polygon then gl_globals.save := True end end if gl_globals.save then gl_begin_saving end emgl_begin (mode) end vz_end is -- Replaces emgl_end do emgl_end if gl_globals.save then -- Use aa hack to render antialiased polygons? if gl_globals.aa_hack then -- Save affected attributes vz_push_attributes (Vz_polygon_bit | Vz_line_bit | Vz_depth_buffer_bit) vz_set_line_width (1.0) -- Draw lines emgl_polygon_mode (Vz_front_and_back, Em_gl_line) emgl_enable (Em_gl_polygon_offset_line) emgl_depth_mask (Em_gl_false) emgl_polygon_offset (-1, 0) emgl_begin (gl_globals.mode) gl_replay_vertices emgl_end -- Revert vz_pop_attributes end gl_end_saving end end feature {EM_VIZ_RENDERER} -- Rendering settings Vz_all_attribute_bits: INTEGER is -- All attributes that could be affected once Result := Vz_point_bit | Vz_line_bit | Vz_polygon_bit | Vz_depth_buffer_bit | Vz_color_buffer_bit | Vz_transform_bit | Vz_lighting_bit end vz_set_defaults is -- Setup default state do vz_set_front_face (Vz_clockwise) vz_set_culling (True, Vz_back) vz_set_line_width (1.0) vz_set_point_size (1.0) vz_set_depth_test (False, False) vz_set_blending (True) vz_set_lighting (False) vz_default_antialiasing end vz_set_blending (enable: BOOLEAN) is -- Set blending enable do if enable then emgl_enable (Em_gl_blend) emgl_blend_func (Em_gl_src_alpha, Em_gl_one_minus_src_alpha) else emgl_disable (Em_gl_blend) end end vz_set_lighting (enable: BOOLEAN) is -- Enable and set lighting parameters local i: INTEGER do if enable then emgl_enable (Em_gl_lighting) -- Only enable the first light emgl_enable (Em_gl_light0) from i := Em_gl_light1 until i > Em_gl_light7 loop emgl_disable (i) i := i + 1 end emgl_color_material (Vz_front_and_back, Em_gl_ambient_and_diffuse) emgl_light_modeli (Em_gl_light_model_two_side, 1) emgl_enable (Em_gl_color_material) emgl_enable (Em_gl_normalize) else emgl_disable (Em_gl_lighting) end end vz_set_light (color: EM_COLOR; direction: EM_VECTOR3D) is -- Set light parameters local c: EM_VECTOR4F d: EM_VECTOR4F do c.set (color.red, color.green, color.blue, color.alpha) c.scale (1.0/255.0) gl_lightfv_external (Em_gl_light0, Em_gl_diffuse, c) -- Reverse z d := [direction.x, direction.y, -direction.z, 0.0] gl_lightfv_external (Em_gl_light0, Em_gl_position, d) end vz_set_culling (enabled: BOOLEAN; face: like Vz_front_and_back) is -- Set culling enable and face do if enabled then emgl_enable (Em_gl_cull_face) emgl_cull_face (face) else emgl_disable (Em_gl_cull_face) end end vz_enable_clip_plane (plane: like Vz_clip_plane0; a, b, c, d: DOUBLE) is -- Enable clip `plane' with components `a', `b', `c', `d' local v: EM_VECTOR4D do v.set (a, b, c, d) emgl_enable (plane) emgl_clip_plane (plane, v) end vz_override_antialiasing (enabled: BOOLEAN) is -- Override global antialiasing settings do if enabled then emgl_enable (Em_gl_point_smooth) emgl_enable (Em_gl_line_smooth) -- Disable polygon smoothing (deprecated by most modern gfx hw) -- This is why we have gl_aa_hack emgl_disable (Em_gl_polygon_smooth) gl_globals.aa_hack := True else emgl_disable (Em_gl_point_smooth) emgl_disable (Em_gl_line_smooth) emgl_disable (Em_gl_polygon_smooth) gl_globals.aa_hack := False end end vz_default_antialiasing is -- Revert antialiasing settings to default do vz_override_antialiasing (Viz_options.use_antialiasing) end vz_set_depth_test (depth_test, depth_write: BOOLEAN) -- Set depth test enable and write -- This behaves a bit different than OpenGL: -- If `depth_write' is true, depth values will be written -- to the depth buffer regardless of depth_test do if depth_write then emgl_depth_mask (Em_gl_true) -- Needs to be on for depth writes... emgl_enable (Em_gl_depth_test) if depth_test then emgl_depth_func (Em_gl_less) else -- ...so just pass through emgl_depth_func (Em_gl_always) end else emgl_depth_mask (Em_gl_false) if depth_test then emgl_enable (Em_gl_depth_test) emgl_depth_func (Em_gl_less) else emgl_disable (Em_gl_depth_test) end end end feature {NONE} -- Implementation gl_globals: TUPLE [mode: INTEGER; aa_hack: BOOLEAN; save: BOOLEAN] is once create Result end -- Internals gl_current_color: EM_VECTOR4F -- Current color values gl_current_normal: EM_VECTOR3F -- Current normal values gl_current_vertex: EM_VECTOR3F -- Current vertex values gl_flush_vertex -- Called by vz_vertex to possibly save (for antialiasing hack) and pass vertex onto OpenGl do if gl_globals.save then gl_save_vertex end gl_pass_vertex end gl_colors: DS_ARRAYED_LIST [EM_VECTOR4F] is once create Result.make (3) end -- Saved colors gl_normals: DS_ARRAYED_LIST [EM_VECTOR3F] is once create Result.make (3) end -- Saved normals gl_vertices: DS_ARRAYED_LIST [EM_VECTOR3F] is once create Result.make (3) end -- Saved vertices gl_begin_saving is -- Begin saving vertex values do end gl_save_vertex is -- Save vertex values do gl_colors.force_last (gl_current_color) gl_normals.force_last (gl_current_normal) gl_vertices.force_last (gl_current_vertex) end gl_pass_vertex is -- Pass current vertex values to OpenGL do emgl_color4f (gl_current_color.x, gl_current_color.y, gl_current_color.z, gl_current_color.w) emgl_normal3f (gl_current_normal.x, gl_current_normal.y, gl_current_normal.z) emgl_vertex3f (gl_current_vertex.x, gl_current_vertex.y, gl_current_vertex.z) end gl_replay_vertex (i: INTEGER) is -- Pass saved vertex `i' to OpenGL do gl_current_color := gl_colors @ i gl_current_normal := gl_normals @ i gl_current_vertex := gl_vertices @ i gl_pass_vertex end gl_replay_vertices is -- Pass all saved vertices to OpenGL, again local i: INTEGER do from i := 1 until i > gl_vertices.count loop gl_replay_vertex (i) i := i + 1 end end gl_end_saving is -- Finish saving vertex values do gl_colors.wipe_out gl_vertices.wipe_out gl_normals.wipe_out end end