Geeks3D Forums
HWiNFO/32/64 v4.18
Changes in HWiNFO v4.18 - Released on: May-16-2013:
Fixed reporting of GPU Power/Current on certain CHL controllers.
Added support of CHL8203, CHL8212 and CHL8213 on GPU.
Added preliminary support ITE IT873...
TechPowerUp GPU-Z v0.7.1
GPU-Z is a lightweight utility designed to give you all information about your video card and GPU.
Version History
0.7.1
Added support for NVIDIA GeForce GTX 770...
Molecular Musings
molecularmusings
As promised in the last blog post, today we are going to take a look at how Molecule handles internal references to data owned by some other system in the engine.
First, a quick recap of reasons why we don’t want to use pointers for referencing data is in order:
- With raw pointers, ownership is sometimes unclear. If I’m handed a pointer, do I need to delete the instance? Who owns it? How long can I hold on to it?
This very quickly leads to double-deletes and/or dangling pointers. Both are kinds of bugs which can be hard to find if you’re unlucky. - The above can be somewhat alleviated by using a shared_ptr<> or some reference-counting mechanism, but now we have added additional overhead which isn’t really necessary. Ownership is still unclear – when is the data behind the reference-counted pointer actually freed? Who else holds on to it?
- How are pointers replicated or copied, e.g. across the network? You always have to have some kind of serialization mechanism in place because you cannot just send pointers across the network – the address they contain won’t make sense in a different address space.
- Pointers don’t support relocation. Ultimately, the system who owns the data should also be responsible for managing the data’s memory. Therefore, a system might want to move things around in memory, e.g. for run-time defragmentation. Notifying each and every instance that might hold a pointer to system-internal data is tedious and error-prone.
So, let us now take a closer look at how we can store internal references without running into the above-mentioned problems.
Handles
In the Molecule Engine, handles are used to refer to internal data. That is, they refer to data owned by some system directly, and not via some indirection. This is also the reason why they are called internal references.
What are handles? Basically, they are indices into the data, but with a twist. One can think of handles as „smart indices“. But before going into detail about handles, which problems do plain indices already solve?
- You cannot accidentally call delete or free() on an index. Furthermore, if a system only deals with indices as input and output parameters, it should be clear that the system also owns the data.
- Indices can be easily replicated and copied. They also support data relocation out-of-the-box: if we want to access the data at e.g. index 3, it doesn’t matter where the data itself resides, as long as it remains in the same order. It can reside at address 0xA000 or 0xB000 or someplace else – data[3] will give us the data we want.
Of course, there are things which are not supported by plain indices:
- We cannot detect access to stale/deleted data. We might try to access the data at index 3, but that might have been freed already since our last access.
- Whole data blocks can be moved around in memory, but the order of individual data items cannot be changed, because that would mess up our indices.
Handles help us with the first problem, but also don’t support arbitrary relocation of individual data items. This is what IDs or external references are for, but those will be the topic of the next post.
The question remains: how do we turn indices into handles that can detect access to already deleted data?
The idea is quite simple: instead of only using an index, a handle also stores the generation in which the index was created. The generation is simply a monotonically increasing counter that gets incremented each time a data item is deleted. The generation is stored both inside the handle, and for each data item. Whenever we want to access data using a handle, the index’ generation and the data item’s generation need to match.
An example
Going back to our example from the last post, let us assume our render backend provides space for 4k vertex buffers. New vertex buffers are allocated using a pool-allocator/free-list internally, and users only deal with a VertexBufferHandle.
Initially, our pool of vertex buffers is empty, and all generations are set to zero.
4096 Vertex buffers: +----+----+----+----+----+----+ | VB | VB | VB | .. | VB | VB | +----+----+----+----+----+----+ 4096 Generations: +----+----+----+----+----+----+ | 0 | 0 | 0 | .. | 0 | 0 | +----+----+----+----+----+----+
The first time we allocate a vertex buffer, the handle will contain an index of 0, and a generation of 0. Future vertex buffer handles will have a different index, and also a generation of 0.
Assume we now destroy the first vertex buffer we allocated. The generation of the slot that contained it will increment, yielding the following layout:
+----+----+----+----+----+----+ | VB | VB | VB | .. | VB | VB | +----+----+----+----+----+----+ +----+----+----+----+----+----+ | 1 | 0 | 0 | .. | 0 | 0 | +----+----+----+----+----+----+
If we now want to access that vertex buffer using the handle, we check its generation against the one stored with our vertex buffer, and find that they don’t match – meaning that we tried to access already deleted data.
In code, this situation looks somewhat like the following:
VertexBufferHandle handle = backend::CreateVertexBuffer(...); // some more vertex buffers created in the meantime // at a later point in time, we destroy the vertex buffer... backend::DestroyVertexBuffer(handle); // ...but somebody, somewhere, still holds the same handle backend::AccessVertexBuffer(handle);
Handle implementations
One thing we haven’t talked about yet is how handles can be implemented. As almost always, the simplest solutions are the best, so a trivial struct will suffice in this case:
struct Handle
{
uint32_t index;
uint32_t generation;
};
In practice, you normally would not use two 32-bit integers for both the index and the generation, but rather use bitfields instead. In the case of our vertex buffer handles, we need 12 bits for storing indices in the range [0, 4095], which leaves 20 bits for the generation if we want our handles to be 32-bit integers. Hence, our handles would look more like the following:
struct Handle
{
uint32_t index : 12;
uint32_t generation : 20;
};
This means that the generation overflows after 1048576 vertex buffers have been deleted in the same slot in our pool. Theoretically, this means that we could wrongly access a vertex buffer via an old handle that was generated more than 1048576 vertex buffer create/delete cycles ago, in that very slot. In practice this should never happen, unless we store an old handle for ages, create/delete buffers like crazy, and never access the buffer using that handle in the meantime.
Yet, depending on the number of bits you are willing to spend this can happen, so it is something to keep in mind.
Last but not least, another nice thing about handles that I mentioned in the previous blog post is that they use less memory than a pointer. Most handles can store their index and generation in a single 32-bit integer, which means they need half the amount of memory compared to 64-bit pointers. Additionally, we really only need to store the generation inside a handle for detecting access to stale data. We should not need that in a retail build, hence handles can be as small as 16-bit integers in those builds, if your indices only need to be in the range [0, 65535].
A generic implementation
In Molecule, I use a generic handle implementation which defines the underlying data types according to certain build rules, and also static_asserts whether the bits fit into that type. The basic struct is as follows:
template <size_t N1, size_t N2>
struct GenericHandle
{
// uint16_t or uint32_t, depending on build type, realized using preprocessor-#ifs
uint32_t index : N1;
uint32_t generation : N2;
};
All handle types then become simple typedefs, e.g.:
typedef GenericHandle<12, 20> VertexBufferHandle;
And that concludes today’s post! In the next part in the series, we will discuss how external references also allow for moving individual data items around in memory, without user code having to care about that.
Filed under: C++, Graphics
cbloom rants
05-17-13 - Cloth Diapering
Oh yes indeed, you are in for a spate of baby-related blogging.
I'm pretty sure clother diapers are bullshit. I'm about to cancel my diaper service. In this first week I've been using a semi-alternating mix of cloth and disposable. I assumed that I would start out with disposables just for ease in the first few days and then switch to cloth because it's "better", but I don't think I will.
(I make all my decisions now based only on 1. personal observations and 2. serious scientific studies where I can read the original papers. I try to avoid and discount 3. journalism 4. hearsay 5. the internet 6. mass-market nonfiction. I think they are garbage and mental poison.)
What I'm seeing is :
Disposable diapers actually work the way they claim to. The seal around the borders is good. The entire diaper itself has a nice low profile so is not too bulky or uncomfortable. But most importantly, they actually do trap and absorb moisture. When baby has a heavy pee in a disposable diaper, the moisture stays right in one little spot and doesn't spread all over. When I remove the diaper I can feel her skin all over the nether regions is pretty dry.
Cloth diapers don't. The worst aspect is that when baby has a heavy pee, the cloth soaks it up, and because it's cloth and wicks moisture, the pee is spread all over her entire lower parts. When I get the diaper off, she's soaking wet all over. (and yes of course I'm changing her almost instantly after peeing because at this point we're watching her constantly). That alone is enough to turn me off cloth diapers, but there's lots more that sucks about them. It's really hard to get the diaper cover on such that it actually makes a water-tight seal, so leakage is much more likely (and if you do try to make it water tight, it's easy to make it too tight and cut off circulation, which I accidentally did once). The cloth diaper alone looks pretty comfortable on her, but the diaper cover is much rougher and more bulky than a dispoable; the result is that she has this huge awkward thing on.
When you add the inconvenience of cloth diapers (longer changing times, having to store poop in your house, taking the pail in and out for pickup), it just seems like a massive lose.
The only possible argument pro-cloth that makes sense to me is the reduction of the landfill load. Now, environmental arguments are always complicated; there are arguments for the other side based on the environmental cost of washing (though I think they're bogus). But even assuming that the environmental case is clear, being a hypocritical liberal I wouldn't actually inconvenience myself and discomfort my baby for the benefit of the landfill.
Eh, actually I take back that false self-accusation. That's a retarded Fox News style "gotcha" that's based on misrepresentation and not understanding. I've never advocated the standard liberal martyrdom (and if I once did, I certainly don't now). I don't believe in choosing to undermine yourself because you believe the world would be better if everyone did it. I believe in changing the laws such that they encourage you to make the choice that is better for the world. eg. people who don't drive because they believe it's evil, even if it would be much to their benefit, are just being dumb martyrs. The US government massively subsidizes driving, so if you don't take advantage of that you are essentially paying for other people to drive. I would love it if the government would subsidize *not driving* rather than the other way around, but until they do I'm driving up a storm. (tangent : the massive subsidize for Teslas is a great example of the way that Dems and Reps are in fact both really working for the same cause : creating loop holes and kick backs so that they can give money to rich people).
I'm a big tangent wanderer. My political philosophy in a nutshell :
Government's role is to create a market structure (through laws, regulation, the Fed, direct market action, etc) such that when each actor maximimizes their own personal utility, the net result is as good for the entire world (nation) as possible.
(if you're out of high school (or the 18th century) you should know that a free market does not do that on its own)
(And crucially, "good for" must be defined on something like a sum-of-logs scale, or perhaps just maximize the median, or minimize the number in poverty; if you maximize the sum (basically GDP) then giving huge profits to Larry Ellison and fucking everyone else looks like it's "good for the world")
And, uh, oh yeah, cloth diapers suck.
05-08-13 - A Lock Free Weak Reference Table
It's very easy (almost trivial (*)) to make the table-based {index/guid} style of weak reference lock free.
(* = obviously not trivial if you're trying to minimize the memory ordering constraints, as evidenced by the revisions to this post that were required; it is trivial if you just make everything seq_cst)
Previous writings on this topic :
Smart & Weak Pointers - valuable tools for games - 03-27-04
cbloom rants 03-22-08 - 6
cbloom rants 07-05-10 - Counterpoint 2
cbloom rants 08-01-11 - A game threading model
cbloom rants 03-05-12 - Oodle Handle Table
The primary ops conceptually are :
Add object to table; gives it a WeakRef id
WeakRef -> OwningRef (might be null)
OwningRef -> naked pointer
OwningRef construct/destruct = ref count inc/dec
The full code is in here : cbliblf.zip , but you can get a
taste for how it works from the ref count maintenance code :
// IncRef looks up the weak reference; returns null if lost
// (this is the only way to resolve a weak reference)
Referable * IncRef( handle_type h )
{
handle_type index = handle_get_index(h);
LF_OS_ASSERT( index >= 0 && index c_num_slots );
Slot * s = &s_slots[index];
handle_type guid = handle_get_guid(h);
// this is just an atomic inc of state
// but checking guid each time to check that we haven't lost this slot
handle_type state = s->m_state.load(mo_acquire);
for(;;)
{
if ( state_get_guid(state) != guid )
return NULL;
// assert refcount isn't hitting max
LF_OS_ASSERT( state_get_refcount(state) state_max_refcount );
handle_type incstate = state+1;
if ( s->m_state.compare_exchange_weak(state,incstate,mo_acq_rel,mo_acquire) )
{
// did the ref inc
return s->m_ptr;
}
// state was reloaded, loop
}
}
// IncRefRelaxed can be used when you know a ref is held
// so there's no chance of the object being gone
void IncRefRelaxed( handle_type h )
{
handle_type index = handle_get_index(h);
LF_OS_ASSERT( index >= 0 && index c_num_slots );
Slot * s = &s_slots[index];
handle_type state_prev = s->m_state.fetch_add(1,mo_relaxed);
state_prev;
// make sure we were used correctly :
LF_OS_ASSERT( handle_get_guid(h) == state_get_guid(state_prev) );
LF_OS_ASSERT( state_get_refcount(state_prev) >= 0 );
LF_OS_ASSERT( state_get_refcount(state_prev) state_max_refcount );
}
// DecRef
void DecRef( handle_type h )
{
handle_type index = handle_get_index(h);
LF_OS_ASSERT( index >= 0 && index c_num_slots );
Slot * s = &s_slots[index];
// no need to check guid because I must own a ref
handle_type state_prev = s->m_state.fetch_add((handle_type)-1,mo_release);
LF_OS_ASSERT( handle_get_guid(h) == state_get_guid(state_prev) );
LF_OS_ASSERT( state_get_refcount(state_prev) >= 1 );
if ( state_get_refcount(state_prev) == 1 )
{
// I took refcount to 0
// slot is not actually freed yet; someone else could IncRef right now
// the slot becomes inaccessible to weak refs when I inc guid :
// try to inc guid with refcount at 0 :
handle_type old_guid = handle_get_guid(h);
handle_type old_state = make_state(old_guid,0); // == state_prev-1
handle_type new_state = make_state(old_guid+1,0); // == new_state + (1
handle_guid_shift);
if ( s->m_state($).compare_exchange_strong(old_state,new_state,mo_acq_rel,mo_relaxed) )
{
// I released the slot
// cmpx provides the acquire barrier for the free :
FreeSlot(s);
return;
}
// somebody else mucked with me
}
}
The maintenance of ref counts only requires relaxed atomic increment & release atomic decrement (except when the pointed-at object is
initially made and finally destroyed, then some more work is required). Even just the relaxed atomic incs
could get expensive if you did a ton of them, but my philosophy for how to use this kind of system is that you inc & dec refs
as rarely as possible. The key thing is that you don't write functions that take owning refs as arguments, like :
void bad_function( OwningRefT
hence doing lots of inc & decs on refs all over the code. Instead you write all your
code with naked pointers, and only use the smart pointers where they are needed to ensure ownership for the lifetime
of usage. eg. :
Thingy> sptr )
{
more_bad_funcs(sptr);
}
void Stuff::bad_caller()
{
OwningRefTthingy> sptr( m_weakRef );
if ( sptr != NULL )
{
bad_function(sptr);
}
}
void good_function( Thing * ptr )
{
more_good_funcs(ptr);
}
void Stuff::bad_caller()
{
OwningRefT
thingy> sptr( m_weakRef );
Thingy * ptr = sptr.GetPtr();
if ( ptr != NULL )
{
good_function(ptr);
}
}
If you like formal rules, they're something like this :
1. All stored variables are either OwningRef or WeakRef , depending on whether it's
an "I own this" or "I see this" relationship. Never store a naked pointer.
2. All variables in function call args are naked pointers, as are variables on the
stack and temp work variables, when possible.
3. WeakRef to pointer resolution is only provided as WeakRef -> OwningRef. Naked pointers
are only retrieved from OwningRefs.
And obviously there are lots of enchancements to the system that are possible. A major one that I recommend is to put more information in the reference table state word. If you use a 32-bit weak reference handle, and a 64-bit state word, then you have 32-bits of extra space that you can check for free with the weak reference resolution. You could put some mutex bits in there (or an rwlock) so that the state contains the lock for the object, but I'm not sure that is a big win (the only advantage of having the lock built into the state is that you could atomically get a lock and inc refcount in a single op). A better usage is to put some object information in there that can be retrieved without chasing the pointer and inc'ing the ref and so on.
For example in Oodle I store the status of the object in the state table. (Oodle status is a progression through Invalid->Pending->Done/Error). That way I can take a weak ref and query status in one atomic load. I also store some lock bits, and you aren't allowed to get back naked pointers unless you have a lock on them.
The code for the weak ref table is now in the cbliblf.zip that I made for the last post. Download : cbliblf.zip
( The old cblib has a non-LF weak reference table that's similar for comparison. It's also more developed with helpers and fancier templates and such that could be ported to this version. Download : cblib.zip )
ADDENDUM : alternative DecRef that uses CAS instead of atomic decrement. Removes the two-atomic free path.
Platforms that implement atomic add as a CAS loop should probably just use this form. Platforms that have
true atomic add should use the previously posted version.
// DecRef
void DecRef( handle_type h )
{
handle_type index = handle_get_index(h);
LF_OS_ASSERT( index >= 0 && index c_num_slots );
Slot * s = &s_slots[index];
// no need to check guid because I must own a ref
handle_type state_prev = s->m_state($).load(mo_relaxed);
handle_type old_guid = handle_get_guid(h);
for(;;)
{
// I haven't done my dec yet, guid must still match :
LF_OS_ASSERT( state_get_guid(state_prev) == old_guid );
// check current refcount :
handle_type state_prev_rc = state_get_refcount(state_prev);
LF_OS_ASSERT( state_prev_rc >= 1 );
if ( state_prev_rc == 1 )
{
// I'm taking refcount to 0
// also inc guid, which releases the slot :
handle_type new_state = make_state(old_guid+1,0);
if ( s->m_state($).compare_exchange_weak(state_prev,new_state,mo_acq_rel,mo_relaxed) )
{
// I released the slot
// cmpx provides the acquire barrier for the free :
FreeSlot(s);
return;
}
}
else
{
// this is just a decrement
// but have to do it as a CAS to ensure state_prev_rc doesn't change on us
handle_type new_state = state_prev-1;
LF_OS_ASSERT( new_state == make_state(old_guid, state_prev_rc-1) );
if ( s->m_state($).compare_exchange_weak(state_prev,new_state,mo_release,mo_relaxed) )
{
// I dec'ed a ref
return;
}
}
}
}
05-15-13 - Baby
I suppose this is the easiest way to announce to various friends and semi-friends rather than trying to mass-email. I have a new baby, yay! No pictures, you paparazzos. She's adorable and healthy. I love how simple and direct her communication is. Suckling lips = needs to nurse. Squirming = needs a diaper change. Fussing = cold or gassy. Everything else = needs to sleep. I wish all humans communicated so clearly.
I want to write about the wonderful experience of having a home birth (see *2), but don't want to intrude on Tasha's privacy. Suffice it to say it was really good, so good to be home and have everything at hand to make Tasha comfortable, and then be able to take baby in our arms and settle into bed right away. We spent the first 36 hours after birth all in bed together and I think that time was really important.
I've always wanted to have kids, but I'm (mostly) glad that I waited this long. For one thing Tasha is a wonderful mom and I'm glad I found her. But also, I realize now that I wasn't ready in my twenties. I've changed a lot in the last five years and I'm a much better person now. I've learned important lessons that are helping me a lot in this challenging time, like to do hard work correctly you have to not only complete the task but also keep a good attitude and be nice to the people around you while you do it. And that when you are tired and hungry is when you can really show your character; anyone can have a good attitude when they're fresh, but if you get nasty when the going gets tough then you are nasty. etc. standard cbloom slowly figures out things that most people learned in their teens.
Now for some old-style ranting.
1. "We had a baby". No you fucking did not. Your wife had a baby. If you were a really good husband, you held her hand and got her snacks. She squeezed a watermelon out of her vagina. You do not get to take any credit for that act, it was all her. It's a bit like Steve Jobs saying "we invented" anything; no you did not you fucking credit-stealing douchebag, your company didn't even invent it, much less you.
(tangent : I can't stand the political correctness in sport post-game interviews these days; they're all so sanitized and formulaic. They must go to interview coaching classes or something because everyone says exactly the same things. Of course it's not the athlete's fault, they would love to have emotional honest outbursts, it's the god damn stupid public who throw a coniption if anybody says anything remotely true. In particular this post reminds me of how athletes always immediately go "it wasn't just me, it was the team"; no it was not, Kobe, you just had an 80 point game, it was all fucking you, don't give me this bullshit credit to the team stuff. Be a man and say "*I* won this game".)
2. People are busy-body dicks. When we would tell acquaintances about our plans to have a home birth, a good 25% would feel like they had to tell us what a bad idea that was and nag us about the dangers of childbirth. Shut the fuck up you stupid asshole. First of all, don't you think that maybe we've researched that more than you before making our decision, so you don't know WTF you're talking about? Second of all, we're not going to change our mind because of your nagging, so all you're doing is being nasty about something you're not going to change. We didn't ask for your opinion, you can just stay the hell out of it. (The doctors that we would occasionally see for tests were often negative and naggy as well, which only made us more confident in our choice).
It's a bit like if a friend tells you they're marrying someone and you go "her?". Even if the marriage is a questionable choice, they're not going to stop it due to your misgivings, so all you're doing is adding some unpleasantness to their experience.
You always run into these idiots when you do software reviews or brainstorming sessions. You'll call a meeting to discuss revisions to the boss fight sequence, and some asshole will always chime in with "I really think the whole idea of boss fights sucks and we should start over". Umm, great, thanks, very helpful. We're not going to tear up the whole design of the game a few months from shipping, so maybe you could stick to the topic at hand and get some kind of clue about what things are reasonable to change and which need to be taken as a given and worked within as constraints.
Like when I'd ask for reviews of Oodle, a few of the respondents would give me something awesomely unhelpful like
"I don't like the entire style of the API, and I'd throw it out and do a new one" , or "actually I think a paging +
data compression library is a bad idea and I'd just start over on something else". Great, thanks; I might agree
with you but obviously you must know that that is not going to happen and it's not what I was asking for, so if
you don't want to say anything helpful then just say "no".
iPhone Development Tutorials and Programming Tips
Open Source Control Allowing You To Easily Create An E-Mail Recipient Library Like The Mail App
About a year ago I mentioned a useful library allowing you to send e-mail via the SMTP and IMAP protocols that automatically handles any message encoding.
Here’s a control allowing you to create a recipient bar styled similar to that found within the Mail App called TURecipientBar from David Beck.
TURecipientBar uses auto layout to keep everything aligned properly, a removable add button, a customizable look and more.
Here’s an image of TURecipientBar in action:
You can find TURecipientBar on Github here.
A nice control for any app involving e-mail entry.
- Open Source Component For Easily Adding A Newsletter Opt-In Form Into Your Apps
- Open Source iOS Library For Working With The iMap And SMTP E-mail Protocols
- Tutorial: How To Create An iPad Split View With A Sliding Master Controller Like The Mail App
- Best Resources In iOS Development – July 16th, 2012
- Open Source iOS Control For Presenting Information In The Toolbar Space
Original article: Open Source Control Allowing You To Easily Create An E-Mail Recipient Library Like The Mail App
©2013 iOS App Dev Libraries, Controls, Tutorials, Examples and Tools. All Rights Reserved.
Gamasutra Feature Articles
Killer & Dragons: The GungHo and Grasshopper Interview
GungHo's Morishita and Grasshopper's "SUDA51" speak to Gamasutra. ...
c0de517e Rendering et alter
I'll create a new trend...
I've seen it in the CouchDB guide, where the citation is attributed to Joe Stump. Premature generalization is the root of all evil...
![]() |
| Scaling is Specialization. |
OpenGL
GLSL Hacker 0.5.0 With Python Support
GLSL Hacker is a cross-platform utility (Windows, Linux and Mac OS X) for coding 3D demos and prototypes with GLSL, Lua and Python programming languages. GLSL Hacker 0.5.0 adds the support of Python 2.7, improves compute shaders support and fixes many bugs.
NVIDIA launches Nsight Visual Studio Edition 3.0 with OpenGL debugging support
The NVIDIA Developer Tools team is proud to announce the final release of NVIDIA® Nsight Development Platform, Visual Studio Edition 3.0, an application development platform for heterogeneous systems. This new release officially supports OpenGL frame debugging and profiling, GLSL GPU shader debugging, local single GPU shader debugging, the new Kepler GK110 architecture found in Tesla K20 & GeForce GTX TITAN, and CUDA 5.0. This release requires NVIDIA Display Driver Release 319 or newer.
iPhone Development Tutorials and Programming Tips
iOS Library For Creating Great Looking Customizable Flat User Interface Elements
Flat user interface design is extremely popular because of the excellent minimalist look.
Here’s a library from Grouper called FlatUIKit that allows you to easily create flat user interface elements for your switches, sliders, steppers, nav bar, alert view and buttons.
You can also customize the colors of each element, and depending on the element you can also customize the corner radius, shadowing, text, and more.
Here are some images from the readme showing the various flat user interface elements:
You can find FlatUIKit on Github here.
An awesome library for creating flat user interface elements.
- iOS Library That Runs A Specific Code Block Only When User Upgrades An App
- Tools And Library For Making It Easier To Localize Elements Created With Interface Builder
- Building Your iPhone App’s Interface Quickly
- iOS Control For Creating A Great Looking Rounded Navigation Menu Complete With Animations
- Finishing With Interface Builder – Building Your iPhone Apps Interface Quickly 2/2
Original article: iOS Library For Creating Great Looking Customizable Flat User Interface Elements
©2013 iOS App Dev Libraries, Controls, Tutorials, Examples and Tools. All Rights Reserved.
Gamasutra Feature Articles
Sponsored: The World of Just Cause 2 - Using Creative Technology to Build Huge Open Landscapes
A deep dive into open world technology. ...
Game From Scratch
A first look at Google’s new IDE Android Studio
So, it is now available for download, although the version is 0.1, so expect some warts! Oh, the “it” in question is Google’s new IDE for Android development based on IntelliJ by Jetbrains, a developer I am a huge fan of.
Now I am going to take a tour of the IDE.
Welcome screen:
New Project Screen
New Project Part 2
New Project Part 3
New Project Part 4
Code Editing Window / Code tips
Error Dialog
Debug device chooser
Debug Window
GUI Editing
Screen size options:
Theme selector
Multiple Device preview
I experienced no crashes, everything was very intuitive and quick, other than initial loading. I’m initially quite impressed. IF you are wondering, this IDE *ONLY* works for Android projects.
c0de517e Rendering et alter
Peek'n'Poke
Enjoy!
P.S. If you extend/fix/find anything incredibly dumb in the code below, leave a comment! Thanks...
- It would be really cool to make a small (maybe embedded, scripts written in C# itself) DSL out of this, letting you connect to processes-data sources, fetching pointers and buffers of data from them, having a few format converters and then pushing the results into visualizers and so on... Could be a weekend project. We'll see if I'll ever have the time (no!)
- Did you know that you can hook d3d (or any other native API) from C3? http://spazzarama.com/2011/03/14/c-screen-capture-and-overlays-for-direct3d-9-10-and-11-using-api-hooks/
- In theory, you could programmatically set a data breakpoint (just change the debug register of a thread) but I'm not sure if or how you could then attach a handler for the exception it would raise, from an outside process (our debugger)
- Intel's PinTool is very cool, it allows dynamic instrumentation of code http://pintool.org/
- There is quite a research community around these concepts as well, e.g. http://people.cs.pitt.edu/~naveen/papers/wbia05.pdf http://www.amazon.ca/Software-Visualization-Visualizing-Structure-Behaviour/dp/3540465049 http://www.st.uni-trier.de/~diehl/softvis/org/index.php http://softvis.wordpress.com/
- Certain tools made for reversing/injection purposes, e.g. this look interesting... An area to explore...
using System; namespace Peek { class Program { #region Kernel Imports // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx const uint ACL_DELETE = 0x00010000; const uint ACL_READ_CONTROL = 0x00020000; const uint ACL_WRITE_DAC = 0x00040000; const uint ACL_WRITE_OWNER = 0x00080000; const uint ACL_SYNCHRONIZE = 0x00100000; const uint ACL_END = 0xFFF; //if you have Windows XP or Windows Server 2003 you must change this to 0xFFFF const uint PROCESS_VM_READ = 0x0010; const uint PROCESS_VM_WRITE = 0x0020; const uint PROCESS_VM_OPERATION = 0x0008; const uint PROCESS_ALL_ACCESS = (ACL_DELETE | ACL_READ_CONTROL | ACL_WRITE_DAC | ACL_WRITE_OWNER | ACL_SYNCHRONIZE | ACL_END); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern uint OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool ReadProcessMemory(uint hProcess, UIntPtr lpBaseAddress, byte[] buffer, uint size, uint lpNumberOfBytesRead); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool ReadProcessMemory(uint hProcess, UIntPtr lpBaseAddress, IntPtr buffer, uint size, uint lpNumberOfBytesRead); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool WriteProcessMemory(uint hProcess, UIntPtr lpBaseAddress, byte[] buffer, uint size, uint lpNumberOfBytesWritten); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool WriteProcessMemory(uint hProcess, UIntPtr lpBaseAddress, IntPtr buffer, uint size, uint lpNumberOfBytesWritten); static byte[] ReadMemory(UIntPtr address, uint size, uint processHandle) { byte[] buffer = new byte[size]; ReadProcessMemory(processHandle, address, buffer, size, 0); return buffer; } class UnmanagedMemWrapper // should we GC.AddMemoryPressure? { public UnmanagedMemWrapper(uint size) { this.ptr = System.Runtime.InteropServices.Marshal.AllocHGlobal((int)size); } ~UnmanagedMemWrapper() { System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr); } public IntPtr ptr; } #endregion // Kernel Imports // Utility, half2float, could use DirectXMath DirectX::PackedVector functions instead... [System.Runtime.InteropServices.DllImport("d3dx9_35.dll")] public static extern void D3DXFloat16To32Array(float[] output, IntPtr input, uint nfloats); static void PrintUsageAndErrors(string error) { System.Console.WriteLine("Peek"); System.Console.WriteLine("----"); System.Console.WriteLine(); System.Console.WriteLine("Arguments: process name, instance number, pointer address, [peek mode]"); System.Console.WriteLine("Note that multiple processes can have the same name..."); System.Console.WriteLine(); System.Console.WriteLine("Peek mode:"); System.Console.WriteLine(" img [format] xsize ysize -- draws a 2d image"); System.Console.WriteLine(" Supported formats: argb8 argb16 rgb8 rgb16 r8 r16 argb32f argb16f rgb32f rgb16f r32f r16f"); System.Console.WriteLine(); if(error.Length!=0) { System.Console.WriteLine("Error!"); System.Console.WriteLine(error); } } [STAThread] static void Main(string[] args) { if (args.Length < 7) { PrintUsageAndErrors("Not enough arguments"); return; } var procs = System.Diagnostics.Process.GetProcessesByName(args[0]); UInt32 procNumber = 0; if (!UInt32.TryParse(args[1], out procNumber)) { PrintUsageAndErrors("Can't parse process number"); return; } if (procs.Length <= procNumber) { PrintUsageAndErrors("Process instance not found"); return; } var proc = procs[procNumber]; uint procHandle = OpenProcess(PROCESS_VM_READ, false, proc.Id); if (procHandle == 0) { PrintUsageAndErrors("Failed to open process"); return; } switch (args[3]) { case "img": { UInt32 xsize, ysize; if ((!UInt32.TryParse(args[5], out xsize)) || (!UInt32.TryParse(args[6], out ysize))) { PrintUsageAndErrors("Can't parse img size"); return; } switch (args[4]) { case "argb8": PeekImg(procHandle, args[2], xsize, ysize, 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ImgOP.NONE); break; case "rgb8": PeekImg(procHandle, args[2], xsize, ysize, 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, ImgOP.NONE); break; case "argb16": PeekImg(procHandle, args[2], xsize, ysize, 8, System.Drawing.Imaging.PixelFormat.Format64bppArgb, ImgOP.NONE); break; case "rgb16": PeekImg(procHandle, args[2], xsize, ysize, 6, System.Drawing.Imaging.PixelFormat.Format48bppRgb, ImgOP.NONE); break; case "r8": PeekImg(procHandle, args[2], xsize, ysize, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, ImgOP.NONE); break; case "r16": PeekImg(procHandle, args[2], xsize, ysize, 2, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale, ImgOP.NONE); break; case "argb32f": PeekImg(procHandle, args[2], xsize, ysize, 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ImgOP.F32_TO_I8); break; case "rgb32f": PeekImg(procHandle, args[2], xsize, ysize, 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, ImgOP.F32_TO_I8); break; case "argb16f": PeekImg(procHandle, args[2], xsize, ysize, 4, System.Drawing.Imaging.PixelFormat.Format32bppArgb, ImgOP.F16_TO_I8); break; case "rgb16f": PeekImg(procHandle, args[2], xsize, ysize, 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, ImgOP.F16_TO_I8); break; case "r32f": PeekImg(procHandle, args[2], xsize, ysize, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, ImgOP.F32_TO_I8); break; case "r16f": PeekImg(procHandle, args[2], xsize, ysize, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, ImgOP.F16_TO_I8); break; default: PrintUsageAndErrors("Unknown image format"); return; } break; } default: PrintUsageAndErrors("Unknown peek options"); return; } } class DBForm : System.Windows.Forms.Form { public DBForm() { DoubleBuffered = true; } } enum ImgOP { NONE, F16_TO_I8, F32_TO_I8 } static void PeekImg( uint procHandle, string ptrString, UInt32 xsize, UInt32 ysize, UInt32 bytesPP, System.Drawing.Imaging.PixelFormat format, ImgOP imgOp = ImgOP.NONE ) { uint imageSize = 0; uint readSize = 0; float[] tempHalfToFloatMemory = null; UnmanagedMemWrapper unmanagedMemory = null; UIntPtr pointer = new UIntPtr(0); using (var form = new DBForm() { Text = "Peeker" }) { form.SetBounds(0, 0, xsize > 400 ? (int)xsize : 400, (int)ysize + 100); // Meh, there was no reason to do all this by hand really, also, I could have added everything to the DBForm class... var timer = new System.Windows.Forms.Timer() { Interval = 33, Enabled = true }; var background = new System.Drawing.Drawing2D.HatchBrush( System.Drawing.Drawing2D.HatchStyle.LargeCheckerBoard, System.Drawing.Color.Black, System.Drawing.Color.White); System.Drawing.Bitmap bitmap = null; var noAlphaButton = new System.Windows.Forms.CheckBox() { Text = "NoAlpha", Left = 0, Width = 70 }; var endianSwapButton = new System.Windows.Forms.CheckBox() { Text = "Endian", Left = 70, Width = 70 }; var RBSwapButton = new System.Windows.Forms.CheckBox() { Text = "RB Swap", Left = 140, Width = 70 }; var memControl = new System.Windows.Forms.TextBox() { Text = ptrString, Left = 210, Width = 210 }; var xresControl = new System.Windows.Forms.NumericUpDown() { Minimum = 0, Maximum = 9999, Value = xsize, Top = 25, Left = 0, Width = 105 }; var yresControl = new System.Windows.Forms.NumericUpDown() { Minimum = 0, Maximum = 9999, Value = ysize, Top = 25, Left = 105, Width = 105 }; var resetButton = new System.Windows.Forms.Button() { Text = "Reinit", Top = 25, Left = 260 }; form.Controls.Add(memControl); form.Controls.Add(noAlphaButton); form.Controls.Add(endianSwapButton); form.Controls.Add(RBSwapButton); form.Controls.Add(xresControl); form.Controls.Add(yresControl); form.Controls.Add(resetButton); if (format != System.Drawing.Imaging.PixelFormat.Format32bppArgb) { // For now these conversions are coded only for argb8 and formats that decode into argb8 noAlphaButton.Enabled = false; endianSwapButton.Enabled = false; RBSwapButton.Enabled = false; } resetButton.Click += delegate(object sender, System.EventArgs e) { // This is and ugly hack just because the delegate/event system in C# is a bit restrictive... InitBuffers(bytesPP, format, imgOp, ref imageSize, ref readSize, ref tempHalfToFloatMemory, ref unmanagedMemory, ref bitmap, ref pointer, ref memControl, xresControl, yresControl); }; InitBuffers(bytesPP, format, imgOp, ref imageSize, ref readSize, ref tempHalfToFloatMemory, ref unmanagedMemory, ref bitmap, ref pointer, ref memControl, xresControl, yresControl); form.Paint += delegate(object sender, System.Windows.Forms.PaintEventArgs e) { if (unmanagedMemory == null) return; ReadProcessMemory(procHandle, pointer, unmanagedMemory.ptr, readSize, 0); if (imgOp == ImgOP.F16_TO_I8) { D3DXFloat16To32Array(tempHalfToFloatMemory, unmanagedMemory.ptr, (uint)tempHalfToFloatMemory.Length); unsafe { fixed (float* floatPtr = tempHalfToFloatMemory) { byte* bytePtr = (byte*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i++) { float scaledVal = floatPtr[i] * 255.0f; bytePtr[i] = (byte)(scaledVal > 255.0f ? 255.0f : scaledVal); } } } } else if (imgOp == ImgOP.F32_TO_I8) { unsafe { byte* bytePtr = (byte*)unmanagedMemory.ptr; float* floatPtr = (float*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i++) { float scaledVal = floatPtr[i] * 255.0f; bytePtr[i] = (byte)(scaledVal > 255.0f ? 255.0f : scaledVal); } } } if (noAlphaButton.Checked && endianSwapButton.Checked) { unsafe { byte* bytePtr = (byte*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i += 4) { bytePtr[i] = bytePtr[i + 3]; bytePtr[i + 3] = 255; byte temp = bytePtr[i + 2]; bytePtr[i + 2] = bytePtr[i + 1]; bytePtr[i + 1] = temp; } } } else if (noAlphaButton.Checked) { unsafe { byte* bytePtr = (byte*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i += 4) bytePtr[i+3] = 255; } } else if (endianSwapButton.Checked) { unsafe { byte* bytePtr = (byte*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i += 4) { byte temp = bytePtr[i + 3]; bytePtr[i + 3] = bytePtr[i]; bytePtr[i] = temp; temp = bytePtr[i + 2]; bytePtr[i + 2] = bytePtr[i + 1]; bytePtr[i + 1] = temp; } } } if (RBSwapButton.Checked) // Loop again, I don't want to code all the variants... { unsafe { byte* bytePtr = (byte*)unmanagedMemory.ptr; for (int i = 0; i < imageSize; i += 4) { byte temp = bytePtr[i + 2]; bytePtr[i + 2] = bytePtr[i]; bytePtr[i] = temp; } } } //var data = bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.WriteOnly, bitmap.PixelFormat); //System.Diagnostics.Debug.Assert(data.Scan0 == unmanagedPtr.ptr); //bitmap.UnlockBits(data); // Draw a pattern to be able to "see" alpha... e.Graphics.FillRectangle(background, 0, 0, form.Bounds.Width, form.Bounds.Height); e.Graphics.DrawImage(bitmap, new System.Drawing.Point(0, 60)); }; timer.Tick += delegate(object sender, EventArgs e) { form.Refresh(); }; // Run... System.Windows.Forms.Application.EnableVisualStyles(); form.Show(); form.Focus(); timer.Start(); System.Windows.Forms.Application.Run(form); } } private static void InitBuffers(UInt32 bytesPP, System.Drawing.Imaging.PixelFormat format, ImgOP imgOp, ref uint imageSize, ref uint readSize, ref float[] tempHalfToFloatMemory, ref UnmanagedMemWrapper unmanagedMemory, ref System.Drawing.Bitmap bitmap, ref UIntPtr pointer, ref System.Windows.Forms.TextBox memControl, System.Windows.Forms.NumericUpDown xresControl, System.Windows.Forms.NumericUpDown yresControl) { imageSize = (uint)xresControl.Value * bytesPP * (uint)yresControl.Value; readSize = imageSize; if (imgOp == ImgOP.F16_TO_I8) { tempHalfToFloatMemory = new float[imageSize]; readSize *= 2; } else if (imgOp == ImgOP.F32_TO_I8) { readSize *= 4; } unmanagedMemory = new UnmanagedMemWrapper(readSize); bitmap = new System.Drawing.Bitmap( (int)xresControl.Value, (int)yresControl.Value, (int)(xresControl.Value * bytesPP), format, unmanagedMemory.ptr ); UInt64 pointerInt = 0; if (memControl.Text.StartsWith("0x")) { try { pointerInt = Convert.ToUInt64(memControl.Text.Substring(2), 16); } catch (System.Exception) { memControl.Text = "Can't parse ptr"; } } else if (!UInt64.TryParse(memControl.Text, out pointerInt)) { memControl.Text = "Can't parse ptr"; } pointer = new UIntPtr(pointerInt); } } }
Game Design Aspect of the Month
Advancement, Progression and Pacing (Part IV)
In Part I of this article, game designer and educator Ian Schreiber explains the reasoning behind using advancement, progression and pacing in games. In Part II, he discusses challenge levels in PvE. In Part III, he explains how to handle the reward schedule in PvE. Next, he tackles challenge levels in PvP.
Challenge Levels in PvP
If PvE games are all about progression and rewards, PvP games are about gains and losses relative to your opponents. Either directly or indirectly, the goal is to gain enough power to win the game, and there is some kind of tug-of-war between the players as each is trying to get there first. I’ll remind you that when I’m saying “power” in the context of progression, I’m talking about the sum of all aspects of the player’s position in the game, so this includes having more pieces and cards put into play, more resources, better board position, taking more turns or actions, or really anything that affects the player’s standing (other than the player’s skill level at playing the game). The victory condition for the game is sometimes to reach a certain level of power directly; sometimes it is indirect, where the actual condition is something abstract like Victory Points, and it is the player’s power in the game that merely enables them to score those Victory Points. And in some cases the players don’t gain power, they lose power, and the object of the game is to get the opponent(s) to run out first. In any case, gaining power relative to your opponents is usually an important player goal.Tracking player power as the game progresses (that is, seeing how power changes over time in a real-time game, or how it changes each turn in a turn-based game) can follow a lot of different patterns in PvP games. In PvE you almost always see an increase in absolute player power level over time (even if their power level relative to the challenges around them may increase or decrease, depending on the game). In PvP, there are more options to play with, since everything is relative to the opponents and not compared with some absolute “You must be THIS GOOD to win the game” yardstick.
Positive-sum, negative-sum, and zero-sum games
Here is an important distinction in power-based progression that we borrow from the field of Game Theory: whether the game is zero-sum, positive-sum, or negative-sum. If you haven’t heard these terms before:
- Positive-sum means that the overall power in the game increases over time. Settlers of Catan is an example of a positive-sum game: With each roll of the dice, resources are generated for the players, and all players can gain power simultaneously without any of their opponents losing power. Monopoly is another example of a positive-sum game, because on average every trip around the board will give the player $200 (and that money comes from the bank, not from other players). While there are a few spaces that remove wealth from the game and are therefore negative-sum (Income Tax, Luxury Tax, a few of the Chance and Community Chest cards, unmortgaging properties, and sometimes Jail), on average these losses add up to less than $200, so on average more wealth is created than removed over time. Some players use house rules that give jackpots on Free Parking or landing exactly on Go, which make the game even more positive-sum. While you can lose lots of money to other players by landing on their properties, that activity itself is zero-sum (one player is losing money, another player is gaining the exact same amount). This helps explain why Monopoly feels to most people like it takes forever: it’s a positive-sum game so the average wealth of players is increasing over time, but the object of the game is to bankrupt your opponents which can only be done through zero-sum methods. And the house rules most people play with just increase the positive-sum nature of the game, making the problem worse!
- Zero-sum means that the sum of all power in the game is a constant, and can neither be created nor destroyed by players. In other words, the only way for me to gain power is to take it from another player, and I gain exactly as much as they lose. Poker is an example of a zero-sum game, because the only way to win money is to take it from other players, and you win exactly as much as the total that everyone else loses. (If you play in a casino or online where the House takes a percentage of each pot, it actually becomes a negative-sum game for the players.)
- Negative-sum means that over time, players actually lose more power than they gain; player actions remove power from the game without replacing it. Chess is a good example of a negative-sum game; generally over time, your force is getting smaller. Capturing your opponent’s pieces does not give those pieces to you, it removes them from the board. Chess has no zero-sum elements, where capturing an enemy piece gives that piece to you (although the related game Shogi does work this way, and has extremely different play dynamics as a result). Chess does have one positive-sum element, pawn promotion, but that generally happens rarely and only in the end game, and serves the important purpose of adding a positive feedback loop to bring the game to a close.
Positive and negative feedback loops
Another thing I should mention here is how positive and negative feedback loops fit in with this, because you can have either kind of feedback loop with a zero-sum, positive-sum or negative-sum game, but they work differently. In case you’re not familiar with these terms, “positive feedback loop” means that receiving a power reward makes it more likely that you’ll receive more, in other words it rewards you for doing well and punishes you for doing poorly; “negative feedback loop” is the opposite, where receiving a power reward makes it less likely you’ll receive more, so it punishes you for doing well and rewards you for doing poorly.
One interesting property of feedback loops is how they affect the player’s power curve. With negative feedback, the power curve of one player usually depends on their opponent’s power: they will increase more when behind, and decrease more when ahead, so a single player’s power curve can look very different depending on how they’re doing relative to their opponents, and this will look different from game to game.
With positive feedback, you tend to have a curve that gets more sharply increasing or decreasing over time, with larger swings in the endgame; unlike negative feedback, a positive feedback curve doesn’t always take the opponent’s standings into account… it can just reward a player’s absolute power.
Now, these aren’t hard-and-fast rules… a negative feedback loop can be absolute, which basically forces everyone to slow down around the time they reach the end game; and a positive feedback loop can be relative, where you gain power when you’re in the lead. However, if we understand the game design purpose that is served by feedback loops, we’ll see why positive feedback is usually independent of the opponents, while negative feedback is usually dependent.
The purpose of feedback loops in game design
The primary purpose of positive feedback is to get the game to end quickly. Once a winner has been decided and a player is too far ahead, you don’t want to drag it out because that wastes everyone’s time. Because of this, you want all players on an accelerating curve in the end game. It doesn’t really matter who is ahead; the purpose is to get the game to end, and as long as everyone gets more power, it will end faster.
By contrast, the primary purpose of negative feedback is to let players who are behind catch up, so that no one ever feels like they are in a position where they can’t possibly win. If everyone is slowed down in exactly the same fashion in the endgame, that doesn’t fulfill this purpose; someone who was behind at the beginning can still be behind at the end, and even though the gap appears to close, they are slowed down as much as anyone else. In order to truly allow those who are behind to catch up, the game has to be able to tell the difference between someone who is behind and someone who is ahead.
[This article was adapted from Ian Schreiber's course, Game Balance Concepts.]
Ian Schreiber has been in the game industry since the year 2000, first as a programmer and then as a game designer. Also an educator since 2006, Ian has taught game design and development courses at a variety of schools, and on his own without a school. He has co-authored two books, Challenges for Game Designers and Breaking Into the Game Industry.
Game From Scratch
Google announce Android Studio… RIP Eclipse
Today during the Google IO event there was an announcement that both shocked and pleased me. They are releasing a new IDE for Android development. Best of all, it's based on IntelliJ, easily my favourite Java IDE.

(Photo's are from Verge )
One of the coolest new features is the addition of a tool allowing you to see your code running on a multitude of different devices at the same time:

I can say easily one of the things I hate most about Android development is Eclipse, which is pretty much the defacto tool for Android. You could always work in IntelliJ or Netbeans, but it was never quite as seamless and always seem to have a gap or two in functionality. Any news that might potentially keep me away from the hateful IDE that is Eclipse is great news to me!
You can read more about the announcement over at The Verge. As of yet, no downloads are available on Googles websites.
Edit: Download link now available. Also, so hands on screenshots available here.
Geeks3D Forums
NVIDIA CUDA 5.0 for MAC release 5.0.59
New in Release 5.0.59 - no changelog available
actually libcuda_313.01.01.dylib has been added
OpenGL
Comparing Hosek-Wilkie and Preetham Sky Models in SilverLining SDK 2.8
The SilverLining Sky, 3D Cloud, and Weather SDK for OpenGL now lets you switch between the new Hosek-Wilkie model presented at the 2012 SIGGRAPH conference, and the 1999 Preetham model for simulating real-time skies for any time and location. A video’s been prepared using SilverLining comparing its extensions to the two models.
iPhone Development Tutorials and Programming Tips
Open Source iOS Utility Library For Easier Concurrency Programming
Earlier this year I mentioned a thread safe NSTimer replacement.
Here’s an interesting library from Cue called TheKitchenSync providing a library that makes iOS concurrency programming easier.
The library provides thread safe arrays and dictionary classes, an enhanced dispatch queue, easy to implement locks and more.
As the readme states:
Cue’s iOS concurrency library, TheKitchenSync, provides you with a set of advanced locks and thread-safe collections, similar to what you might find in Java.
You can find TheKitchenSync on Github here.
A nice collection of tools for concurrency programming.
- Nifty Utility Library For Easier Threading, Core Location, UITableViews And More
- Tutorial: Objective-C Blocks (Closures) For Beginners
- Creating Isometric Tile Map Games For the iPhone
- Tutorial: Using The Message Center In The Open Source Innerband (iBoost) Library
- A Library Making It Easier To Create Advanced Visual Effects On Your Views Using CATransform3D
Original article: Open Source iOS Utility Library For Easier Concurrency Programming
©2013 iOS App Dev Libraries, Controls, Tutorials, Examples and Tools. All Rights Reserved.
Gamasutra Feature Articles
From XNA to MonoGame
Want to move away from Microsoft's moribund tool? This tutorial explains how. ...
Game From Scratch
A closer look at the Awe6 Haxe inverted game framework
I just recently took a look at available Haxe game engines and decided to take a closer look at two of them, HaxeFlixel and Awe6. I started with Awe6, as frankly it's the most non-traditional of the two options and as a result, the most interesting to me.
Awe6 is a very design pattern heavy framework, built around the concepts of Inversion of Control and Dependency Injection, but reality is, just about every single design pattern that isn't the Singleton make an appearance. As a direct result though, groking it all can be a bit confusing… my current understand of things took a great deal of digging through code and documentation to arrive at. That is one immediate problem with Awe6… the number of examples available can at best be called lacking.
I actually prefer going through working code than I do documentation, so this part is a rather large disappointment. Then again, if I document awe6 usage, I suppose I will have more people interested in the material, double edged sword I suppose. Anyways, so far as existing code to work from, there is the incredibly simple Hello World example, the demo in github and finally this example, probably the best of the bunch.
Ok, enough about what other people have done, now lets take a look at what I've discovered. One of the ongoing trends of Haxe development holds true for Awe6. If you are developing on Windows using FlashDevelop, the process is amazingly smooth. If you aren't… it isn't. I've given in and just work under FlashDevelop, at least when creating my projects. I deploy to Dropbox then can reboot and test in Mac if needed. The following instructions apply to Windows/Flashdevelop only. You can get it working on other OSes, but its a pain.
Getting started is brutally simple. If you haven't already, install Haxe and NME.
Open a command prompt and type haxelib install awe6
Then run the command haxelib run awe6 install
That's it. Assuming you have FlashDevelop installed, you can now create a new awe6 Project via the project menu, otherwise refer to their site for details of working from command line. It will create a fully fleshed out folder structure for you, but truth is, when just starting out this is a bit daunting. That said, the Hello World example is a bit too trivial, so I set about writing something that is middle ground… a more advanced Hello World, or less advanced example project, depending on your perspective.
This awe6 sample simply loads an image and allows you to manipulate it using the left and right arrows. The code:
import awe6.Types;
import nme.display.Bitmap;
import nme.display.BitmapData;
import nme.display.Sprite;
import nme.Assets;
import nme.Lib;
/**
* ...
* @author Mike
*/
class Main
{
static function main()
{
var l_factory = new Factory( Lib.current, '<?xml version="1.0" encoding="utf-8"?><data></data>' );
}
public function new()
{
// needed for Jeash
}
}
class MyImage extends Entity {
private var _sprite:Sprite;
public function new( p_kernel:IKernel )
{
_sprite = new Sprite();
super(p_kernel, _sprite);
}
public override function _init(): Void {
super._init();
_sprite.addChild(new Bitmap(Assets.getBitmapData("assets/img/mechwarriorFrameScaled.png")));
}
override private function _updater(?p_deltaTime:Int = 0): Void
{
super._updater(p_deltaTime);
if (_kernel.inputs.keyboard.getIsKeyDown(EKey.RIGHT))
_sprite.x += 10;
if (_kernel.inputs.keyboard.getIsKeyDown(EKey.LEFT))
_sprite.x -= 10;
}
}
class Factory extends AFactory {
public override function createScene( type : EScene) : IScene
{
var scene = new Scene(this._kernel, type);
scene.addEntity(new MyImage(this._kernel),true);
return scene;
}
}
Below is the Flash target if you want to play around with it (click it first to give keyboard focus, then price left or right arrow):
If you created a Awe6 project, you will notice the one above is a great deal simpler, but all the same basics are there. Some of the terminology may certainly seem alien to you… Factory? Entity? But don't worry, its not actually that difficult in the end.
Let's start with the Factory… this is basically the "guts" of your game… guts actually is probably the wrong analogy… brains would be a more accurate description or perhaps backbone. Essentially you extend the Factory class to implement specific behaviour to your game by overriding a series of methods. In our simple example above, we override the createScene method, but there are dozens of other methods and members that you can set. The full documentation is right here. Essentially the factory configures/defines your game, handles special actions ( such as the back key ), allows you to provide your own implementation of the Sessions, Preloader, Overlay, etc…
So, if Factory is the brains or backbone of your application, Scenes are the meat of it. This is how you organize your game into manageable pieces. You could create a Scene for say… the title screen, one for when the game is playing, one for displaying the high scores, one for credits, one for settings, etc. On top of this, literally, you have the Overlay, which is basically a top level UI or HUD if you like. Your Factory class can create one, but I believe you can also create one at the Scene level as well.
After Scene, we have entities… simply put, these are "things" in your game, visible or not. This could be… your main player, an enemy or a simple proximity trigger. Entities can in turn contain other entities. A Scene can contain numerous entities which themselves can contain many more. Each entity will receive an update() call per tick for updating itself. That's the bare basics of the hierarchy of objects and that just scratches the surface… it doesn't touch on other aspects such as Agendas ( state machines ), Session ( game state ), Preloader ( asset loading/caching ), or many other aspects of the framework. We also don't touch on the kernel yet, which is a very important concept that we will talk about in a moment.
Now, lets take a quick look at how our code works, in order of execution. When our program's main() is called, we simply create an instance of Factory, a class we define that inherits from AFactory. We pass in the context as well as a simple empty configuration in this case. As part of the process ( we will look a bit deeper in a second ) our Factory classes createScene method is called. In createScene, we create a simple scene and add a MyImage entity to it. MyImage is a simple Entity that contains a Sprite class holding our mech image. In the updater method ( called each tick when the entity needs to update ), we check the kernel for input, and move our position accordingly.
Now, understanding exactly what is going on behind the scenes is probably the trickiest part, so lets take a closer look at the process.
As we mentioned earlier, the Factory class is critical to your game, forming it's backbone, setting major configuration settings and perhaps most importantly controlling scene creation. This is where execution begins. You inherit from AFactory, but awe6 remaps it to an appropriate version depending on your platform ( you can see this logic in action right here, the same trick is performed for a number of classes ), all of the platform specific implementations simply provide platform specific functionality, but ultimately inherit from this guy, AFactory.hx. It's kinda confusing at first, but you only really need to involve yourself in the details if you are trying to grok the source code. The most important part of of AFactory to understand at this point is this call:
| inline private function _init():Void |
| { |
| #if haxe3 |
| config = new Map<String,Dynamic>(); |
| #else |
| config = new Hash<Dynamic>(); |
| #end |
| _configure( true ); |
| _driverInit(); |
| } |
The call _driverInit() is of critical importance. This is where the kernel is created. What is the kernel, other than the object we keep passing around? Well if Factory is the backbone of your game, Kernal is the backbone of awe6. Essentially, kernel IS the game engine, and ultimately it is created by your Factory class ( or more specifically, the class your factory inherits from ). So, obviously kernel is important, let's take a look at it's Init() method, it will make a great deal of things clear:
override private function _init():Void
{
super._init();
_view = new View( this, _context, 0, this );
_processes = new List<IProcess>();
_helperFramerate = new _HelperFramerate( factory.targetFramerate );
_isPreloaded = false;
// Perform driver specific initializations.
isDebug = factory.isDebug;
isLocal = _driverGetIsLocal();
_driverInit();
// Initialize managers.
assets = _assetManagerProcess = new AAssetManager( _kernel );
audio =_audioManager = new AudioManager( _kernel );
inputs = _inputManager = new InputManager( _kernel );
scenes = _sceneManager = new SceneManager( _kernel );
messenger = _messageManager = new MessageManager( _kernel );
_view.addChild( _sceneManager.view, 1 );
_addProcess( _assetManagerProcess );
_addProcess( _inputManager );
_addProcess( _sceneManager );
_addProcess( _messageManager );
_addProcess( _audioManager );
// Set defaults for visual switches.
isEyeCandy = true;
isFullScreen = false;
// Signal completion to the factory and initialize factory-dependent components.
factory.onInitComplete( this );
session = factory.createSession();
session.reset();
_preloader = factory.createPreloader();
_addProcess( _preloader );
_view.addChild( _preloader.view, 2 );
}
This is where the various subsystems are created ( assetManager, audio, input, etc… ) and started running ( via addProcess call ). Then you will notice the code calls back into the Factory, calling the onInitiComplete method. At this point, the Factory now has a copy of the kernel and the kernel has a pointer to the factory. One other very important call for program execution is
_view.addChild( _sceneManager.view, 1 );
View is something drawn on screen, in this case the main window. In sceneManager, this is where we go full circle, with the call:
scene = _kernel.factory.createScene( p_type );
This in turn is what calls our derived Factory class's createScene method, causing the Scene to be created, our entity to be added to the scene, etc...
The bright side is, you don't really need to know ANY of this to make use of Awe6. I just personally hate using a framework if I don't understand process flow. It's a clever architecture, decoupling key systems and allowing for you to organize your own code in a clean manner, while still enabling communication between various systems.










