Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

112 Neutral

About GorbGorb

  • Rank
  1. If you really have to optimize your solution, I'd suggest this approach: Organizing memory Use fixed size memory blocks of chars as nodes in your rope. This allows you to pool allocate those blocks, minimizing calls to new and malloc. When you run out of allocated blocks, allocate a bigger buffer. Don't simply memcpy your blocks to the new location but push_back each character in your new structure, filling up each block completely, starting at the beginning of the buffer (thus making the doubly linked list cache friendly again, in case you want to traverse it). Finding insert position For inserting text into the string, I assume you need to know where a line starts. I see multiple solutions for this: a) Store the number of newlines a node contains in the node (and keep that number updated). Iterate over nodes to find the right block. easy to implement low memory usage inserting newlines is O(1) finding newlines is O(n) and needs to touch a lot of memory b) Maintain a dynamic array of pointers to nodes. The pointer at index n shall point to the node containing the line with index n higher memory usage inserting newlines is O(n) finding newlines is O(1) c) Combination of a) and b). Use pointers to find approximate location of your line (for example, pointer n points to line 10 * n). most difficult to implement otherwise, same characteristics as b)
  2. You can automate this with templates (not tested, but the concept works): class message_dispatcher { private: struct abstract_listener { void* listener; void (*handle)( void* listener , const void* message ); }; template< class MessageType , class ReceivingType > static void handle_func( void* listener , const void* message ) { ReceivingType& typed_listener = *static_cast< ReceivingType* >( listener ); const MessageType& typed_message = *static_cast< const MessageType* >( message ); typed_listener.handle( typed_message ); } std::multimap< type_info , abstract_listener > listeners; public: template< class MessageType , class ReceivingType > void subscribe( ReceivingType& r ) { abstract_listener al{ &r , &handle_func< MessageType , ReceivingType > }; type_info info = typeid( MessageType ); listeners.insert( { inf , al } ); } template< class MessageType > void dispatch( const MessageType& msg ) { type_info info = typeid( MessageType ); auto range = listeners.equal_range( info ); while( range.first != range.second ) { ( *(range.first->handle_func) )( range.first->listener , &msg ); ++range.first; } } }; struct message_a {}; class specific_listener { public: void handle( message_a& m ) { } }; specific_listener listener; message_dispatcher dispatcher; dispatcher.subscribe< message_a >( listener ); dispatcher.dispatch( message_a() ); Notice, however, that you can't use a message hierarchy. If you dispatch a B : A, a handler that has subscribed for A won't get that message. If you need the performance, you can change std::multimap to something like a hash map and replace type_info with your own ids, e.g. template< class T > void* t_id() { static char c; return c; } typedef void* msg_id; msg_id id = t_id< message_a >(); //or if you need to communicate between different dlls struct message_a { static const unsigned int id = //some unique value };
  3. template<class First, class Second> class Either { public: template<class T> Either<First, Second>& operator=(Either<T, Empty> either) { first_ = std::move( either.value() ); hasFirst_ = true; return *this; } template<class T> Either<First, Second>& operator=(Either<Empty, T> either) { second_ = std::move( either.value() ); hasFirst_ = false; return *this; } bool hasFirst() const { return hasFirst_; } bool hasSecond() const { return !hasFirst_; } const First& first() const { return first_; } const Second& second() const { return second_; } private: union { First first_; Second second_; }; bool hasFirst_; }; This will eliminate unnecessary copies. Look at boost::variant, it does something similar.
  4. Hi, I'm learning gles 2 android ndk at the moment, but I can't display a texture. I expect my code to render a black texture on the screen, but all I get is some color garbage. This is my rendering routine: [source lang="cpp"] gl_context::create_context( s ); glViewport( 0 , 0 , gl_context::width() , gl_context::height() ); glClearColor( 0.0f , 0.0f , 0.0f , 0.0f ); GLuint shader_program = 0; GLuint position = 0; GLuint texture_coord = 1; GLuint sampler = 0; const char* vertex_shader_source = "attribute vec4 position; \n" "attribute vec2 a_texture_coord; \n" "varying vec2 v_texture_coord; \n" "void main() \n" "{ \n" " gl_Position = position; \n" " v_texture_coord = a_texture_coord; \n" "} \n"; const char* fragment_shader_source = "precision mediump float; \n" "uniform sampler2D sampler; \n" "varying vec2 v_texture_coord; \n" "void main() \n" "{ \n" " gl_FragColor = texture2D( sampler , v_texture_coord );" //" gl_FragColor = vec4( 1.0 , 0.0 , 0.0 , 1.0 );" //uncommenting this results in a red screen, so I guess I have a valid gles 2 context "} \n"; GLuint vertex_shader = glCreateShader( GL_VERTEX_SHADER ); glShaderSource( vertex_shader , 1 , &vertex_shader_source , 0 ); glCompileShader( vertex_shader ); GLuint fragment_shader = glCreateShader( GL_FRAGMENT_SHADER ); glShaderSource( fragment_shader , 1 , &fragment_shader_source , 0 ); glCompileShader( fragment_shader ); shader_program = glCreateProgram(); glAttachShader( shader_program , vertex_shader ); glAttachShader( shader_program , fragment_shader ); glBindAttribLocation( shader_program , position , "position" ); glBindAttribLocation( shader_program , texture_coord , "a_texture_coord" ); glLinkProgram( shader_program ); glUseProgram( shader_program ); sampler = glGetUniformLocation( shader_program , "sampler" ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D , 0 ) ; std::vector< GLubyte > buffer( 64 * 64 * 3 , 0 ); glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGB , 64 , 64 , 0 , GL_RGB , GL_UNSIGNED_BYTE , buffer.data() ); glUniform1i( sampler , 0 ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); const GLfloat vertex_positions[] = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, }; const GLfloat texture_coords[] = { 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, }; glVertexAttribPointer( position , 2 , GL_FLOAT , GL_FALSE , 0 , vertex_positions ); glEnableVertexAttribArray( position ); glVertexAttribPointer( texture_coord , 2 , GL_FLOAT , GL_FALSE , 0 , texture_coords ); glEnableVertexAttribArray( texture_coord ); glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); glDisableVertexAttribArray( position ); glDisableVertexAttribArray( texture_coord ); gl_context::swap_buffers();[/source]
  5. With some template magic and type erasure this can actually be emulated in c++, for example, I use this: prototype p = system_manager.new_prototype(); p.add_component( velocitity{ x , y , z } ); p.add_component( mass{ 200 } ); entity a = system_manager.new_entity( p ); entity b = system_manager.new_entity( p ); which doesn't look that much worse. The idea is to have references to base_system s in your system_manager. During its initialization, you create a map< typeinfo , unsigned int >, where the value type is unsigned int. When adding a component to a prototype (usually while loading a level) you lookup that system_index in the map once and store it with the component. To create an entity from a prototype you simply iterate over all components in it and do systems[ system_id ].insert( component ); Maybe I'll refactor my implementation a bit and upload it somewhere, it is, as you said, quite some work to implement a generic component system in c++.
  6. GorbGorb

    Smart pointers question

    boost::shared_ptr has the same thread-safety as a normal pointer. You're not allowed to do Thread 1:[font=courier new,courier,monospace] a = null;[/font] Thread 2:[font=courier new,courier,monospace] shared_ptr<T> b = a;[/font] [/quote] with normal pointers either.
  7. GorbGorb

    Organizing and managing code?

    Don't use new unless you need a custom data structure or for unique_ptr. Use std::make_shared and std::vector instead (you could also create std::make_unique, I'm sure it'll make it into the standard soon). A *a = new A; //use a delete a; is very like not exception safe. Better: std::unique_ptr< A > a( new A() ); //use a //std::unique_ptr deletes a You don't leak memory if you use modern c++.
  8. Thanks for the answers so far, confirmed me in my thoughts. Funny, I thought about the exact same thing right after starting this thread =) For now I will go with 1a) and an unsorted vector. I also thought about creating a lookup table from 1b) only once and using it for querying components after construction, reusing the memory for the next entity creation. Another aspect I want to improve in my design is loading and storing entity prototypes. I want to be able to load entities from files, create a prototype and spawn them later. The prototype class is implemented with type erasure, maybe a little bit like boost::any[] (not with slow built-in rtti though). The problems arise when I have to modify new entities slightly, for example setting position and velocity or changing a flag for this specific entity. Currently, I buffer all spawn requests to ensure my component data structures stay valid while iterating, so I can't just change a certain property right after spawning the entity. The solution I've come up is to pass another prototype object to the spawn function which overwrites standard components if set. This sounds rather over-engineered to me. How is that problem typically solved?
  9. Hi, I'm not sure how to implement an entity system, as described in http://t-machine.org...opment-part-1/. Especially construction, communication between components and managing entity lifetime is giving me a hard time. Here are a few alternatives I thought about: 1) Store indexes to components in the entity object a) in an std::map (or a sorted vector). Since map lookup is slow, I have to store additional references in components that need to access other components very often (for example, the physics component needs fast access to the transform component). memory overhead per component: - in map: 1 int component id , 1 int/ptr for access to specific component - in component: optional fast-access references, optional ptr to entity object b) in an array that is large enough to hold an index for each component type in my entity system. Finding a specific component of an entity is just indexing an array, but entities with few components suffer from a heavy memory overhead. In addition, I get cache misses if I access that lookup table very often. memory overhead per component: - in lookup table: 1 int component id , even for nonexistent components - in component: 1 ptr to component entity object 2) Destroy references to components after construction and keep a reference count in the entity object After construction, each component stores references to other components itself. Afterwards, the reference table or map is destroyed. When processing a component, I have to check wether the entity is still valid or deleted. memory overhead per component: - 1 ptr to reference count - references to all possibly needed components, cannot query a component past construction Currently, I tend towards 1a). I like that it's possible to add or remove components from entities during their entire lifetime, and it probably scales better if I want to add many different components. What are your thoughts?
  10. I believe there is no satisfactory solution for your problem. Your base EventListener has to either now about all message types or all specific listener types. This can be automated via variadic templates, but you'll have to recompile when adding a new listener type or message type.
  11. template<typename EVENT_DATA> virtual void onEvent(Event<EVENT_DATA>* event) { ; } [/quote] Which compiler do you use? Function templates cannot be virtual.
  12. I think std::make_shared allocates the reference count in the same memory block as the object.
  13. This is my implementation of your entity class: template< class Type > void destruct_function( void *obj_mem ) { static_cast< Type* >( obj_mem )->~Type(); } class entity { public: ~entity() { for( auto it = components.begin() ; it != components.end() ; ++it ) ( *it->first )( it->second ); } template< class Type > Type *query() { auto it = components.find( &destruct_function< Type > ); if( it != components.end() ) return static_cast< Type* >( it->second ); else return 0; } private: std::map< void (*)( void * ) , void * > components; };
  14. I use this solution: inline unsigned int new_id() { static unsigned int previous_id = 0; ++previous_id; return previous_id; } template< class Type > class id_container { public: const static unsigned int value; }; template< class Type > const unsigned int id_container< Type >::value = new_id(); template< class Type > unsigned int type_id() { return id_container< Type >::value; } Keep in mind though that this won't work across dll boundaries, and you should make the new_id() function thread safe if you want to use type_id in mutliple threads.
  15. I don't want to comment the idea of having an entity object as I don't claim to have found the Holy Grail, but I think it's unclean to use strings to identify components, especially if all component types are known at compile time. Instead, use type erasure: class entity { private: class base_entity_wrapper { public: std::type_info *id; virtual ~base_entity_wrapper() {} }; template< class Type > class entity_wrapper : public base_entity_wrapper { public: entity_wrapper( Type object ) : obj( std::move( object ) ) , id( &typeid( Type ) ) {} Type obj; }; std::vector< base_entity_wrapper* > components; //use a smart pointers instead public: template< class Type > void add_component( Type object ) { components.push_back( new entity_wrapper< Type >( std::move( object ) ) ); //currently not exception safe, use std::unique_ptr } template< class Type > Type *get() { for( auto it = components.begin() ; it != components.end() ; ++it ) { if( *(**it).id == typeid( Type ) ) return static_cast< component_wrapper< Type >* >( *it )->obj; } return 0; } }; //using: e.add_component( CA() ); e.get< CA >(); You can increase performance drastically by using a handcrafted typeid, but I'm not sure whether posting one is worth the time.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!