Jump to content
  • Advertisement

Cygon

Member
  • Content Count

    1053
  • Joined

  • Last visited

Community Reputation

1219 Excellent

About Cygon

  • Rank
    Contributor

Personal Information

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. An interesting idea!   Do you have a way to deal with a 'Dongle' that has a non-trivial copy constructor? I'd imagine that with the code above, the Foo::Impl::mem field would be copied in a memcpy() / std::copy()-like manner without invoking the copy-constructor.   The solutions I can think of would be to implement the Impl class' copy constructor & assignment operator create new Impl instances instead or to add a memoryWipe() method to my classes that drops file handles, refcounted resources, etc. without properly destroying them. Both are ugly :)
  2. Cygon

    Unreal Engine 4

    I'm on the same path :)   You can find a good overview for the different concepts (blueprints, actors, components, game modes...) of Unreal Engine 4 here: Unreal Engine: Getting Started. Once you have a rough idea of how the engine is put together, you can follow this free book: Blueprints - Master the Art of Unreal Engine 4 Blueprints   The book is very specific (less a comprehensive explanation and more a "look over my shoulder while I make something"), but if you've already got some experience with other engines or know a bit about their design, you can probably connect the dots and figure out the general workings. While learning the workflow of an experienced at the same time.
  3. Cygon

    What if game engines were cars?

    Haha, love these kinds of comparisons :)   I would have taken proprietary engines from another angle, since they're so often tailored to a very specific usage. Like, a car with a single seat only fitting a specific driver who is expected to stick his feet through a hole into the engine compartment where he can direct the front wheels and control the fuel/air mixture with his toes to accelerate or slow down. Needs a picture of a tuned old french budget car :D
  4. Cygon

    Generalized Platformer AI Pathfinding

    Splendid!   I have written a platformer navigation system myself not so long ago and ended up with the same basic data structures. What differs is that I tried to solve the jump/drop problem algorithmically.   This has turned out to be one of the biggest issues - currently I'm setting up a 4-point spline from jumpoff to landing with an army of tweaks to figure out a realistic apex point depending on jump height, distance and velocity. And then there's the issue of whether that spline should be followed with linear speed, or slowing down upwards and speed up downwards...   Simply recording the developer's inputs used to jump or drop onto another platform is quite an idea and even allows for complicated jumps requiring air control. Thanks for sharing this!   I'm curious about one thing: how does the AI in Nomera figure out which node it is on (eg. at game start or after being throw back by a weapon)? A simple search for the closest node below the character? Collision volumes above the nodes?
  5. Cygon

    Banshee Engine Architecture - Introduction

    Yeah, I'm outta this discussion.   You falsely claim I set up a strawman when my point stands, with or without your std::vector, you dishonestly quote a single sentence from a website to make it say the opposite of what it actually did, you call me an "apologist" for just asking what riled you up against exceptions so much. It seems you consider this a war, not a discourse.   This has turned too toxic for me.   -   Regarding the original topic, this looks like an interesting engine, good work!   The general architecture appears to be inspired by Ogre a bit (the RenderSystem, RenderQueue, SceneManager and so on all look very familiar, down to the method names and coding conventions), but I welcome that, since at its core, Ogre is a very nice engine that only accumulated a lot of cruft over the years :)   Maybe you could add a bit more information about the hows and whys of the engine's architecture. It would be pretty interesting and provide something to learn from, apart from just providing a nice introduction into the engine.
  6. Cygon

    Banshee Engine Architecture - Introduction

    I don't know if it makes sense to continue this discussion. You seem far too worked up / polarized on this.   - Only you need a debugger. The "this application needs to be closed..." window you get when an application crashes (or the terminal output you get on Linux for that matter) contains a crash dump. When you user, artist, whatever sends that to you, you obtain the complete callstack from it. Often the sending process is automated with an error reporting wrapper.   - If you only add that code to 10 out of 10000 lines then you have an incomplete callstack. I don't see how that would help with debugging (you first post talks about being able to get a call stack).   - If you're using a fixed array you still have overhead. And a limit.   - A mutex is the wrong choice: you'd mix callbacks between different threads. If you want to use your stack in a multi-threaded application, you need a thread-local container.   - Yes, throw means "I've encountered an error I can't handle in this scope" thus it's jumping to higher scopes until one can deal with the error. And it can't be swiped under the carpet accidentally, letting the application continue in an invalid state. And cleanup is still handled locally (see RAII which you demonstrated yourself).   - Let me quote two more sentences of that punchline: The term “zero-cost exception” is a bit of misnomer: it refers only to the runtime cost when exceptions are not being thrown. The actual overhead in throwing an exception is quite high. Zero runtime cost unless an error occurs. Sounds good to me. The article underlines my points, by the way.   You can decide for yourself that you just don't like exceptions, I don't mind. But your arguments here are flawed and strongly opinionated. I think if you manage to take the emotion out of it, you'll find that your concept may have merit for C, but is on very weak footing in C++.
  7. Cygon

    Banshee Engine Architecture - Introduction

      I don't know what turned your opinion against exceptions that much, but they are, I believe not just in my opinion, the cleanest, safest and most readable way of handling errors.   Exceptions preserve the call stack, too. Any connected debugger can be told to break when an exception is thrown, or just when an exception is left unhandled. Getting the callstack when the application crashes at the end user is possible, too.   With exceptions, you also don't have to write tons of boilerplate code pushing and popping cleanup callbacks onto stacks. And you don't have the runtime overhead of a dynamically allocated container (you seem to be using std::vector). Plus you don't have to provide a thread local global "callback stack" to any and all of your engine's systems (creating a monolithic piece of code forcing anyone into this scheme of doing things).   Exceptions are extremely efficient, too. Google "zero cost exception handling" - the days when a try..catch block resulted in a setjmp() instruction are pretty long gone. In fact, you can't create anything remotely as efficient for cleaning up without getting down and dirty with stack frames and the instruction counter.
  8. Cygon

    Singletons, You

    I strongly disagree with the contents of this article.   The author should really look at better solutions like dependency injection and IoC containers and reevaluate his understanding of the term "coupling." All the advantages that are presented are, imho, the result of a poor understanding of the issues they're supposed to be advantageous at.   Management and Memory - this is were singletons are the worst solution imaginable. There is no clearly defined shutdown path (even after shutdown, the singleton could be accessed by other objects shutting down), and if the singleton is managing objects, should you decide to need two object pools, you have to touch every single point where the singleton is accessed. Forcing a full free-threaded API on a class has serious performance implications.   Portability and Re-Use - singletons are a nightmare in this regard because they introduce the supermarket syndrome into your code. Any class, anywhere, at any time, from any thread can access whatever singleton it might need. And any singleton accessed may do the same with other singletons. Thus, extracting a class in a singleton-accepting project somewhere else, even if it looks like that class has no dependencies, may turn out to require half the original project. This is a form of dependency hiding, not dependency management.   Debugging - there isn't any substance to the claims. Of course if there's one instance of an object it's easier to debug, but that's not because of the singleton. I could do the same unsubstantiated claim in reverse, that the singleton will only make it harder because any number of threads might be accessing said singleton, forcing you to freeze all other threads or get confused when you have multiple 'current' instructions that are executing in it.   Easy Access - see supermarket syndrome above.   Couling - not a myth, but the prime reason against singletons. This paragraph reveals the author's poor understanding of dependency management. A class that accepts its dependencies through its constructor (see constructor injection), ideally in the form of interfaces, is not tightly coupled to its dependencies. Unit tests can test the class in isolation by providing it with mock implementations of its dependencies. Other projects can provide alternative implementations. Dependencies are not hidden but communicated openly through the constructor. Automatic dependency and lifetime management using IoC containers such as Ninject (.NET) or hypodermic (C++) becomes possible.   In overall, I think this is a really poorly researched article that serves to promote bad design choices with a line-up of the false advantages of this anti-pattern. The article should not pass peer review in its current state.
  9. Cygon

    Singletons, You

  10. Very nice!   Your use of the term 'delegate' is a little bit unusual (since they're not representing a method directly, but just the connection between an event and its subscriber). Maybe 'subscription' or 'forwarder' would also be good terms for this.   It would also be interesting to have a performance comparison. There's the by now well-known FastDelegate library (with limited portability) and the Impossibly Fast Delegate library which should be portable. Some community members have created signal/slot systems based on these, so it would be pretty interesting to see how this one holds up against that.   @Bearhugger: that is an interesting problem :)   I'd imagine that even having a flag in the class that is set by the destructor would still rely on the memory not having been reused by the time the running iteration gets to check it. The only safe way I can think of would be to register some local variables in an instance-wide notification list...   ...but then destruction could still happen while the event is executing the call into the subscriber. And the subscriber is likely to access the event publisher in the callback. Maybe it's best to require that subscribers don't destroy their event publishers from within the callback :P class Event { public: ~Event() { std::lock_guard<std::mutex> iterationLockScope(this->iterationLock); for(std::size_t index = 0; index < this->activeIterations.size(); ++index) { *this->activeIterations[index] = true; } } public: void Fire() { std::vector<Delegate> copiedSubscribers bool destroyed = false; // Still a race condition up to this point... :/ { std::lock_guard<std::mutex> iterationLockScope(this->iterationLock); ScopeGuard activeIterationScope = MakeGuard( this->activeIterations, std::vector<bool *>::erase, &destroyed ); copiedSubscribers.swap(std::vector<Delegate>(this->subscribers)); } for(std::size_t index = 0; index < copiedSubscribers.size(); ++index) { if(destroyed) { break; } copiedSubscribers[index](); } } private: std::vector<Delegate> subscribers; private: std::vector<bool *> activeIterations; private: std::mutex iterationLock; };
  11. Cygon

    Efficient Art Production: Theory and Practice

    @AndrewMaximov: Your advice is sound and emil is right, too: longer edges == lower performance (and, for extremely skinny triangles, even precision issues in certain algorithms)   Only the reason is slightly different. The "quads" in emil's article are blocks of 2x2 pixels by which graphics hardware steps through polygons 2-scanline-wise (allows for early rejection of entire blocks if obscured, helps align memory accesses and probably some other things). So if more screen space is touched by polygon borders, those quads have to be evaluated 2, 3 or even 4 times in the worst case.   Depending on the hardware's design, this also means a rectangle from (2, 2)-(10, 10) is usually rendered faster than one from (3, 3)-(11, 11) even though it's the same number of pixels because 19 more 2x2 pixel blocks ("quads") have to be processed.   But one can hardly optimize for such stuff, apart from maybe making edges as short as possible (which I find difficult, too, since one usually builds models from 4-sided polygons without knowing in which direction they'll be split). My own real world reason for subdividing cleanly is texturing - having extremely skinny triangles makes it hard to tweak texture coordinates since you can hardly see the difference.
  12. Cygon

    Efficient Art Production: Theory and Practice

      I do not believe this to be the case.   One important concept in hardware and software rasterizer design is "fill rules" or "rasterization rules," which include designing your rasterizer to never leave out a pixel and never draw a pixel twice along triangle edges.   This means that only the top and left facing edge pixels of a triangle are rendered. Thus, no matter how small the triangles, and no matter their topology, you'll simply never have a pixel that is drawn twice for two triangles with a shared edge.   Here are some references   http://fgiesen.wordpress.com/2011/07/06/a-trip-through-the-graphics-pipeline-2011-part-6/   http://graphics-software-engineer.blogspot.de/2012/04/rasterization-rules.html   http://msdn.microsoft.com/en-us/library/windows/desktop/cc627092%28v=vs.85%29.aspx
  13. Cygon

    What does your IDE look like?

    I'm using the built-in Visual Studio "Dark" Theme with colors from the Solarized Color Palette for syntax highlighting. The designer of that palette lists all kinds of color theory stuff that he took into account, all I know is that the colors contrast perfectly and that the brightness is very consistent.     I'm using the Lucida Console font because I find it more readable than serif fonts.   The width of the code view is set to show exactly 100 columns because I dislike horizontal scrolling, so I break my lines before that length (traditional 80x25 feels just a little bit short for modern code and 100x37 is the next larger terminal size).   EDIT: As requested by asvsfs, also providing the vssettings files: http://blog.nuclex-games.com/downloads/Solarized-VS2012.vssettings http://blog.nuclex-games.com/downloads/Solarized-VS2013.vssettings
  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!