Various optimizations for Json.c and Json.h.
parse_value uses a switch on starting character and avoids three strncmp
calls in many cases.
parse_number dispatches to strtod (C89) or strtof (C99), which is a
slightly more permissive superset of JSON's RFC4627 number parsing, but
is also quite a bit faster. More explicit error handling added here
too.
(The parse_value and parse_number changes alone made for a ~1.5x speedup
on our tiny ARM926 platform using uclibc 0.9.30 and gcc 4.3.3.)
Use _stricmp or strcasecmp in Json_strcasecmp. This one has a tricky
#include issue; it's in <strings.h> in some systems and <string.h> in
others. Defining _DEFAULT_SOURCE and/or _BSD_SOURCE pulls it into
<string.h> in all of the systems we could find. This is a noticeable
win, but less than parse_value or parse_number.
Elide NULL checks in almost all functions, insert one during
Json_create. Everywhere else, the code already explicitly checks and
returns. skip() keeps a NULL check but pushes it outside the loop, so
we only check it on entry to the method.
Also elide some redundant starting character checks for parse_object
('{') and parse_array ('[') since they're only called from parse_value
and we know the character is correct. There's an opportunity to do this
also for parse_string, but it's a bit more complicated as it's called
from parse_object as well as parse_value.
For all these elided checks, allow them to reappear if SPINE_JSON_DEBUG
is defined and nonzero.
Spine doesn't use the "prev" field ever, so drop it entirely from the
Json structure unless someone defines SPINE_JSON_HAVE_PREV non-zero.
Pull some of the assignments out of conditionals to placate some of the
higher-warning-level compilers.
A few TODO comments left near some of the other speedup opportunities,
as well as one existing place that might need additional error handling.
(Tested on various x86 and ARM gcc versions, Xcode 5.x series, Visual
Studio 2010 SP1, ARMCC 5.04, and MWCCARM 4.0. Holler if this should be
decomposed into a patch series, if there are any suggestions or idiom
changes, or a different submission method we should be using.)
spine-c
The spine-c runtime provides basic functionality to load and manipulate Spine skeletal animation data using ANSI C. It does not perform rendering but can be extended to enable Spine animations for other C-based projects, including C++ or Objective-C projects.
Setup
- Download the Spine Runtimes source using git or by downloading it as a zip.
- Open the
spine-c.slnVisual C++ 2010 Express project file. For other IDEs, you will need to create a new project and import the source.
Alternatively, the contents of the spine-c/src and spine-c/include directories can be copied into your project. Be sure your header search is configured to find the contents of the spine-c/include directory. Note that the includes use spine/Xxx.h, so the spine directory cannot be omitted when copying the files.
If SPINE_SHORT_NAMES is defined, the sp prefix for all structs and functions is optional. Only use this if the spine-c names won't cause a conflict.
Examples
Extension
Extending spine-c requires implementing three methods:
_spAtlasPage_createTextureLoads a texture and stores it and its size in thevoid* rendererObject,widthandheightfields of anspAtlasPagestruct._spAtlasPage_disposeTextureDisposes of a texture loaded with_spAtlasPage_createTexture._spUtil_readFileReads a file. If this doesn't need to be customized,_readFileis provided which reads a file usingfopen.
With these implemented, the spine-c API can then be used to load Spine animation data. Rendering is done by enumerating the slots for a skeleton and rendering the attachment for each slot. Each attachment has a rendererObject field that is set when the attachment is loaded.
For example, AtlasAttachmentLoader is typically used to load attachments when using a Spine texture atlas. When AtlasAttachmentLoader loads a RegionAttachment, the attachment's void* rendererObject is set to an AtlasRegion. Rendering code can then obtain the AtlasRegion from the attachment, get the AtlasPage it belongs to, and get the page's void* rendererObject. This is the renderer specific texture object set by _spAtlasPage_createTexture. Attachment loading can be customized if not using AtlasAttachmentLoader or to provider different renderer specific data.
spine-sfml serves as a simple example of extending spine-c.
spine-c uses an OOP style of programming where each "class" is made up of a struct and a number of functions prefixed with the struct name. More detals about how this works are available in extension.h. This mechanism allows you to provide your own implementations for spAttachmentLoader, spAttachment and spTimeline, if necessary.