snowcrash

Hi folks,

I am not using any of the game engines supported in the official runtimes (unity, libgdx etc). Does anyone know of any generic runtimes for Android/Java that will allow me to plug in my own rendering system?

I don't want to have to depend on 3rd party libraries just to be able to load and render an animation, and ideally don't want to reinvent the wheel by implementing an entire runtime when so many already exist.
snowcrash
  • Сообщения: 25

Nate

You could repurpose the libgdx runtime and then implement the rendering for Android. I don't know that anyone has done that.
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

Yeah I went down that path but it's a fairly steep learning curve to understand all the "ins and outs" and to be honest I was hoping I wouldn't have to build an entire runtime engine just to use the tool. It makes sense that there would be a version of a runtime that had a libgdx "adapter" but a tightly bound dependency means anyone with their own engine is kinda lost. Removing/replacing the util classes is fairly simple but requiring a texture atlas (and all it's dependencies) to just parse the JSON document makes it a little difficult.

I also tried compiling the spine-c runtime with the NDK (because it's generic) but ran into some compilation problems. That's most likely an issue with my environment though.

I think I'm going to try abstracting out all the GDX specific bits, and the rendering, into a GDX adapter then implement my own custom adapter. That way the "boilerplate" code that is necessary to just parse the document and create the data model can be independent of the specific implementation for rendering and/or transformations.
snowcrash
  • Сообщения: 25

Pharan

Have you checked Spine-C#?

It's probably the closest thing to a generic Java-like runtime. At least it'll give you a clearer idea on what a generic runtime handles separate from the engine-specific concerns (plus it's easier to understand than the C runtime because it uses language-supported OO).
Аватара пользователя
Pharan
  • Сообщения: 5366

snowcrash

I hadn't checked that out actually. I'm about half way through refactoring the spine-libgdx implementation to abstract out all the libgdx stuff. I'll submit a pull request once it's done.
snowcrash
  • Сообщения: 25

Nate

Making spine-libgdx generic would need to fork a number of libgdx classes, which I don't really want to do. :( I'm not sure what sort of performance you'll see on Android without OpenGL, but I expect it to be pretty bad. The easiest thing to do is just use libgdx. You should be able to mix an OpenGL view with other Android views.
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

"Making spine-libgdx generic would need to fork a number of libgdx classes".. not really. I'm converting all references to libgdx classes in the spine runtime to interfaces. There would then just be a libgdx "adapter" which is just a set of implementations of those interfaces (eg. Array, FloatArray etc). libgdx iteself and its classes don't change. There's just a layer of abstraction which is only relevant in a spine context.

I am using OpenGL. I just have my own implementation which uses my own shaders, sprite batches, textures etc. My experience in the past with engines is that I inherit a whole lot of fat and a whole lot of inflexibility. From what I've heard libgdx is great, but I need/want the flexibility to shape things independent of the restrictions imposed by any given framework.

The end result for spine is a default runtime implementation which still uses libgdx but is extensible to other frameworks and/or rendering environments.
snowcrash
  • Сообщения: 25

Nate

I'm not sure if interfaces would be better than forking the classes needed. Using interfaces for core classes like Array isn't great as it causes virtual method calls, and implementations of those interfaces will basically be the libgdx classes anyway. I don't think I would merge it with the official runtimes right now, as I already have 18 of those and keeping it all maintained is a huge pain! I would definitely link to your stuff on the runtimes page though.
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

Agreed on the virt. method implications, but there's not really another option. You've said you don't want to fork libgdx and (now) don't want interfaces... which is fine, but I'm not sure I understand what you're suggesting as an alternative? Perhaps the best interim solution would be to either replace the basic utility classes (Array, FloatArray) with comparable alternatives or (better) remove the need to have collection operations for each frame (e.g. I typically create a collection at startup then convert this to an array so each frame is iterating an array), so there are no method calls at all. Virtual method calls that are only called during bootstrap operations are fine.

There seems to be an assumption that if a developer is building for Android therefore they're using libgdx. For thousands of developers this is simply not the case. I like to support new and innovative companies, and the client tool is awesome, but awesome + unusable is not a winning combination. I understand that you don't want to include just any old crap into the project, but an unwillingness to remove dependency on a framework whose inclusion will necessarily exclude a significant portion of your target market seem odd to me. Then again I may be overstating the impact.
snowcrash
  • Сообщения: 25

Nate

Well, you are the only person that has spoken up about a need for a generic Java runtime. I would suggest implementing a solution specific to your game engine based on spine-libgdx by forking the necessary classes. This is probably what I'd do to make a generic Java runtime, which I would probably maintain separately from spine-libgdx. Use the same class and package names and then updating the latest Spine runtime would just be a matter of copying spine-libgdx over your runtime files, then using Eclipse's organize imports on the whole project.
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

OK fair enough. I guess most people must be using libgdx.

I tried porting the libgdx flavor but it turns out that it's actually easier to just use the spine-c flavor and expose what I need via JNI back to Android.

In my implementation I don't need all the vert transformations etc, all I really need is the bone scale/rotate/translate values at a given time step. To that end I've included a snippet from my implementation which seems to work (i.e. values change over time) but I just want to confirm that my assumptions are correct.

So rather than extracting the vertices, I just get the bone data:
spAnimationState_update(state, deltaTime);
spAnimationState_apply(state, skeleton);
spSkeleton_updateWorldTransform(skeleton);

int i;
for(i = 0; i < skeleton->boneCount; i++) {

spBone* data = skeleton->bones[i];

callback->onBoneStep(
i,
data->worldX,
data->worldY,
data->worldRotation,
data->worldScaleX,
data->worldScaleY);
}
(The "callback" instance is calling back to the JVM)

I don't really want "world" coordinates, but when I use the relative values (e.g. data->x) they don't seem to update.

Is there a better way to just get the SRT values?
snowcrash
  • Сообщения: 25

Nate

Have you looked at gdx-jnigen?
http://www.badlogicgames.com/wordpress/?p=2254
It's super cool, makes doing native stuff a breeze. Eg:
https://github.com/libgdx/libgdx/blob/m ... .java#L796
The build is done for you, setting it up looks like this:
https://github.com/badlogic/jglfw/blob/ ... Build.java

Your code looks fine. Applying an animation adjusts the local SRT. If you don't care about world SRT, you don't need updateWorldTransform:
spAnimationState_update(state, deltaTime);
spAnimationState_apply(state, skeleton);

int i;
for(i = 0; i < skeleton->boneCount; i++) {
spBone* bone = skeleton->bones[i];
callback->onBoneStep(
i,
bone->x,
bone->y,
bone->rotation,
bone->scaleX,
bone->scaleY);
}
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

I'd actually already written all the bits by the time I posted that last reply. There's not a lot to it and the build is handled pretty easily with Android's ndk-build command. Anyway thanks for your help.

BTW.. I had a follow up question.

What's the significance of the "track" parameter when setting an animation?

https://github.com/EsotericSoftware/spi ... ate.c#L228

I had wondered how I can run more than one "version" of the same animation without needing to reload the JSON files. Is this what the "track" means? If not, how do I run more than one animation (with their own state) without needing to load up the skeleton/atlas files for each one?
snowcrash
  • Сообщения: 25

Nate

See here:
http://esotericsoftware.com/spine-using ... ationstate

Animations are stateless, they only needed to be loaded once and can animate any number of skeletons. You can see the separation here:
http://esotericsoftware.com/spine/files ... iagram.png
Only "Instance Data" has state for a skeleton.

AnimationState keeps the state (time, queue per track, previous animation for mixing, etc) per skeleton. It is just for convenience though.
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

OK.. I think that makes sense. My confusion arises from here I think:

https://github.com/EsotericSoftware/spi ... son.c#L304

Creating a spSkeletonData instance (which is stateful according to the diagram) requires the loading of the JSON file from disk. So.. I plan to re-create the spSkeletonJson_readSkeletonDataFile method elsewhere and retain the json data (char* json) so it can be re-used to create additional spSkeletonData instances without needing to load the JSON file from disk every time. Alternatively I guess I could cache the data read in the _spUtil_readFile implementation. On second thought that's going to be a lot easier, as long as I also create a way to clean it up at the end.
snowcrash
  • Сообщения: 25

Nate

Skeleton is stateful, you need one per on-screen skeleton instance. SkeletonData is not stateful, you need only one.
http://esotericsoftware.com/spine-using ... eletondata
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

OK.. thanks for that. Much clearer now.

So hopefully this is my last question. :)

I have the json files being loaded and executed, with (world) bone SRT coming back to Android and with a simple render of the SRT data just using primitive shapes the animation appears to be correct (just via visual comparison with the same skeleton running inside the spline app).

The only problem I have now is the time scale. My version seems to run a lot slower than the same animation running in spline. I'm calling the spAnimationState_update function with a delta parameter that corresponds to the number of milliseconds since the last frame render (so "real time" in other words) but the animation is running at about 1/20th of the speed I see in the app.

Are the time units milliseconds? If so, is there a reason you can see that, for example, passing 100ms to spAnimationState_update would not position animation at the same state as 100ms in the app?

It could be that I've added some cruft somewhere along the way but I just want to make sure I'm understanding the use of spAnimationState_update.

Thanks!
snowcrash
  • Сообщения: 25

Nate

The time is in seconds. :)
Аватара пользователя
Nate

Nate
  • Сообщения: 9766

snowcrash

Yep.. that's done. I think we're done.

Thanks for all your help. I won't bother with a pull request as it's a fairly specific implementation, but if anyone else wants a look it's at:

https://github.com/jasonpolites/spine-r ... ne-android

It's a bit rough, but it's a start.
snowcrash
  • Сообщения: 25


Вернуться в Runtimes