indexing description: "A vertex buffer objects which wraps an EM vertex array" date: "$Date$" revision: "$Revision$" deferred class EM3D_VBO_ARRAY[N -> NUMERIC, V -> EM_ABSTRACT_VECTOR[N] create default_create end ] inherit EM_ABSTRACT_VECTOR_ARRAY[N, V] rename make as make_array undefine default_create redefine make_array, put, resize end EMGL_VERTEX_BUFFER_OBJECT export {ANY} bind, unbind, is_vbo_supported {NONE} all end convert to_c_pointer: {POINTER} feature {NONE} --Initialization make( a_size, vbo_dynamic: INTEGER ) is -- Make a new VertexbufferObject Array haybrid -- vbo_dynamic: -- 0 means static (you specify it once and use it m-times) -- 1 means dynamic (you specify it n-times and use it m-times) -- 2 means stream (you specify it n-times and use it once) require valid_dynamic: vbo_dynamic>=0 and vbo_dynamic<=2 do inspect vbo_dynamic when 0 then internal_usage := em_gl_static_draw when 1 then internal_usage := em_gl_dynamic_draw when 2 then internal_usage := em_gl_stream_draw end make_array( a_size ) end make_array( n: INTEGER ) is -- Make a new VertexBufferObject Array hybrid do Precursor( n ) if is_vbo_supported then default_create create changelog.make( n ) bind data ( n*dimension*data_size, to_c_pointer, internal_usage) unbind end changed := true end feature {NONE} -- Implementation changelog: DS_ARRAYED_LIST[ INTEGER ] list_sorter: DS_SORTER[ INTEGER ] is once create {DS_QUICK_SORTER[ INTEGER ]}result.make( create {DS_COMPARABLE_COMPARATOR[ INTEGER ]}.make) end data_size: INTEGER is deferred end put_vector( v:V; i: INTEGER ) is -- Put the vector to position i in internal_map deferred end internal_usage : INTEGER internal_map: EWG_MANAGED_POINTER save_unmap is -- Unmap with a rescue require vbo_bound: is_bound do unmap rescue data( count*dimension*data_size, to_c_pointer, internal_usage) end target: INTEGER is once result := em_gl_array_buffer_arb end feature --Status frozen static: INTEGER is 0 frozen dynamic: INTEGER is 1 frozen stream: INTEGER is 2 use_map: BOOLEAN set_use_map( a_value: like use_map ) is -- Shall we use OpenGL's map/unmap(or SubCopy)? do use_map := a_value end changed: BOOLEAN feature --Commands put (v: V; i: INTEGER) is -- Put an item into the VBO array do Precursor( v, i ) changed := true if is_vbo_supported then if use_map then if internal_map=void then bind create internal_map.make_shared ( map( em_gl_write_only ), size) unbind end put_vector( v, i ) else changelog.force_last( i ) end end end update is -- Update the VBO local i: DS_ARRAYED_LIST_CURSOR[ INTEGER ] start_pos, last_pos: INTEGER do if changed and is_vbo_supported then bind if use_map then if internal_map /= void then internal_map := void save_unmap end else changelog.sort ( list_sorter ) -- Pass it segment wise to opengl -- TODO: Improve the segment finding from i := changelog.new_cursor; i.start until i.after loop from start_pos := i.item last_pos := i.item -- Adjust this value for better results until i.after or i.item-last_pos>1 loop last_pos := i.item i.forth end sub_data ( start_pos*dimension*data_size, (last_pos-start_pos+1)*dimension*data_size, to_c_pointer ) end changelog.wipe_out end unbind end changed := false end resize( new_size: INTEGER ) is -- Resize the VBO as well do Precursor( new_size ) if is_vbo_supported then bind data ( new_size*dimension*data_size, to_c_pointer, internal_usage) unbind end end feature -- File storage store_in_file( a_file: RAW_FILE ) is -- Store the VBO in a_file do a_file.put_integer ( count ) a_file.put_integer ( data_size*dimension ) a_file.put_data ( to_c_pointer, count*data_size*dimension ) end load_from_file( a_file: RAW_FILE ) is -- Load the VBO from a_file do a_file.read_integer resize( a_file.last_integer ) a_file.read_integer if data_size*dimension/=a_file.last_integer then error_handler.raise_error ( error_codes.em_error_em3d, ["data size / dimension missmatch"] ) end a_file.read_data ( to_c_pointer, count*data_size*dimension ) -- Push it into the vbo if is_vbo_supported then bind data ( count*dimension*data_size, to_c_pointer, internal_usage) unbind end end end