Spherical forums

miniSphere is the current official implementation of Sphere and a complete rewrite of Chad Austin's original Sphere game engine, coded from the ground up in C. It uses Allegro (http://alleg.sourceforge.net/) for cross-platform graphics and sound and JavaScript is powered by ChakraCore (https://github.com/Microsoft/ChakraCore). The engine boasts almost full parity with the Sphere 1.5 API and most Sphere 1.x games run in miniSphere with no modifications. But make no mistake: this is a Sphere v2 engine, and includes many, many features not found in the engine it replaces. These include Galileo, a scene graph API pioneered by TurboSphere which enables more flexible rendering than the Sphere v1 primitive-drawing functions; the RNG class for ultimate control over random number generation; SphereFS, a standard protocol for specifying asset filenames within the sandboxed file system; and full native support for JavaScript module syntax (import/export) as defined in ES2015. Best of all, old and new API functions can be mixed within the same codebase, making migration of existing codebases to Sphere v2 very easy.

Thanks to ChakraCore, the same JavaScript engine that powers Microsoft Edge, miniSphere natively supports modern JavaScript features such as template strings, arrow functions, destructuring assignment, even modules! The engine also comes with an SCons-inspired programmable build engine, Cell, also JS-powered, which can be used to build assets on-the-fly. miniSphere was also the first implementation of Sphere to include support for single-step debugging! Thanks to ChakraCore's powerful built-in debugger API, it does! Using either Sphere Studio or the SSj command-line debugger (both included with the engine), you can set breakpoints, see console output, and step through your game's code line-by-line to find bugs, inspect variables and even run arbitrary JavaScript code. It's an invaluable tool for any serious game developer. Some might say it's miniSphere's killer feature!

AUR official package for Arch Linux (https://aur.archlinux.org/packages/minisphere/) (install with makepkg and pacman)

tarball for Linux and similar platforms (https://github.com/fatcerberus/minisphere/releases/download/v5.3.0/minisphere-5.3.0.tar.gz) (.tar.gz, ~937 kB)

note on macOS release:The macOS release is maintained by @Rhuan. While every attempt is made to coordinate milestone releases (e.g. 5.3.0) across all platforms, the macOS build can sometimes fall a few patches behind during a given release cycle.

Small issue with that: besides that that puts surface operations entirely in software, how would I implement methods like surface.drawText, not to mention all the primitives. If I wanted a 1:1 mapping to Sphere 1.x I'd have to implement those all in JS as well, meaning I don't get the benefit of letting the hardware do it, as I could if I were to implement surfaces natively.

So I'm thinking maybe not surfaces, but a lot of things will be implemented scriptside in minisphere. For example: Color objects. Duktape's stack-based API is painful to use (I don't even remember Lua's being this bad...) and once constructors and prototypes get involved, it gets even more convoluted. For simple objects like Color, there's no real benefit to creating them on the C side as in the end it's just a simple RGBA tuple. JS can handle those very well on its own.

In the process I think I'm going to make tweaks to the structure of the API, clean things up a bit. For example, BlendColors() and BlendColorsWeighted() both get folded into the Color object as a single method: color_obj.blendWith(color2, w1, w2). Of course, to maintain compatibility with existing Sphere code, I'll be sure to expose some kind of legacy API, likely as an optional thing, similar to what Jester is planning to do with TurboSphere.

I've been doing that to a certain extent with the map engine, and with images now.

I think that colors are one of the better objects to do that with, actually. In V8 there was a pretty high overhead to making any native-defined object, especially since that usually meant some native-side allocation had to occur. Making colors is easy to do all over the place in a normal Sphere script without even thinking about it. Putting them fully in script would help alleviate that. Especially because there is no particular reason they need to be done in native.

I think it's a good technique. Have a powerful, concise core API that Sphere's API is implementable in, and also a script-side layer that fills out the rest of the Sphere API. Even with the map engine, which is all script anyway =P

I'm not too concerned about script-to-native overhead--the purpose of a stack-based API like the one in Duktape and Lua is that any objects created are allocated in-engine, rather than on the native side. For example, this:

As you can probably tell, the bigger concern here is the unmaintainable mess the C-side constructors will end up becoming (hint: see first code snippet). A lot of that can be avoided simply by implementing stuff directly in JS to start with.

Hm, so I'm thinking I may try out Allegro after all. SFML was definitely designed for use in C++ (mapping a C++ API directly to C = incredibly bad idea), and I'd really like to keep this in C to keep it as simple as possible.

The main difference between SDL2 and 1.2 is API changes, especially WRT window handling (which is one of the many things abstracted to their newer image/surface/frame/etc buffer handling API). Most of the extra libraries (especially sdl_audio) do keep their APIs but simply changed internally to be SDL2-compatible at that time.

Support-wise, whatever 1.2 runs on SDL2 still runs on, but SDL2 might recommend a more C++ approach to it.

Re Allegro - It won't hurt to see how far an Allegro-based Sphere-compatible engine can go. If you choose to do it, I'd very much consider promoting it as an official multi-platform alternative to current vanilla 1.5, alongside TurboSphere and SSFML. :)

NEO: That's not entirely true. SDL2 does not work on some platforms like QNX, SunOS, Windows CE, BeOS, and AmigaOS4 where SDL 1.2 did work, and support is spotty on Solaris, AIX, HP-UX, and Haiku.

So basically, you lose some old-world mobile platforms and QNX, and it becomes hard going on traditional, commercial Unix, and Haiku. I for one do not mourn for the platforms that become unusable. Having Unix, Windows (Win32 and Metro), Haiku, Android, and iOS, in addition to a theoretical HTML5/JSM platform seems like plenty to me.

SDL2 supports compiling out certain portions, too (for instance, the SDL that I distribute with TS has no audio support), but I found that SFML can do that too, and I suspect Allegro could as well.

SDL2 (and for the most part SDL 1.2) are a mix of OOP and procedural code. I find it pretty easy to work with in either C or C++, it doesn't feel all that unnatural in either. I'd say its worth considering, Allegro is fine with me, too. These are all fairly comparable solutions, and I wouldn't say that its 'wrong' to choose any of them.

So Allegro's API is actually quite nice. Much less boilerplate required to get things up and running compared to SFML. Just create a display and an event queue, and then a main loop that calls al_flip_display() and processes events and you're good to go. SFML was such a pain in the ass, requiring creating structures all over the place just to do something as simple as draw a rectangle.

Honestly, Allegro seems like a perfect fit for the backend of a Sphere engine: Its API is very close in structure to the way the Sphere 1.x API is already designed, meaning this should be pretty painless.

So Allegro's API is actually quite nice. Much less boilerplate required to get things up and running compared to SFML. Just create a display and an event queue, and then a main loop that calls al_flip_display() and processes events and you're good to go. SFML was such a pain in the ass, requiring creating structures all over the place just to do something as simple as draw a rectangle.

Honestly, Allegro seems like a perfect fit for the backend of a Sphere engine: Its API is very close in structure to the way the Sphere 1.x API is already designed, meaning this should be pretty painless.

So fairly big showstopper I just hit: Duktape creates and writes JS objects entirely in-engine with the only thing existing on the native side being the code of native functions. There doesn't appear to be a way to create an object on the native side (e.g. a sound) and have data associated with it that is invisible to JS (pointers or handles, say) but readily accessible to native code. The only facility Duktape supplies for this purpose is the "stash", which is itself an in-engine (but invisible to script) JS object and global to the JS context--not exactly suitable.

So yeah, not really sure what to do here.

edit: Also, Allegro's handling of alpha is... odd. I draw two overlapping rectangles, both with alpha 0. These should be completely invisible, right? Instead I get this...

edit 2: Well, I figured it out the alpha issue anyway, Allegro's default blend mode assumes premultiplied alpha, so I just had to change it using al_set_blender()

Okay, so Duktape is very strange. If you try to retrieve the location (file and line number) of a script error, it instead gives you the filename of the C source file which called the script and the line in that file where the Duktape call was made. For instance, calling Abort() reports that the error happened in sphere_api.c on line 49--in other words, the duk_error call. Even for, say, syntax errors though, it seems to correctly report the line in the script, but not the filename--instead it returns the path of the C file making the duk_peval_*() call.

Here's where things get strange though: It correctly reports the source file and line number for the duk_error() call even in release mode, where that information shouldn't even be available (there's no debugging info). What sorcery is this?

Yeah, that's what it is, half of Duktape's API is just macros that call internal functions. Thank goodness Intellisense works with macros now (it never used to, at least it didn't the last time I used VC++), otherwise that would be annoying as hell.

I also did some reading and found out I can store internal state for native-created JS objects. It's simple, too: On the native side, you just set properties on the object with identifiers starting with 0xFF as the first character. Since that creates an invalid UTF-8 string, such properties aren't accessible on the JS side but the native code can access them easily.

So something interesting I found out: Duktape uses reference counting for garbage collection, only falling back on mark/sweep if refcounting fails to free the object--i.e. circular refs. Which means a call like the following:

...will cause the garbage collector to finalize and free the sound as soon as play() returns (meaning this snippet is effectively an expensive no-op under Duktape), whereas, say, SpiderMonkey, the sound might actually stick around for a while. Something to keep in mind.

As for actual minisphere news, I've implemented about half of the Sound API (NOT the SoundEffect API though, that's a different beast entirely), meaning minisphere can load and play music and sounds now! It definitely helps that the learning curve on Allegro (and even Duktape, for the most part) is practically non-existent, which is awesome. Now I remember why I used to love coding in C. Sure, it's ridiculously easy to shoot yourself in the foot (although perhaps not quite so bad as C++), but the language is so simple that, for the most part, it ends up being self-documenting.

So is there a safer (not subject to buffer overflows) version of sprintf() I can use? sprintf_s() is VC++-only, and C99 support in VC is abysmal, meaning no snprintf() either. See, my code for normalizing paths looks like this:

You should check out using parts of BSD's libc. That's what I've been doing for my Kashyyk IRC client when I want some reasonable C-string support with MSVC.

For instance, I imported BSD libc's strcasestr function (look here, strcasestr.c, strcasestr.h, str-two-way.h (https://github.com/FlyingJester/Kashyyyk/tree/master/kashyyyk/platform)) for use with MSVC (and in more recent builds, MingW as well). I only compile the functions I need, not the entire library.BSD's libc seems to be intended to work with pretty archaic and incapable compilers, and so it seems to mostly work with even MSVC, which it has no real reason to support. It also has very confined systems, so in the case of strcasestr, I only needed one extra file besides the source file and header for the function I wanted (and even then just a header).

Alternatively, just put in some defines or def'ed out functions that adapt snprintf, sprintf+strlen, and sprintf_s depending on what is available to the compiler. That way you can get sprintf_s and snprintf when they are available, and have a safe, if less efficient default when neither exists. I do that for `strdup' in TurboSphere. One define that uses strdup, one with strdup_, an inline function that uses strlen, malloc, and memcpy to replicate it.

Alternatively, just put in some defines or def'ed out functions that adapt snprintf, sprintf+strlen, and sprintf_s depending on what is available to the compiler. That way you can get sprintf_s and snprintf when they are available, and have a safe, if less efficient default when neither exists. I do that for `strdup' in TurboSphere. One define that uses strdup, one with strdup_, an inline function that uses strlen, malloc, and memcpy to replicate it.

...and I've just hit the one thing I absolutely hate about C: String processing. Even just to parse the command line to interpret -game "<game dir>" is ridiculous. Also, Duktape isn't particularly fast--in fact, I think it might even be slower than the SM in Sphere 1.5. I had minisphere try to run Specs (which has lots of RequireScript in main.js), and there was about a half-second delay between the game window showing up and the JS error due to undefined identifiers (i.e. unimplemented APIs). Granted, this was under the VC debugger, so I'm sure I took a performance hit just for that, but even so...

You could check out using stdargs (or was it stdarg?) for that. Or for more generally strings, something the NSPR. There is a reason that a LOT of C-based projects either have or use some system other than just raw C-strings for their string representations.

It shoudn't be that hard to do arg parsing like that in C. TurboSphere did its argument parsing in pure C up until very recently.

It's possible that duktape is much slower on error conditions (like an uncaught exception). That's true of a lot of virtual machines, especially because often there's not a lot of reason to be fast when you can't recover.

Yeah, I found out from playing around that the game dir comes into main() as argv[1] = "-game" and argv[2] = <game dir> conveniently sans quotes, making it simpler than expected. Of course, this was AFTER writing code to parse the full command line... oh well.

Can I count on this behavior though, or do there exist compilers that pass the full command line to main() as a single argument?

Also, MS apparently doesn't like strdup and getcwd (and probably some others). The compiler complains that "The POSIX name is deprecated, use _strdup instead." Last I checked, these weren't deprecated in any standard... I would really like a clean build without preprocessor cruft everywhere, but that's looking more and more impossible. Pure C is apparently not as portable as everyone makes it out to be.

Let me just say for the record that Allegro is awesome. So much stuff is built in that I never expected to be, I always thought it was just a graphics library. For instance, a platform-agnostic way of handling file paths, avoiding all the path-parsing headaches discussed above. Also: INI-style config management, meaning I don't even have to parse game.sgm myself, I can let Allegro do it. ;D

One potential source of incompatibility, though: Duktape doesn't recognize const, it causes a syntax error. I realize it's not standard JS, but SpiderMonkey handles it without issue, so any existing Sphere game that declares things const won't run in minisphere.

One potential source of incompatibility, though: Duktape doesn't recognize const, it causes a syntax error. I realize it's not standard JS, but SpiderMonkey handles it without issue, so any existing Sphere game that declares things const won't run in minisphere.

Same with Jurassic! I was able to modify the code though so I am using technically a modified version of it. You could do a RegEx replacement of const to var, but you have to make sure it's only ever in the context of a variable declaration and not say, in some text or a comment (meaning you'll have to write a custom pre-processor parser).

Okay, so I think minisphere actually isn't too far off from being able to run Spectacles. I think I just need surface support, which shouldn't be too difficult, and .rfn font support (plus associated text-drawing functions), which... may be harder.

See, Allegro has a function to register your own font loader, al_register_font_loader(), which I could use to let it load .rfn fonts, but here's the issue: The documentation for the ALLEGRO_FONT structure is, well, pretty much nonexistent--even a Google search turns up nothing of use. Which leaves me only to look at how Allegro loads fonts internally to try to figure it out myself, and even that wasn't particularly helpful at last attempt.

See, I would do stuff in script, but Duktape is actually pretty slow so I need all the performance help I can get by doing stuff natively. Besides, if I let allegro load the font instead of drawing the bitmaps manually, I get stuff like WrapText etc. basically for free instead of having to implement it myself.

So I finally got Allegro loading RFN fonts, and it actually seems to work pretty well. Only issue: Apparently RFN fonts are actually stored fixed-width (including the default system font), despite vanilla Sphere rendering them variable-width--and the format supports it even! This means naively rendering characters according to their associated glyphs' widths causes the string to be spaced quite far apart. Still haven't figured out how to fix this yet.

I guess I could crop the glyph bitmaps at load time, but I'm reluctant to do so because that would mess with RFNs that were actually saved variable-width and would thus already be tuned for proper kerning, etc.

Yeah, as it turns out the Sphere 1.5 API isn't all that complicated, there's just a LOT of functions. Most of the graphics APIs would be about 3-5 lines of code if it weren't for all the stack juggling Duktape requires.

So, who's up for trying to compile minisphere on something other than Windows to see how it works? :D

Yeah, as it turns out the Sphere 1.5 API isn't all that complicated, there's just a LOT of functions. Most of the graphics APIs would be about 3-5 lines of code if it weren't for all the stack juggling Duktape requires.

Implementing the Sphere graphics API was precisely what lead me to believe that it would be better to have a very small API, even if it were a little more verbose. That's why TurboSphere just has the Shape and Group objects, and no primitives or even direct Surface or Image blitting at all.

Yeah, as it turns out the Sphere 1.5 API isn't all that complicated, there's just a LOT of functions. Most of the graphics APIs would be about 3-5 lines of code if it weren't for all the stack juggling Duktape requires.

Implementing the Sphere graphics API was precisely what lead me to believe that it would be better to have a very small API, even if it were a little more verbose. That's why TurboSphere just has the Shape and Group objects, and no primitives or even direct Surface or Image blitting at all.

Also: It's still smaller than Sphere 1.5. About half the size at last check. Also a much smaller codebase. Vanilla Sphere's codebase is frankly huge for such a simple engine.

Even if you include all the Allegro libraries? Sphere's codebase includes the entire editor, too (which has some guts in many shared components), as well as the loaders for many audio file types, image types (including all of libungif), and the binaries include the MSVC runtime, as well as several graphics plugins.

I'd be surprised if, including all the necessary libraries, minisphere was actually able to open all the same file types as Sphere, play most of the same games (stuff like const notwithstanding), and was still less than half the size.

@FJ:I'm using the Allegro monolithic library, which is about a 2.25MB DLL and includes all Allegro functionality, including audio (if you're using more than about 3 Allegro components, the monolithic is actually smaller than the individual DLLs). The minisphere executable at current is around 550KB. That's literally the entire engine in 2.8MB. Even if you count the system directory (which I guess technically you should? Full Sphere 1.5 compliance and all): 3.89MB.

Admittedly not a huge difference--ignoring editor.exe and SciLexer.dll, but including config.exe and the system directory, Sphere 1.5 is 5.25MB. Still, minisphere is smaller, so I think the name still stands! :)

@Radnen:Very odd. Give me a code sample that you tried that caused the error, I'll look into it. It runs Spectacles very well, so...

@Radnen:Very odd. Give me a code sample that you tried that caused the error, I'll look into it. It runs Spectacles very well, so...

Well, it does it for anything, even if I use dll files, etc. how are you playing games with it? Do you drag them on to the executable or do you put everything into the startup folder? Because the startup game also did the same thing.

You can put the game into the startup folder, but actually, all you have to do is point Sphere Studio at minisphere and it'll work. It accepts the -game commandline argument just like 1.5 and SSFML does.

So did you get it to run anything? Specs uses a good chunk of the API, so I'd expect there must be at least some games out there that work. Although most games use the map engine, so perhaps not... Note that the startup game won't work even if you remove the consts as I didn't implement ExecuteGame et al. yet.

Anyway, I've just started on the map engine and am currently trying to get In the Steps of the Blackfoot running. That was the game that introduced me to Sphere, so I kind of have a soft spot for it. :)

Note that the startup game won't work even if you remove the consts as I didn't implement ExecuteGame et al. yet.

ExecuteGame is very challenging to implement with most JS engines. It's extremely difficult, or just plain impossible for V8 to cancel execution of a script from native. I am unsure of how difficult it is with SM, although it seems to have better support for such an idea. I would think that JS engines not expressly intended for a web browser may actually have an advantage here.

I basically have just written this part of the API off. It's a cool feature, but ultimately not that useful. I don't lose much sleep knowing the startup games don't run.

That's the awesome thing about Duktape--everything is done in-engine, and the call to game() is protected, meaning all I have to do to bail out of script execution (including infinite while(true) loops! Assuming they call FlipScreen anyway...) is throw an exception via duk_error(). This drops me off immediately after the duk_pcall, with the exception on the stack. This is the same mechanism I use to bail out when the game window is closed, and it's awesome.

I basically have just written this part of the API off. It's a cool feature, but ultimately not that useful. I don't lose much sleep knowing the startup games don't run.

Not so fast! There is a... compromise. You could spawn an entirely new instance of Sphere. So you would have two games running simultaneously, but if you minimize one and play the other you should be fine. I'm intending to do this with SSFML.

I basically have just written this part of the API off. It's a cool feature, but ultimately not that useful. I don't lose much sleep knowing the startup games don't run.

Not so fast! There is a... compromise. You could spawn an entirely new instance of Sphere. So you would have two games running simultaneously, but if you minimize one and play the other you should be fine. I'm intending to do this with SSFML.

You mean an OS-level instance of Sphere? Like with `exec`?

That's an option. I for one would far prefer the engine actually be capable of starting and stopping, but so far that has been difficult.

I know that in Posix systems it would even be simple to startup a new Sphere process and assign it to a nohup parent process...hmm...

So out of morbid curiosity, I ran SSFML's startup game in minisphere and tried the surface fill test, one of the few things in there that actually works. My results: ~1400 FPS. Screenshot attached as proof. ;D

Of note: The main menu runs at around 700FPS on the same machine.

Laptop is i5-2450M with 4GB RAM, Win8.1 Pro x64.

Edit: In the interest of completeness, I also ran the test on Sphere 1.5. It barely broke 550 FPS on the same machine. Honestly, my experience so far has been that minisphere actually outperforms Sphere 1.5 in all cases. At least with the standard32 plugin, anyway. I should probably test it with the OpenGL plugin at some point...

So out of morbid curiosity, I ran SSFML's startup game in minisphere and tried the surface fill test, one of the few things in there that actually works. My results: ~1400 FPS. Screenshot attached as proof. ;D

Yep, you have better surfaces, even better than 1.5. But with HW surfaces in SSFML I could do 6500 fps on that same screen (~900 in Sphere 1.5 for comparison). I do 700 fps on that screen in SW (so worse than Sphere). But, only when many HW surfaces and features were used the fps started going way way down, it's like SFML just can't handle more than 2 or 3 surfaces on screen at the same time. I find this odd since I use hardware surfaces for tile animations in the map engine and it's really fast. But then again it's just a single surface.

From what I can tell, the tiling is what's doing it. Disabling the window background as a test, it hit 1600 fps. Which is weird, since it's just drawing the same bitmap multiple times, and I'm even batching them (unbatched, for the curious, it dropped to 3(!) fps).

The big window test is notoriously difficult on the graphics because it tiles a 1x1 pixel background image (in practice you won't see this). Compare to Standard32 Sphere 1.5 and SphereGL. I think SphereGL bottoms out at 2fps, or some other horrendously low number (even on my Nvidia GTX 970). In practice, try a windowstyle with a 16*16 or greater background image. Now, that said, if you are batching the image I'm really curious why you only get 30fps. Allegro must be doing some pretty naive graphics processing, despite the fact you can tell it to "defer" the drawing. I say this because you can totally do better with surfaces.

Standard32 Sphere manages 415 fps in the big window test (AMD A10-6800K), 13 with sphere_gl. Note that on the same machine, this (13fps) is identical to minisphere's result. I wonder if Allegro is using OpenGL under the hood?

No idea how SSFML pulls 3000fps in this test. You must have one hell of a sprite batcher.

There are, I suspect, two reasons that the SphereGL driver sucks at this. The first is that sending so many vertices takes a lot of time, and bandwidth is the main limiting factor for doing hardware graphics. This is just a general issue with older OpenGL, and why using a newer version like 3.3 or 4.1 is better, because it makes doing that impossible.The second issue is that SphereGL decides to unbind textures and disable texturing at the end of every call. This was the main place I saw for improvement when I wrote FJ-GL. There I do this lazily, just binding what ever texture I need at the start of every call, and using a 1px white texture for primitives.

I would suspect that with SphereGL, almost all of the time is spent binding, unbinding, enabling, and disabling texturing. Even if that wasn't happening, it's still deluging the GPU with vertices, which is generally not what you want to do.

An alternative would be to actually use UV coordinates to do hardware tiling of the texture, but the Sphere graphics driver API doesn't have that feature. Before I moved windowstyles to script in TS, this is what I did.

Hm, allegro lets me draw textured triangles via al_draw_prim(). I use this for my implementation of GradientRectangle. I should test that later...

Oh, also abysmally slow in minisphere: GrabImage. The SSFML image test runs at around 15fps. Sphere 1.5 and SSFML both handle this test with aplomb. Allegro must not like me using the backbuffer as a blit source...

Edit: I tried out the U/V hardware tiling, it seems to work pretty well, except for the SSFML Big Window test. This is what I got. Does the hardware not like tiling 1x1 textures?

Edit: I tried out the U/V hardware tiling, it seems to work pretty well, except for the SSFML Big Window test. This is what I got. Does the hardware not like tiling 1x1 textures?

Yes. I was not sprite-batching that 1x1 pixel, I was U/V wrapping it. Essentially I'm letting the gpu do the tiling rather than physically inputting the coords of the tiles, so I'm really only sending 4 vertices to the gpu while the rasterizer does an excellent job at tiling it. I apply this technique for the sides as well, don't forget those! That Big Window test should run really fast if done right. I'd love to use the U/V method to speed up my tile maps but it assumes it's the same image being repeated, and for tile maps the tiles change.

As for your error, are you sure you are tiling it correctly? It seems to tile at 16x16 rather than 1x1, don't use the corner size for the background image size.

And width and height are 1 here? I see single variables here, something has to tell it tile a 1x1 sized object in a WxH sized area.

How does Allegro do it? In OpenGL, you would just use a UV that is the number of times you want it tiled horizontally and vertically, respectively. You never need to specify the source texture's size in any way, because it's 'size' is normalized to 1.0fx1.0f before the texturing stage.

The code samples I've seen you specify pixels in the range of (0,0)-(w, h) for UV. Maybe just because Allegro is designed for 2D or perhaps a remnant of its all-SW-rendered days. I'll experiment more later.

I will say minisphere draws shorter strings much faster, but it slows down longer the string. SSFML never slows down on almost any string length.

Sphere 1.5: 4900Minisphere: 6250Sphere SFML: 7250

Edit:I'd say I'm rather pleased with the speed of minisphere. It draws things much faster than I had ever anticipated. I've NEVER seen an fps higher than 8500 on this machine in SSFML, but on my Win7 I can get to 10,000 with SSFML (weird, huh). So, it's awesome to see minisphere get 11,500+.

I assume this is RAM usage? But yeah, I'm happy see that, outside of memory footprint (which is still tiny, let's be honest here :) ), minisphere soundly kicks Sphere 1.5's ass. That was one of my main goals with the project, since Sphere 1.5 was really starting to show its shortcomings performance-wise with Specs, especially on less powerful machines. Somehow, some way, Duktape, even being all-bytecode with no JIT to speak of, is STILL more than twice as fast as 1.5's Spidermonkey.

It's also good to see that you got it to build. I was going to include the Allegro binaries in the repo, but decided it wasn't necessary since I'm just using pre-built binaries that are, at present, readily available on the web. It's just a matter of unzipping them to the proper location. I tried to make it as painless as possible other than that, as long as you're using Visual Studio anyway!

minisphere only worked with the -game parameter. I just used my Sphere Studio. Building it was easy, I just didn't know how to start running a game. The startup game had consts and so it failed, and dragging a .sgm onto the executable didn't run the game.

@LordEnglish: yes, I meant RAM. .NET apps use the CLR and .NET runtime which are memory hogs, but if I account for that I still get about 20+MB's RAM usage out of it... so it's still a memory hog (but I'm not really going to worry about that, it's just a curiosity).

minisphere only worked with the -game parameter. I just used my Sphere Studio. Building it was easy, I just didn't know how to start running a game. The startup game had consts and so it failed, and dragging a .sgm onto the executable didn't run the game..

Does drag-and-drop work with Sphere 1.5? Last time I tried I thought it didn't work, so I've always just opened stuff in Sphere Studio. I'll have to implement that now.

It's not the startup folder apparently, it's the system folder. I opened an issue, you are reading the system font without checking that it exists (maybe more things later, that's where it errors out).

It's not the startup folder apparently, it's the system folder. I opened an issue, you are reading the system font without checking that it exists (maybe more things later, that's where it errors out).

Yeah, there's a gross lack of sanity checks in here. You wonder how I implemented this all so fast, well, here's your answer. :P

I'll look into it.

Edit: Found the issue. There are no checks whatsoever in al_load_rfn_font() despite all my other loading functions having ample error checking. The crash is because it's trying to read from an ALLEGRO_FILE* that is NULL (because the file didn't exist).

Does drag-and-drop work with Sphere 1.5? Last time I tried I thought it didn't work, so I've always just opened stuff in Sphere Studio. I'll have to implement that now.

Well, Sphere was able to do this magical thing called "registering a filetype", I couldn't seem to do this easily in .net but if I implemented drag and drop, I was able to set the Engine.exe of SSFML to open on default for any .sgm related files and it worked. I can play games in SSFML by double-clicking the .sgm game icon. This is a feature I want to add to Sphere Studio too.

Well, Sphere was able to do this magical thing called "registering a filetype", I couldn't seem to do this easily in .net but if I implemented drag and drop, I was able to set the Engine.exe of SSFML to open on default for any .sgm related files and it worked. I can play games in SSFML by double-clicking the .sgm game icon. This is a feature I want to add to Sphere Studio too.

I would recommend for simplicity having the engine, when told to `run' an SPK, unpack the SPK into a subdirectory of your engine's root and run the game from there.

Or just don't do SPKs. It's a pretty silly format to begin with.

I kind of like the idea having a single file to distribute a game, and I found out I don't even have to unpack it to disk--Allegro lets me open a buffer in memory as a file (sort of like a memory mapped file but in reverse...) that I can pass to loading functions.

Of course, if we're being honest, if I weren't trying for near-1:1 Sphere compatibility I would probably just use zip instead of SPK... Well, I'll see what happens. Either way it's not a priority for a while at least.

@Radnen:Let me just say that the SSFML testbed has been invaluable in filling out the Sphere API. I'm almost at the point of being able to run all the non-map-engine tests, there's now only 2 or 3 that error out due to missing APIs. Most of my implementations have gone off without a hitch and produce identical output to SSFML and Sphere 1.5 (outside of the speed tests, which seem universally faster than Sphere 1.5)--except for the surface test.

Here's the thing: I'm not actually sure what's wrong in my implementation because I can't decipher the surface test code. It creates 4 surfaces and then proceeds to juggle them like crazy, so I don't know where minisphere is failing, but clearly something is screwed up, as you can see in the attached screenshot. The green-tinged versions of the Blockman sprite are missing, and the whole bottom row is just the green blocks without the rotated silhouette...

Most of my implementations have gone off without a hitch and produce identical output to SSFML and Sphere 1.5 (outside of the speed tests, which seem universally faster than Sphere 1.5)--except for the surface test.

I'm curious if you've tried the version of Sphere 1.6+ that I compiled with MSVC 2010 a year ago, available at rpgmaker.net/users/FlyingJester/locker/sphere16fj.zip (http://rpgmaker.net/users/FlyingJester/locker/sphere16fj.zip). I found that simply using a newer compiler made the engine between 10% and 50% faster, depending on the situation. Using slightly newer OpenGL with FJ-GL also mad many tests--particularly texturing--up to 25% faster.

I would not be too surprised if you were still faster than that, but it would still be interesting to see the results.

I was doing another round of speed tests, this time using my link library.

I have a test where I compare Link.js with Lazy.js and my old Query.js functional programming libraries. I was shocked to see Query.js outpace the other by a magnitude of 10. Lazy execution is just SLOW on both minisphere and Sphere-SFML.

// in 1.5 using 10 times less results:Link: 300msLazy: 300msQuery: 19ms

As a reminder, Query is the library I originally made that Link is based off of. The only problem is it doesn't lazy execute the chain. Safe to say, it really is fast and kicks the crap out of the other two if you need it for a tight execution loop. In a web browser, this is not the case and is actually slower by many factors (query forces through the chain n times, where n is each added operation, Link and Lazy go through the chain once).

I'm curious if you've tried the version of Sphere 1.6+ that I compiled with MSVC 2010 a year ago, available at rpgmaker.net/users/FlyingJester/locker/sphere16fj.zip (http://rpgmaker.net/users/FlyingJester/locker/sphere16fj.zip). I found that simply using a newer compiler made the engine between 10% and 50% faster, depending on the situation. Using slightly newer OpenGL with FJ-GL also mad many tests--particularly texturing--up to 25% faster.

I would not be too surprised if you were still faster than that, but it would still be interesting to see the results.

minisphere still beats it, but admittedly by a much narrower margin. Anything purely script-based though, like the Color creation benchmark, blows minisphere out of the water. That doesn't surprise me though, since I assume this is TraceMonkey or newer and not the ancient SM in 1.5.

All 1.6FJ tests are with FJ-GL. Testbed runs at 320x240. CPU is an AMD A10-6800K and I'm using the GPU built into the chip (Radeon HD 8670D).

Windows: Draws 3 windows using a windowstyle, two of them with a color mask, the second of which continuously expands and contracts. Note that minisphere currently ignores the colormask.1.6FJ: ~2230 fps.minisphere: ~2900.

So yes, minisphere is still faster at rendering, in most cases by a sizable margin. ;D

minisphere still beats it, but admittedly by a much narrower margin. Anything purely script-based though, like the Color creation benchmark, blows minisphere out of the water. That doesn't surprise me though, since I assume this is TraceMonkey or newer and not the ancient SM in 1.5.

It's the very last release without any JIT or tracing engine.

For a few things it's still the fastest JS engine I've seen--for example, the empty loop test with lower values (~1000000), probably since it's a very mature interpreter and isn't spending time running the code through any tracers or type analyzers, as modern SpiderMonkey does. In most real-world scenarios, this isn't the case, though.

Parallax X/Y is a value usually default at 1. It is the mutiplier added to the camera for the parallax effect. 1, 1 is neutral, or no movement while 2 is twice as fast, etc.

Scroll X/Y is a value usually default at 0. It is the constant speed that constantly moves the background by that amount. 2 makes it scroll fast (2 pixels), while 1 is slower (the maps FPS dictates apparent speed).

I got the map engine working! So far it can load the bitmaps from an RTS tileset and load and render a map using the proper tiles. ChangeMap works.

Oh, and just because I'm meticulous like this: I ran minisphere and Sphere 1.5 at the same time, lined up the windows, Alt+Tabbed between them and the output is identical! I wasn't sure if I got the alignment on the sprites right or not, but it looks like I did.

Awesome! The map is the most daunting part. It's not hard to do but there's certainly a lot of pieces in it. To emulate Sphere correctly you'll basically need to copy it's line intersection code for obstructions and the command queue code for movement. I'd be impressed if you manage to get lithonite.js working the way it was intended. (In SSFML it works mostly correctly besides a few edge cases... with edges!)

If you are drawing the layers to surfaces and then drawing the surface to screen, check to make sure you can do tile animations easily and fast enough. That'll be the next big step.

I didn't even bother with the extra complexity of surfaces. I just told Allegro to defer drawing and drew all the visible tiles directly to the backbuffer. See, I looked into how the deferred drawing works, and what benefits most from it is bitmap drawing--when you defer, Allegro batches all al_draw_bitmap() calls and then sends them all to the GPU at once as a single, huge triangle list. In theory this should be blazing fast without the need to cache the layers on a surface. Even more so once I implement atlasing for tilesets (currently each tile gets its own bitmap).

I didn't even bother with the extra complexity of surfaces. I just told Allegro to defer drawing and drew all the visible tiles directly to the backbuffer. See, I looked into how the deferred drawing works, and what benefits most from it is bitmap drawing--when you defer, Allegro batches all al_draw_bitmap() calls and then sends them all to the GPU at once as a single, huge triangle list. In theory this should be blazing fast without the need to cache the layers on a surface. Even more so once I implement atlasing for tilesets (currently each tile gets its own bitmap).

Ok, awesome! That actually will make animations easier to do. Tileset atlasing would also end up as a huge win, too. Allegro would be using OpenGL, and sending different texture pointers to HW is certainly a bottleneck.

Okay, whose idea was it to use line segments for obstruction? >:(. I know it's more flexible than bounding-box collision, but the crazy math required to check for intersections is insane. Nothing like rects where it's just a few comparisons and you're done. I looked at Sphere's source code and the TestSegments function alone must be at least 100 lines of code...

Line intersect is faster than pixel-perfect and can be nearly as accurate (if you map a decent contour), while bounding-box can be clunky on organic objects. That said my implementation of line intersect code is definitely not 100 lines, but then again I did abstract things away into helper classes. But even then, a hundred lines for that is a lot.

The math there is the core of it, I'm sure you can abstract lines into a struct in C and make a few helper functions. It's literally that, and for loops, checking all the lines, whether the source is a person, a tile, or a custom map obstruction line.

It's not that crazy (https://github.com/FlyingJester/TurboSphere/blob/master/bin/system/scripts/turbo/segment.js#L49), or at least it shouldn't have be. My JS implementation is totally contained inside that one file, and you'll note it's only 109 lines :)

Eventually, Chad Austin had wanted to use BSP trees for obstructions. I suspect that was a part of the change to segments.

Yeah, wow, yours and Radnen's are so much shorter and more elegant. I just checked the code in Sphere again, and this is what it looks like:https://github.com/sphere-group/sphere/blob/master/sphere/source/common/ObstructionMap.cpp#L63-L189

Even accounting for blank lines and comments, that function still has to be close to 100 lines of code.

At this point I think minisphere is just about ready for a public beta release. There are still a bunch of unimplemented APIs, but even as-is many existing Sphere games run with minimal--sometimes no--modification, so no real sense holding back anymore. So get ready, minisphere is coming! ;D

Or, you know, you could just check it out from GitHub now and build it yourself, but... ;)

update: Aquatis now runs up to the intro cinematic before erroring out due to lack of Surface:applyLookup(). So close...

Abort("ThisFunctionSucks(): This function sucks, why did you call it?", -1);

It allows you to blame the error on a script further up the call stack, useful in libraries to report invalid parameters or other such errors. If the stack offset is not provided, it defaults to 0, meaning "location of Abort call" - i.e. the normal behavior.

It allows you to blame the error on a script further up the call stack, useful in libraries to report invalid parameters or other such errors. If the stack offset is not provided, it defaults to 0, meaning "location of Abort call" - i.e. the normal behavior.

That's really awesome! In RadLib I had to do some SM only hacks to get line numbers and report the penultimate function call in the call stack. This would undoubtedly make that process much easier under your engine. +1

See, the whole thing was kind of a happy accident - by default Duktape reported Abort-generated exceptions as coming from api.c, since that's where the duk_error() call is. In order to get it to show the script file that aborted instead, I had to call into Duktape to walk a step or two up the stack and then use duk_error_raw, which lets you override the file name and line number of the thrown exception. Of course, since I now had full access to the callstack, well... :)

Trivial. The stack offset on Abort isn't required to be -1, it can go all the way up the stack if needed and even gives line numbers. The functionality I use to do it--Duktape.act()--is even exposed to script, so as long as minisphere uses Duktape, the entire callstack will available to scripts at any time.

I have to say, Duktape doesn't look like much, but it's actually a pretty awesome little JS engine. It definitely took me by surprise.

Just implemented atlasing for RFN fonts. The original implementation used individual ALLEGRO_BITMAPs for each glyph, which I suspect was the main reason for minisphere's horrible text-rendering performance up to now. The drag became especially noticeable in Spectacles when the console was displayed. Now it seems to be much better!

Just implemented atlasing for RFN fonts. The original implementation used individual ALLEGRO_BITMAPs for each glyph, which I suspect was the main reason for minisphere's horrible text-rendering performance up to now. The drag became especially noticeable in Spectacles when the console was displayed. Now it seems to be much better!

Awesome!

Were you able to figure out the windowstyle issue? I know it may break on 1x1 sized images, but what about 2x2 or larger?

See, the odd thing is, that big window test? It displays fine if I force Allegro into OpenGL mode. It's only with D3D (Allegro's default under Windows) that the issue shows up. I'll have to test with larger backgrounds though. Honestly I haven't really worried about it since nobody's going to be using 1x1 windowstyles in a real game and the more typical sizes seem to render fine.

So I just finished implementing zones, which completes the map engine. ;D. Still missing APIs I'm sure, but the map engine itself is, as far as I can tell, a complete functional recreation of Sphere's.

Now... what exactly do I need to do to get Lithonite working? It seems to work somewhat in minisphere, but many of the zone types are completely non-functional and others are glitchy--for example slopes cause me to get stuck in diagonal movement eternally, and jumping off ledges makes my guy fly off the map completely out of my control. Since the APIs Lithonite needs are all implemented and should be behaving identically to Sphere, I fail to understand what is causing the glitches.

Also: Lithonite reminded me that I never actually implemented tile animation... I should get on that!

So that didn't take long--I got Lithonite working! :D Little-known fact about SetDelayScript(): Despite the name of the function, it actually queues scripts, rather than setting one at a time. Not supporting this was the reason it didn't work for me, and likely the reason it doesn't work properly in SSFML either--it only tracks one delay script at a time.

Also I really need to implement more of the API esp. zone and trigger execution nuances, etc. I just need to find the time sometime to do it.

I have to say, recreating Sphere like this, I have a new respect for the built-in map engine. I always wrote it off because of the all the bugs in the Sphere 1.x implementation, but now I think it's pretty great. The fact that minisphere fixes a lot of the aforementioned bugs (some of them without conscious effort on my part even) makes it that much more awesome.

What's the best way to implement tile animation? My current implementation just does a brute-force traversal of the map, counting frames for each tile and switching them in-place, but I have a feeling this is going to end up being a performance drain on larger maps. I looked at both SSFML and Sphere's source, but I can't make heads or tails of the lookup method either one uses. Care to enlighten me?

Edit: Okay, I really need to shut up. :-X Leave me to my own devices for an hour and I figure stuff out every single time. Instead of traversing the map, I set up a system where I walk the tileset and, at render time, remap the tile indices passed in from the map engine to their current animation state. Funny thing about it: I ended up looking at the Sphere source again after doing this, and it turns out Sphere uses this exact same system, the code for it is just a lot sloppier.

Edit: Okay, I really need to shut up. :-X Leave me to my own devices for an hour and I figure stuff out every single time. Instead of traversing the map, I set up a system where I walk the tileset and, at render time, remap the tile indices passed in from the map engine to their current animation state. Funny thing about it: I ended up looking at the Sphere source again after doing this, and it turns out Sphere uses this exact same system, the code for it is just a lot sloppier.

Sane here. I walk the tileset, find the correct timings (just once), and then just use them at the appropriate time intervals. I only update the timings when the user sets the tile animation in code.

BTW I just want to add between you me and FJ, working on our own engines has really helped us see how Sphere works internally and I'd say we'd all know at this point how to hack sphere into submission JS code-side. ;)

Speaking of tilesets, I just implemented tile atlasing! My refcounted image system really helped here, I just have it create subimages off of the atlas, then free the atlas--when the last subimage (tile) is freed, the atlas gets freed automatically. The best part is that the subimages are normal image_t pointers, so the atlas doesn't even interfere with things like SetTileImage, which can just free and replace the image pointer as normal.

Well, minisphere has been a far bigger success than I ever anticipated. Not only does it beat Sphere 1.5 in performance hands-down, but it runs the vast majority of existing Sphere games better than Sphere does. I've known Sphere was buggy for quite a while, but I never realized it was quite this bad until I started comparing the two engines side-by-side later in development.

This is the part where I'll be honest: minisphere's development was largely motivated by self-interest. After I finished the Spectacles battle engine, I started work on the field, and then realized that Sphere's map engine doesn't react well at all to blocking logic, UpdateMapEngine be damned. For the longest time I thought it was a bug in the Specs threader, but no, it turns out it has something to do with Sphere's frameskipping logic causing it to skip a ton of FlipScreens (exactly equal to the number of frames spent in the MapEngine loop, interestingly enough), which I didn't fully realize until I got minisphere's map engine up and running and the threader behaved just fine there.

Whatever the case, I'm confident to say that the version of minisphere as it exists on GitHub right now is quite suitable as a drop-in replacement for Sphere 1.5. I'll be posting minisphere 1.0b2 soon. It would be a release candidate instead of a beta, but I haven't implemented networking support yet. I want to at least do that before going gold with 1.0.

This is the part where I'll be honest: minisphere's development was largely motivated by self-interest.

So was TurboSphere. I was frustrated by not being able to do N-body physics and 3D matrix transformations in script, and I was disappointed in the polygon drawing performance.The best engines solve actual problems that you run into :)

New API function: IsSkippedFrame(). This returns true if the next FlipScreen will be ignored, allowing the game to skip rendering for a frame to maximize the effectiveness of frame skipping. The engine already does this internally for primitives and blits (except for render-to-surface, which is exempt for obvious reasons), so figured I may as well expose it to script. :)

Since you've implemented the map engine, can you run my NShoot demo, Artyxx (https://github.com/apollolux/artyxx) in minisphere? I want to find out if the issues it had in vanilla 1.5 still exist, since I know that I also had sloppy code at the time (e.g. wrote an unoptimized particle system script NPart b/c the beta ParticleSystem didn't have collision or the ability to access individual particles for me to script collision myself) but was running against a whole bunch of map engine ridiculousness too.

Hm, seems I can't even get past the intro. minisphere fails with "invalid base value" (I haven't located the cause yet, but basically this is Duktape's obtuse way of calling out attempts to use undefined as an object--probably due to an API I haven't implemented yet), and Sphere 1.5 fails at the same point with an error on SetLayerRenderer (invalid integer "Base" for argument 1).

So one thing that always bugged me about the Sphere map engine is that maps smaller than the screen are rendered aligned to the top-left corner of the screen. Well, I've fixed that: Small maps will be centered in minisphere, as shown in the screenshot below.

Edit: Also, just because of how awesome this is: One of my most recent changes was to massively improve the CPU usage of minisphere under framerate throttling. As you can see in the second screenshot here, my 2nd gen i5 is barely breaking a sweat running minisphere at 60fps without skipping a single frame. See, when there's time left over after a frame, instead of uselessly spinning, the process actually goes to sleep via al_wait_for_event_timed(), greatly reducing its CPU footprint. Of course, this doesn't apply if framerate throttling is off--at that point there's obviously nothing I can do.

Heh, you know most of the awesomeness with minisphere has a lot to do with, well... allegro being awesome. :P

This truly is a light-weight and fast implementation of Sphere! Can't wait to see full parity with the Sphere catalog. And as a bonus since allegro is so awesome there might be a future when minisphere get's a more decent engine like V8, but in the meantime this simply seems good enough.

And as a bonus since allegro is so awesome there might be a future when minisphere get's a more decent engine like V8, but in the meantime this simply seems good enough.

Yes, unfortunately Duktape is the weak link here. For what it is (a lightweight, easy-to-embed JS engine, basically the JS answer to Lua) it's great, but there are some issues. Namely, compiling scripts, even tiny delayscripts, is slow, even compared to Sphere 1.5's SpiderMonkey. This means that anything that abuses delayscripts--like, say, Lithonite--is going to take a pretty noticeable performance hit. Of course this can be alleviated in new games if I allow SetDelayScript and friends to take a (already-compiled) function as argument, but this does nothing to help games using the older method.

Not only that, but games with large codebases, for instance Trial & Error and Aquatis, cause a pretty painful delay on startup while all the scripts are compiled.

So I was going to wait until after releasing 1.0b2 to do this, but I had some free time today and implemented the networking API. For this I used a tiny asynchronous networking library called Dyad (https://github.com/rxi/dyad), which is essentially just a thin wrapper over the target platform's native sockets implementation (e.g. Winsock for Windows, BSD sockets for other platforms) and adds only about 3k to the engine executable's size.

Haha, what can I say, I'm very motivated. :D. For what it's worth, I'm getting very close to a 1.0 release, but I need some outside testing to happen first, particularly with regard to joystick support, which I couldn't test myself as I don't have a gamepad handy.

I'm thinking I might need to make some enhancements to the networking API, though. As implemented in Sphere (and minisphere), it's very barebones and lacks basic functionality--for example, there's no way to tell from script when a socket has finished receiving data.

I think the networking API is very close to what it should be. I rather think it should basically be the same as the BSD socket API, which it almost is. Mainly, I believe that there should be an "Accept" function in addition to "ListenOnPort".

Ignore me on the finished receiving thing. I didn't do enough research into how sockets work to realize that there was no built-in facility for the receiver to know when the other end has sent a full response (for instance, a full HTML doc), it's just an open data channel.

...and yes, that means I somehow successfully implemented networking without knowing a thing about how sockets work. :P

As for SCons, can I cherry-pick only the SCons stuff somehow? The rest of the commits in that pull would probably be a very bad idea to merge in at this point. I may just have to close the pull and import them manually.

Ignore me on the finished receiving thing. I didn't do enough research into how sockets work to realize that there was no built-in facility for the receiver to know when the other end has sent a full response (for instance, a full HTML doc), it's just an open data channel.

...and yes, that means I somehow successfully implemented networking without knowing a thing about how sockets work. :P

As for SCons, can I cherry-pick only the SCons stuff somehow? The rest of the commits in that pull would probably be a very bad idea to merge in at this point. I may just have to close the pull and import them manually.

I do know there is a way to cherry-pick certain commits, using a command literally called `git cherrypick', but I don't recall exactly how it works. I haven;t had to do that since last summer.

I can just make up some new SCons files. There are new source files to account for, anyway. It's probably easiest that way.

Re sockets, you are guaranteed that write commands are not broken when they are read on the other end, even if the amount sent is greater than what a literal packet can hold. You are only in danger of having multiple responses queued up and not being able to distinguish where one ends and another begins. This is almost always solved by the application.

And I believe that anything more is totally up to the application, and really should only be in script in a Sphere-like environment. Only holding the BSD API allows Sphere-like engines to talk to any kind of server and be any kind of server. Any extension of this by the engine in native, I believe, puts this in danger.

So I see what you mean about the lack of any kind of Accept() function for listening sockets. As it's implemented in Sphere, a socket created via ListenOnPort is literally replaced by the first thing to connect to it, meaning trickery like this is required to run an actual server:

So I made some improvements to the networking API as suggested by Jester:

ListenOnPort() now takes an optional second parameter, max_backlog. If not provided, it defaults to zero, which causes the socket to behave as in Sphere 1.5, closing the listener and replacing the socket in-place with that of the first client connection. If max_backlog is greater than zero, it acts as a BSD socket, and the script must call the new Socket:acceptNext() method to get socket objects for new client connections. If acceptNext() is not called periodically, any pending connections past the size of the backlog will be automatically dropped. The listening socket remains open as a listener until closed.

The way this was done, it's fully backwards compatible with the Sphere API and only adds one new method. :)

Edit: Okay, I fibbed. There are 3 new methods: The aforementioned acceptNext(), getRemoteAddress() and getRemotePort(). It's good to know who's connecting to your server, methinks. :P

At this point I have to recommend Sphere developers use minisphere over vanilla Sphere if possible. Only a few APIs are unimplemented (particularly oddball stuff like color matrices), and minisphere is not only faster, but in my testing at least, less glitchy than Sphere 1.5.

Oh, and NEO: After a few necessary minor edits to the code, your Artyxx demo works great in minisphere. 8)

At this point I have to recommend Sphere developers use minisphere over vanilla Sphere if possible. Only a few APIs are unimplemented (particularly oddball stuff like color matrices), and minisphere is not only faster, but in my testing at least, less glitchy than Sphere 1.5.

I will say the only outstanding issues are discrepancies between SpiderMonkey and ECMA5.1, such as const and error constructors and other wacky additions Mozilla decided to add. Since my RadLib library has lots of this intrinsic stuff I'll have to spend time converting it. But yes, I should update my code rather because ECMA complacent JS ideally works anywhere ECMA is supported: it's the smallest subset that's considered correct JS.

Good news: I posted an issue on Duktape's GitHub repo regarding the lack of a reported filename for syntax errors, and the dev fixed it. So now minisphere reports the exact location of syntax errors, making it easier to locate consts that need to be changed. :)

That makes no sense because Sphere 1.5 has no accept() method for listeners and (from what I can tell) the listening socket closes as soon as someone connects to it, at which point the object becomes (i.e. is internally mutated into) a normal bidirectional socket. Sphere might set a backlog of 16 internally, but the way the API is exposed, it effectively can only accept a single connection. Hence the zero default in minisphere to specify the legacy behavior.

Note that the actual backlog on a socket is likely going to be larger than whatever you pass to ListenOnPort() for the second parameter anyway because Dyad is set up to accept() connections automatically--I get a callback with the new socket only after this has been done for me. Which means minisphere can't actually reject any connections--it has to disconnect them after they've already been established if its own backlog is full.

Do connections close properly when Sphere shuts down? One thing I noticed is that when I made networked games in Sphere 1.5, and you hit the X button or Alt+F4 out of the app, you couldn't close open files, connections, etc.

In fact it'd be nice to have access to that as a new feature. The "on close" or "shutdown" callback.

All native-implemented objects in minisphere have finalizers and Duktape guarantees they will be called on shutdown if the GC hasn't done so already. Duktape also uses refcounting in addition to mark-and-sweep, so in most cases you don't even have to wait for an object to be collected when it goes out of scope--it's finalized immediately. Short of a segfault (or refcounting bug in minisphere--I've encountered these before and they're not pretty), you're not likely to leak resources in minisphere.

That said, a shutdown callback could be useful. I'll consider implementing such a thing.

minisphere 1.0b4 is up. No new APIs this time around, just under-the-hood changes. Much of the architecture was rewritten, however (I now use fopen instead of Allegro's file routines, for example), so I thought it was good to push out another release so I could get some testing in.

That makes no sense because Sphere 1.5 has no accept() method for listeners and (from what I can tell) the listening socket closes as soon as someone connects to it, at which point the object becomes (i.e. is internally mutated into) a normal bidirectional socket. Sphere might set a backlog of 16 internally, but the way the API is exposed, it effectively can only accept a single connection. Hence the zero default in minisphere to specify the legacy behavior.

That's not what that number means. Setting that number to zero in Linux or BSD will result in no connections whatsoever being accepted. If any are accepted with winsock, that is a bug in winsock or a misinterpretation of the BSD API. Setting that number sets the number of connections that can exist waiting on listening socket, waiting for an Accept. Setting it to zero means that there can be zero sockets ready to be accepted, the queue has a size of zero and will always be empty.

That makes no sense because Sphere 1.5 has no accept() method for listeners and (from what I can tell) the listening socket closes as soon as someone connects to it, at which point the object becomes (i.e. is internally mutated into) a normal bidirectional socket. Sphere might set a backlog of 16 internally, but the way the API is exposed, it effectively can only accept a single connection. Hence the zero default in minisphere to specify the legacy behavior.

That's not what that number means. Setting that number to zero in Linux or BSD will result in no connections whatsoever being accepted. If any are accepted with winsock, that is a bug in winsock or a misinterpretation of the BSD API. Setting that number sets the number of connections that can exist waiting on listening socket, waiting for an Accept. Setting it to zero means that there can be zero sockets ready to be accepted, the queue has a size of zero and will always be empty.

Setting it to one is much more correct.

I know what the backlog is. I researched sockets after implementing the networking API to better understand how everything works.

Here's the thing: The Dyad library I'm using for networking manages it for me. From what I can tell, Dyad by default sets a backlog of 511 and accepts connections for me, it's just that, for compatibility reasons, I defined zero passed to ListenOnPort() (NOT winsock) to be a sentinel meaning "make this socket behave as in Sphere 1.5". It doesn't mean the actual backlog is zero--that would be nonsensical!

Long story short: minisphere still accepts connections past the backlog value passed to ListenOnPort, it just drops them immediately if it's own backlog is full. Understand now?

Okay, so heads up: Next release of minisphere will include at least the following as system scripts:

analogue.js (Radnen)

kh2Bar (me!)

Link (Radnen)

MultiDelegate.js (me again!)

Scenario (totally me! ;) )

I may add more, but these five seemed like good candidates for essential functionality to include in the default distribution.

I'm removing all the old legacy cruft that the system scripts folder comes with in vanilla. I haven't seen a game yet that uses any of them, and at least half of them are broken or incompatible now anyway. They're just dead weight at this point.

The three that I know are used at least sometimes are circles.js, time.js, and colors.js. I would leave at least those. Colors just needs a working CreateColor (I modified the one included with TurboSphere to use the color constructor), time.js just needs GetTime(), and circles.js needs Surfaces that have the circle primitive methods.

On the other hand, I really recommend exposing a Delay function that replaces time.js from the engine itself, as TurboSphere does, to allow games to not use 100% of the CPU even when idling.

On the other hand, I really recommend exposing a Delay function that replaces time.js from the engine itself, as TurboSphere does, to allow games to not use 100% of the CPU even when idling.

Way ahead of you on that one. I already implemented Delay() a few days ago, it will be in 1.0b5. Keeping CPU usage down is one of my main concerns with minisphere. I hate that Sphere 1.5 maxes out a core the whole time it's running, which is why I implemented the timed sleep after FlipScreen a few betas ago.

Well, after 2 months of nonstop coding, minisphere 1.0 has been released! ;D There's still a handful of Sphere APIs missing or unimplemented, but no real showstoppers, so I figured now was as good a time as any for the 1.0 release.

See the OP to download and go crazy! Don't forget to report bugs as I'm sure there's a ton of them... :P

How high is the warning level on MSVC turned up for you? You have on bazillion implicit-int and default-return warnings now...it wasn't like that before.

I opened another pull request. I had to remove min/max again, and itoa is nonstandard and does not exist outside MSVC and GCC, but it's just a few lines different, plus the SCons files. The bare minimum to confirm that everything is compiling correctly.

How high is the warning level on MSVC turned up for you? You have on bazillion implicit-int and default-return warnings now...it wasn't like that before.

I opened another pull request. I had to remove min/max again, and itoa is nonstandard and does not exist outside MSVC and GCC, but it's just a few lines different, plus the SCons files. The bare minimum to confirm that everything is compiling correctly.

The warning level is whatever MSVC's default is. It doesn't usually warn for implicit conversions, so I don't bother with casts. I'm trying to keep those to a minimum anyway to make the code easy to read; if given the choice between cluttering up the code with casts or putting up with warnings, I'll generally choose the latter. If I wanted to have to cast everything I'd be using c++ not C...

Long story short, I find implicit conversion warnings patronizing. :P

A min/max snuck back in? I've been using fmin/fmax... Must have been a brainfart on my part.

The default returns are actually spurious and can be ignored. There is no platform-independent way to declare a no-return function so I just put up with them. duk_error_ni() calls duk_error_va_raw, which calls longjmp and thus doesn't return. The compiler isn't smart enough to figure that out though, so you get warnings. Before I was calling the built in duk_error directly, which IS declared no-return, which is why you didn't get them before.

Well as you can see, Jester got it to compile under OS X, so in theory nothing should be stopping it from compiling in Linux either. I tried to write the code to be as portable as possible, and libraries were also carefully chosen to this end (Allegro, Duktape and Dyad are all supposed to work on at least the Big 3). Unfortunately Win8.1 doesn't appreciate dual boot configurations and I don't have a spare computer, or I would have tried this myself in Ubuntu.

@Flying Jester:Well, I experimented with raising the warning level in MSVC from level 3 to level 4, and got a ton of spurious warnings, so I'm thinking I will probably lower it again. What irks me most is all the C4706 warnings (assignment within conditional expression) from perfectly idiomatic lines like this:

That code is perfectly clear in its intent, the warning is not needed. And sure, I could go around disabling warnings individually, but that starts to defeat the purpose of the higher warning level, so I might as well just leave it at level 3 where it compiles cleanly. I think the low number of major bugs putting together an engine this fast speaks to the fact of me knowing what I'm doing here without the compiler complaining at me. :P

Also: Don't ever try to compile a Win32 app in MSVC with -Wall - You will get a crapton of warnings (as in, tens of thousands! :o) just from the Windows headers alone.

This is bad. Not respecting constness is undefined behaviour, as well. If you cannot avoid it then you should add a cast.

...anyway...

In some cases it is telling you that you are not following the standard, but the compiler is willing to let it slide, such as in the default-int, const-incorrectness, and non-returns. The compiler could quite validly deny this code even to compile. These are the ones I'm properly worried about, because a standards-compliant compiler may or may not actually compile it.

The functions with no return type I discovered myself during my foray into /W4, those were accidental and I'm not even sure how that happened. I must have been falling over tired when I wrote something like static js_BindJoystickButton. I fixed it in my latest commit.

As for const-correctness, from what I understand - if we're being technical about it it's not undefined behavior to cast away constness (C++ has const_cast for a reason), it's only UB if you write to an actual constant. I'm not saying this isn't a potential source of bugs of course, just want to dispel any misconceptions. That said, const-correctness is something I do take seriously (if you look at the code, I declare a good number of const pointers myself), but if MSVC doesn't warn me about it, I may not always catch violations. But even with /W4, I don't get any such warnings, and /Wall is just unfeasible as mentioned above. Clang must just be REALLY pedantic.

I did fix the no-return functions in the latest commit, I added a noreturn macro so I can now use noreturn in place of a return type. I wasn't aware GCC would accept the __attributes__ before the function declaration, I thought it had to go after, which would have complicated the macro. Thanks for the tip. :)

Oh, and regarding that const violation on line 267, I'm thinking that came about due to confusion with strrchr, which is defined, at least in MSVC, as:

That's my biggest peeve about MSVC. Its standard library tends to take the standard a little loosely, and unlike the GCC and Cland standard libraries it doesn't offer warnings when you use nonstandard functions.

As for const-correctness, from what I understand - if we're being technical about it it's not undefined behavior to cast away constness (C++ has const_cast for a reason), it's only UB if you write to an actual constant. I'm not saying this isn't a potential source of bugs of course, just want to dispel any misconceptions. That said, const-correctness is something I do take seriously (if you look at the code, I declare a good number of const pointers myself), but if MSVC doesn't warn me about it, I may not always catch violations. But even with /W4, I don't get any such warnings, and /Wall is just unfeasible as mentioned above. Clang must just be REALLY pedantic.

Clang doesn't joke around :D That's why I am so happy that TurboSphere compiles with -Wall -Werror with both GCC-compatiblity and pure Clang mode.

Sorry guys, I'm going to have to pull 812.8.2 at midnight. It seems everyone that tested it ended up getting eaten by that hunger-pig at 8:12pm. :'(

...April fools! There was no 812.8.2 version of minisphere with awesome 3D rendering, I made it up (not that it wasn't entirely obvious anyway, haha). ;D. I did post a real bug fix release today though (1.0.3), in case anyone missed it.

Odd, I can't get Kefka's Revenge to run in minisphere. I get an error loading jewtheblue.bmp, which doesn't make sense since Allegro is supposed to support BMP.

Edit: Figured it out, the offending image is actually a PNG image saved as .bmp (Thank goodness for hex editors!). Allegro apparently doesn't appreciate the file extension being changed, while Corona doesn't seem to mind. I'm debating whether I should code in a workaround for this or just leave it alone and make a note in the readme... I'm leaning towards the latter.

Edit2: Aww, looks like KR isn't going to run in minisphere any time soon as it uses the animation API, which I currently have no means of supporting.

Edit: Figured it out, the offending image is actually a PNG image saved as .bmp (Thank goodness for hex editors!). Allegro apparently doesn't appreciate the file extension being changed, while Corona doesn't seem to mind. I'm debating whether I should code in a workaround for this or just leave it alone and make a note in the readme... I'm leaning towards the latter.

AFAIK corona uses the file contents to verify the data, while a lot of libraries tend to use the stupid file extension. Our Sphere engines for example can load rws files without .rws appended to it. Using the first 4 chars to verify the filetype.

Odd, I can't get Kefka's Revenge to run in minisphere. I get an error loading jewtheblue.bmp, which doesn't make sense since Allegro is supposed to support BMP.

Edit: Figured it out, the offending image is actually a PNG image saved as .bmp (Thank goodness for hex editors!). Allegro apparently doesn't appreciate the file extension being changed, while Corona doesn't seem to mind. I'm debating whether I should code in a workaround for this or just leave it alone and make a note in the readme... I'm leaning towards the latter.

Edit2: Aww, looks like KR isn't going to run in minisphere any time soon as it uses the animation API, which I currently have no means of supporting.

It uses MNG for only a select few things, like the little dragon morph animation on the title screen. Maybe they could simply be stubbed?

Oops, that was some of my earlier code, while I was still in JS mode, I accidentally declared the index variable in the for loop itself, which is illegal ANSI C and requires the compiler to be in C99 mode to compile successfully. It's odd though, that SCons script should be exactly what Jester used to get it to build, I haven't modified it...

It seems to have compiled all the source files into object files, but then fails at the next step... Am I missing a dependency, perhaps? I checked, but there's no libfmod in the package repository (Ubuntu), so I'm not sure how to proceed...

Speaking of dependencies, could you please list them in an INSTALL file or something? I noticed I needed liballegro5-dev liballegro-audio5-dev liballegro-image5-dev and installed the other allegro 5 packages just to be sure that I got all appropriate dependencies too, but I'm not sure what else is necessary. All the Allegro libs I am now noticing in the first line in the log up here, I suppose?

fmod is a standard C function (floating point modulo). No idea what's going on there, but it's nothing to do with minisphere itself, that's for sure.

As for dependencies, Allegro 5 should be the only one. You were right to install the whole shebang there, as I'm pretty sure I use the majority of them. My only other two dependencies are Duktape and a small networking library called Dyad, both of whose .c files are included in the project.

Sorry for the lack of build documentation, I'm a Windows developer by nature so I'm used to having a nice IDE (read: Visual Studio) take care of everything for me. I'd much rather write code for my own program than my build tools, thank you. :P

I tried running Sir Boingers. It ran the main menu just fine (after changing all const keywords to var and resaving some scripts as UTF-8).

There is a bug, however: when I try entering the game, or other parts of it, it errors out. Except since I use the space bar, the window closes almost immediately and I can't read the error message at my leasure. Could you perhaps add a short delay (like half a second) before reading the space bar input, or only start checking for it once the last in-game keypress has been released?

Also, after taking a quick screenshot while the error displayed, it turns out it couldn't load the map. (default/tutorial.rmp). Do you know what's up with that? Is it because it's in a subfolder (maps/default/tutorial.rmp)? And do you think you could output the error to the console too?

Edit: just noticed it plays back the menu sound effects only once, too. Is it because I'm stopping the last instance and then immediately playing it back again, perhaps?

I tried running Sir Boingers. It ran the main menu just fine (after changing all const keywords to var and resaving some scripts as UTF-8).

There is a bug, however: when I try entering the game, or other parts of it, it errors out. Except since I use the space bar, the window closes almost immediately and I can't read the error message at my leasure. Could you perhaps add a short delay (like half a second) before reading the space bar input, or only start checking for it once the last in-game keypress has been released?

Also, after taking a quick screenshot while the error displayed, it turns out it couldn't load the map. (default/tutorial.rmp). Do you know what's up with that? Is it because it's in a subfolder (maps/default/tutorial.rmp)? And do you think you could output the error to the console too?

Edit: just noticed it plays back the menu sound effects only once, too. Is it because I'm stopping the last instance and then immediately playing it back again, perhaps?

Which OS is this? If anything other than Windows, I'm impressed you got this far, it means I did something right! ;D Still, I'd like to diagnose some of this stuff. I'll go get the game in question and see what I can do.

As for the spacebar to close the error, I originally made it so you had to press Escape to close it, but added the spacebar option for convenience. Maybe I should go back to just [Esc] to close out.

Also, after taking a quick screenshot while the error displayed, it turns out it couldn't load the map. (default/tutorial.rmp). Do you know what's up with that? Is it because it's in a subfolder (maps/default/tutorial.rmp)? And do you think you could output the error to the console too?

Edit: just noticed it plays back the menu sound effects only once, too. Is it because I'm stopping the last instance and then immediately playing it back again, perhaps?

Figured out the map issue after stepping through the map load function with the debugger a few times. The map itself loads just fine, it's actually the tileset that causes the load failure. Good call on the subdirectory thing: It turns out the tileset filename stored in the RMP file is relative to the directory containing that map--whereas minisphere assumes it's always relative to <gamedir>/maps. So yeah, having the map in a subdirectory tripped it up. Shouldn't be too difficult to fix. 1.0.5, here we come!

As for the sounds, I have noticed a few issues with sound myself, but I haven't been able to pin down the cause yet. Either I'm doing something wrong or Allegro's audio routines are glitched. I'm thinking more the former, though... ;) The sound stuff was actually one of the first things I implemented way back in the beginning of minisphere's development (yes, my priorities are odd, don't judge me! :) ), so the code could probably use another go-over.

Edit: So apparently minisphere doesn't like playing the same sound more than once, despite the explicit al_seek_audio_stream_secs(stream, 0.0); in js_Sound_stop(). Further investigation will be needed. I didn't notice this before because all my sound-playing in Specs is done through Scenario's built-in playSound scenelet, which loads sounds anew each time they're played. I never bothered to implement caching for that scenelet...

Edit2: Damn it, best I can tell it's a race condition in Allegro. This is my working theory: Allegro apparently runs the stream in a separate thread. When you call the stream functions, it queues the operation to be done on the worker thread. So even though I've queued a rewind, I also call play immediately afterwards. I'm guessing Allegro processes the play operation before the seek, so it immediately stops again as it's still at the end of the stream.

Edit3: Aaand I was right. When the stream ends "naturally" (manual starts and stops don't seem to affect it), the stream feeder thread terminates and never gets restarted unless you recreate the stream. Looks like it was an Allegro bug after all!

Big problem. I can't run Blockman in it because it has trouble parsing all the code files. I got it to stop spewing syntax errors due to my use of const, but now it's giving me a 'not callable' issue that I cannot resolve.

The above works 100% in minisphere. Then why the error? In Blockman I use the above pattern on hundreds of files and at some point it starts saying not callable on a myriad of functions using this design pattern. This games runs just fine in Sphere 1.5 and SSFML, but it gives me not callable issues on what are seemingly normal function calls.

This happens because the analyzer thought these functions were somehow set to not callable, when in fact they are. I'm not sure if it's a scoping thing either because if it were, the first two tests would fail since the function in question could not be found. So this is really weird indeed.

Odd, sounds like a Duktape bug. I could post an issue on the Duktape repo, but I'd need a use case that can reproduce it reliably. But from the sounds of things I'm guessing you can't reproduce it on command...?

By the way: minisphere includes an Alert() function that just throws up a message box without terminating the game. Might be useful for these little testcases.

edit: also where can I get the latest Blockman? I have an older copy right now from the Spherical Downloads drive, which is actually one of the games I used for compatibility testing. :-). But that version seems to run just fine, so I'm unable to reproduce this issue with it.

Interesting, I stepped through the internal call code inside Duktape for the offending call, and it successfully gets into the bytecode for constructor. So this "not callable" error is very baffling, since it actually does call the function...

Dammit, I just figured out: the error is misleading. I have an error callback that modifies the filename and line number for error messages starting with "not " because otherwise Duktape doesn't report that info for invalid parameters. The callback uses the info from one step up the call stack, which means the error is actually inside the constructor. I will keep investigating.

Edit: Yep, I sent us both on a wild goose chase. I fixed the error callback to pass through "not callable" errors and here's the actual offending line of code:

Well, several fixes (and const removals) later I got it to get to the main menu, but I can't move the cursor or even confirm my selection. Apparently something's borked with my input routines... which is odd, since input seems to work fine in every other game I've tested.

Yeah, I didn't fix the map loading issue yet. I got sidetracked trying to get Radnen's game running. :P. I'll do the fix later today, it shouldn't take too long. Just have to extract the directory info from the map path and prepend that to the tileset name and I should be golden.

Ah, okay! Sorry to be premature, I saw updates and just assumed. :P In the meantime, I found another crash (http://i.imgur.com/uV04vlt.png) when trying to open either option 2 or 3 in the menu. I'm not sure what's going on because the offending line looks rather innocent:

Well, several fixes (and const removals) later I got it to get to the main menu, but I can't move the cursor or even confirm my selection. Apparently something's borked with my input routines... which is odd, since input seems to work fine in every other game I've tested.

SSFML uses a slightly different keymapping. Rename Options2.ini to Options.ini and it'll be set to use the keymaps for Sphere 1.5. I really need to manually change the keymaps, I wonder, do you use 1.5's keymaps?

I sent Minisphere 1.0.4 to a friend and she sent the following error message back:

(http://i.imgur.com/zjX9YU2.jpg)

Note that I renamed the file to Sarah.exe, put the game in startup, and the only other folder was system. It worked on Wine so I wouldn't assume it wouldn't even run on her system. I have no clue what this error means at all either.

I found this blog post:http://blogs.msdn.com/b/vcblog/archive/2009/08/27/windows-sdk-v7-0-v7-0a-incompatibility-workaround.aspx

A bunch of Win32 APIs were apparently shuffled around in Win7. It looks like the fix is as simple as defining a preprocessor macro. That's a simple enough thing to do, I'll add this to the queue for 1.0.5. The next release is getting a ton of fixes! :D

Alright, 1.0.5 should relax the Win7+ requirement. It was the MSVC 11 build of Allegro I was using. I linked minisphere against the MSVC 9 libs and K32GetModuleFileNameExA disappeared from Dependency Walker. :)

I also fixed the maps in subdirectories issue, but now I'm getting an "invalid base value" error whose cause I can't pin down. It can never be simple, can it...

@Radnen: OOH, I see what you mean about the mappings now. I opened the options file, and saw this line:

...and suddenly understood jack everything. :P See, minisphere uses Allegro's key constants directly, it doesn't remap them. Obviously those values are different than whatever Sphere 1.5 defines them as. I never thought it would be an issue since I expected games to always use the named constants, but didn't account for the possibility of keys being saved out to a file...

I never thought it would be an issue since I expected games to always use the named constants, but didn't account for the possibility of keys being saved out to a file...

Yeah, the game has the ability for you to set your own key mappings.

I added the ability for the game to recognize default keys on startup. If no options.ini is available it'll fill it out with the correct keys on first run. If you switch sphere engine, just delete options.ini and it'll re-scan the keys again.

Okay, that did the trick, now I can select stuff from the menu. Unfortunately, now I'm getting the same error as in DaVince's game: Invalid base value, with no filename or line number to indicate where the issue is. What fun...

Radnen, you'll be happy to know I just got Blockman to run in minisphere. ;D There do appear to be a few glitches, though--such as persons occasionally "jumping" from one place to another during cutscenes instead of moving smoothly, and some camera jerkiness. Not sure what's causing that.

However, there's unfortunately one thing that prevents it from being fully playable: FollowPerson is not implemented. I've been putting that off forever... I knew it would come back to bite me eventually. :(

Radnen, you'll be happy to know I just got Blockman to run in minisphere. ;D There do appear to be a few glitches, though--such as persons occasionally "jumping" from one place to another during cutscenes instead of moving smoothly, and some camera jerkiness. Not sure what's causing that.

However, there's unfortunately one thing that prevents it from being fully playable: FollowPerson is not implemented. I've been putting that off forever... I knew it would come back to bite me eventually. :(

Yeah, I've been wanting to write my own FollowPerson rather than use Sphere's anyways. :P So once you do fix it, I might not use it. There is only 1 instance in the game FollowPerson is used, and it's optional to follow that person.

Radnen, you'll be happy to know I just got Blockman to run in minisphere. ;D There do appear to be a few glitches, though--such as persons occasionally "jumping" from one place to another during cutscenes instead of moving smoothly, and some camera jerkiness. Not sure what's causing that.

Well, that was a hell of a ride. 1.0.5 is done. This release represents a huge chunk of maintenance and fixes about 7 different bugs. Most of them were pretty minor in the grand scheme of things, but they were enough to prevent a lot of games from running, so fixing them is important.

@DaVince: Could you have your friend try minisphere on Vista again, this time with 1.0.5? I'm pretty sure the Win7+ requirement is gone, but I don't currently have access to a Vista or XP machine to know for sure. Also: Sir Boingers now (mostly) works. It tends to error out on death/damage though, due to the stricter type checking in minisphere (this is mentioned in the readme). With a few edits to the game itself, it should now run flawlessly. Awesome game, by the way. :D

Well, that was a hell of a ride. 1.0.5 is done. This release represents a huge chunk of maintenance and fixes about 7 different bugs. Most of them were pretty minor in the grand scheme of things, but they were enough to prevent a lot of games from running, so fixing them is important.

@DaVince: Could you have your friend try minisphere on Vista again, this time with 1.0.5? I'm pretty sure the Win7+ requirement is gone, but I don't currently have access to a Vista or XP machine to know for sure. Also: Sir Boingers now (mostly) works. It tends to error out on death/damage though, due to the stricter type checking in minisphere (this is mentioned in the readme). With a few edits to the game itself, it should now run flawlessly. Awesome game, by the way. :D

Sure, I'll send it to her and let you know. And thanks! :)

I've also fixed those bugs, though I'll hold off on releasing a Sir Boingers with such a minor modification until I've done more tests/fixing... and I might as well continue actual development on the game now that I have the opportunity.

Also, I couldn't help but notice that the error displayed was simply "not boolean" - it didn't tell me what variable exactly it was having trouble with. While that was no issue whatsoever for my simple code, imagine it happening on a more complex line.

Also, I couldn't help but notice that the error displayed was simply "not boolean" - it didn't tell me what variable exactly it was having trouble with. While that was no issue whatsoever for my simple code, imagine it happening on a more complex line.

A bit of background on that. Here's what an API function looks like internally:

duk_require_*() is shorthand for "get the value at this location on stack, but if it's not the type I'm looking for, throw an exception". It's very convenient, and keeps the code size down. But normally you don't even get a filename and line number for such errors: the only reason you do in minisphere is because I manually pull it from the call stack. Otherwise you'd just get a completely useless bare "not boolean" error.

I could fix it, of course, but that would require a bunch of extra conditional checks in every single API function, which really puts me off. Go look at the Sphere source sometime: For a lot of API calls, half the function is argument checking (which, mind you, doesn't really make sense since it still ends up type-coercing 90% of what you throw at it anyway; Spidermonkey is a ridiculously verbose API), and I'd prefer to avoid that here. The "mini" in minisphere is really about the code size more than anything; the fact that the engine itself takes up less space than Sphere 1.5 is just icing on the cake.

I really love the fact that all you really need to distribute a game is the engine binary, startup and system folder, by the way. So much cleaner.

Yep, early in development you also needed the Allegro monolith DLL, but a static link fixed that handily (I static link to the MSVC runtime for the same reason). I always hated that Sphere requires you to distribute about 10 different DLL files along with the engine. Worse, some of those are only needed for the editor, and it's not necessarily obvious which ones. So you have to basically guess which ones you can leave out, or just copy them all and bloat your distributable unnecessarily. Having everything self-contained in the engine executable means that's no longer an issue. :)

If I could, I would also get rid of the system folder requirement, but as a usable system font--at the very least--is required for the engine to even run, not much I can do there.

@Radnen: Curse you and your evil ways! :P Apparently you delete persons in a command generator script? minisphere doesn't particularly appreciate entities being pulled out from under it, and it leads to all sorts of random crashes. Should be fun to fix...

@Radnen: Curse you and your evil ways! :P Apparently you delete persons in a command generator script? minisphere doesn't particularly appreciate entities being pulled out from under it, and it leads to all sorts of random crashes. Should be fun to fix...

I guess, I don't remember. I try not to do that in a command generator. In fact I never aim to use it because in Sphere1.5 it's really slow performing.

A pattern I do use is this:

1. I set person to a death animation.2. I queue animation commands.3. I queue a person script that destroys the person.

That way the death script is cleanly executed when the animation ends. Otherwise I'm set using an update script, continuously checking for a final state and then destroying the person, making sure I don't accidentally destroy an already destroyed person (which ought to just do nothing, come to think of it).

That's what's crashing it, the person script destroys the entity but the engine tries to read the next command and crashes because the underlying person structure has already been freed. I didn't anticipate this eventuality, so minisphere doesn't handle it very well.

Oh, I see what you mean by command generator, I use the person command queue. I've never been a fan of the GENERATE_COMMANDS command, I'm not sure what it does and SSFML does not have that implemented. I say I'm not sure because it slows down a lot when you put logic in it, like random movement. I found that an update script that iterates over the entities on the map is a 1000 times faster than using the GENERATE COMMANDS script area.

So here is my feature request: Does minisphere's executable icon change? I'm not sure how that works, but is there a way you can set up a build script such that you can build minisphere with your own icon? It's not something I imagine most people doing, but it could be great.

I found minisphere to be way easier than Sphere 1.6 to build, less dependencies and less odd code to go wrong.

We should, at some point, try to document what all these commands really do. Some are self explanatory, but others like GENERATE_COMMANDS don't really make sense to me. Even COMMAND_WAIT doesn't seem clear to me.

We should, at some point, try to document what all these commands really do. Some are self explanatory, but others like GENERATE_COMMANDS don't really make sense to me. Even COMMAND_WAIT doesn't seem clear to me.

COMMAND_WAIT you insert into the command queue if you want the entity to not do anything for one frame, but otherwise still be under programmatic control. As for the command generator, the engine calls it for a person on any frame that there is nothing else in that person's queue. Youre supposed to use it to implement automatic movement, e.g. for NPCs. As for why it's so slow, I have a theory that sphere recompiles it every time it's called. It should be fast in minisphere since I pre-compile all person scripts.

ON_GENERATE_COMMANDS is used to run commands on each frame. (I used it to make people walk and look around in Pokemon GS/SS.)COMMAND_WAIT is used to add a short pause where a character does nothing for a frame. Useful when you're inputting a list of commands and want to run it all (like walk north, wait a bit, then walk back south). I used that one in GS/SS too.

I wasn't exactly *good* back when I worked on that game, of course. :P But I think COMMAND_WAIT has its uses. ON_GENERATE_COMMANDS, not so much.

The perks of making a compatible engine: you learn how the original works inside and out. :P up to and including all the annoying little idiosynchrosies that I nonetheless have to emulate to avoid breaking things. I'm not shy about fixing outright bugs though. For that reason minisphere will probably never be 100% compatible with Sphere, but that's fine. If at the end of the day I'm only at 90% parity with vanilla due to bug fixes, I'll take it.

Of course it probably helps that I have a knack for picking up on little subtleties. Great example being, it didn't take me long at all to figure out that Sphere doesn't destroy entities created before a MapEngine() call, which I believe bit Radnen during SSFML development. And that even made sense to me: the flag is called `destroy_with_map`, and no map is destroyed in a map engine start since none is loaded yet.

Honestly I think I've had more fun with this project than if I just made a whole new, unrelated engine, which was my original plan. Getting to see how Sphere works under the hood was worth it all by itself. :)

As for command generator scripts, I wouldn't give them up for anything. It helps keep each entity self-contained without having to feed NPCs movement commands from somewhere else in the code (the update script, for instance). Any time the engine offers to manage something for me, I'll jump at the chance. Less bookkeeping to bloat my own code that way. :P

I just added the Allegro libs to the repo. This makes it ridiculously simple to build the engine on Windows as everything needed is now included--you just need to provide MSVC, which is also simple thanks to VS Community. One of the many benefits of having all your dependencies be MIT/zlib licensed--you can just throw the files in and not have to worry about licensing issues. :)

Obviously there are no issues on Linux or OS X thanks to the SCons script, but I know compiling in Windows can be hell (and I develop in Windows, so that's saying something! :P), so doing this will make everyone's life a lot easier.

There is no NuGet for C projects? If so, I guess Allegro isn't there... I just took dependencies out of Sphere Studio and into NuGet packages to decrease the filesize of the git repo. Too bad though since it's been logged in the commit history, so those old DLL files will truly stay in it forever. :/

No Allegro on NuGet, I've already checked. That was the first thing I tried, but no such luck. No DLLs in mine though, just about 13MB worth of .lib files... Oh well. Note that the debug build is static-linked now as well. Maybe I'll think about adding console logging to it now...

Edit: Wait, no, make that 5MB. Not too bad, then. Not sure where I got 13 from...

Of course it probably helps that I have a knack for picking up on little subtleties. Great example being, it didn't take me long at all to figure out that Sphere doesn't destroy entities created before a MapEngine() call, which I believe bit Radnen during SSFML development. And that even made sense to me: the flag is called `destroy_with_map`, and no map is destroyed in a map engine start since none is loaded yet.

Actually, it seems like there's a bug regarding not destroying persons: when Sir Boingers switches to the next map, all the entities from the previous map are spawned at the entry point location. Which means I get to see this when starting level 2. Those objects (the flame, blue pad and spike ball above it) are all from level 1.

(http://i.imgur.com/QDutsU8.png)

This causes "person does not exist" issues down the line (like when dying/restarting the level).

Edit: by the way, you can experience this quickly for yourself by pressing F7 (the skip level key). It accumulates with each level.

Edit 2: mp3 is not supported, the engine crashes with a playback error. Is that right?

Okay, I've found out what the "Invalid base value" error was. I suspect that my code had a bug in it - namely that it would try to access an array inside an array, except the outer array would sometimes be undefined. What I mean is that there's a possibility that x in this.options[ x ][ y ] might have been undefined. Original Sphere seemed to be able to handle this.options[undefined][0] but Duktape doesn't. (And really, why should it? :) )

So, not sure what's going on, maybe behavior is different enough between the two engines that x ends up undefined sometimes in minisphere while it never does in Sphere. I don't know.

As for the persons respawning at the start of the next level, I noticed that myself, but thanks to a lack of testing in Sphere 1.5 I didn't realize it was a minisphere bug--I thought it was a bug in Sir Boingers. Are you exiting and restarting the map engine when switching levels by any chance? Because I'm thinking that's what it is--minisphere normally removes transient persons when switching maps just like in Sphere, but this doesn't happen if you stop and restart the map engine. Apparently it does in Sphere.

Oh and yes, no mp3 support sadly :(. Allegro apparently doesn't include it, I assume due to licensing issues, and I haven't yet found any addons to re-add support for it.

Yep, I close and reopen the map engine. It ended up working out better (the map engine only runs when necessary - I can finish a map, run some code, then continue with the next one in a more convenient way). That must be the issue, then.

And my test case doesn't work in regular Sphere either (errors out with "has no properties" too). I'm not exactly sure why my fix worked and the game works fine in regular Sphere.

So, not sure what's going on, maybe behavior is different enough between the two engines that x ends up undefined sometimes in minisphere while it never does in Sphere. I don't know.

Sounds like duktape doesn't like using `undefined` as an object key. This is probably a bug, it should coerce to a string first, which SM and V8 do. e.g. hippo[undefined] = true; should be equivalent to hippo['undefined'] = true;.

Sounds like duktape doesn't like using `undefined` as an object key. This is probably a bug, it should coerce to a string first, which SM and V8 do. e.g. hippo[undefined] = true; should be equivalent to hippo['undefined'] = true;.

That doesn't make sense. I could see if maybe it wasn't compatible with XP and crashed or something, but "not a valid win32 application" suggests the .exe got corrupted somehow. It's not a 64-bit build either... Odd.

From GitHub... You compiled it yourself? It definitely shouldn't be showing that particular error. The only time you should get that is if the .exe is either corrupt or 64-bit, and since I know for a fact it's not the latter...

Brain fart, I thought there was a link on Github for the pre-compiled version of it, I remember downloading the source, but never tried to compile it, my bad. So yea, only actually downloaded it from the Google drive on a couple separate instances and same thing.

Okay, everybody, word to the wise for Sphere implementors: Don't use a texture atlas for windowstyles. For a while now I've been trying to figure out what happened to cause the main screen in Radnen's SSFML test suite to slow down to a crawl (~20 fps) when it ran well before. When I first noticed this, I ran minisphere in the profiler (VS 2013 Community is awesome) and found out Allegro was switching to software rendering when drawing the windowstyle. That was about a week ago, and then I forgot about it because I had no idea what might be causing it.

Just now it finally dawned on me: Quite a while ago I modified the windowstyle loader to load the bitmaps into an atlas instead of individually. The reason for the switch to software rendering is because I use U/V tiling... which can't be done in hardware for only part of a texture, so Allegro switches to software to pull it off.

Of course, the flipside of this illustrates just why I love Allegro: It does everything in its power to service a request without me having to write a ton of fallback code. This keeps minisphere's codebase small and still ensures it will run on as many systems as possible. 8)

Sounds like duktape doesn't like using `undefined` as an object key. This is probably a bug, it should coerce to a string first, which SM and V8 do. e.g. hippo[undefined] = true; should be equivalent to hippo['undefined'] = true;.

minisphere 1.0.7 is coming. I'm almost tempted to do a version bump to 1.1 due to both Duktape and Allegro receiving major upgrades (1.2.1 and 5.1.9 respectively), but as that's under-the-hood, I think I will keep it at 1.0 for now.

In any case, the Allegro upgrade shrunk the size of the engine from around 2.5mb down to about 2mb--and even seems to have made things faster! ;D

Radnen, try running Blockman in minisphere now. It works much better with the fixes in this release. Also: The engine is now under 2MB and still completely self-contained!

@Defiant: Could you try this latest release on XP? I ended up having to build Allegro and all its dependencies myself with VS2013 in XP mode (9 static libraries for those keeping count :-\), so it better work now or I might have to murder someone. :P

This just in: I got the minisphere engine binary down to under 1.5MB without sacrificing any functionality. :) Compiling Allegro myself was totally worth it, I can leave out all the useless stuff I don't need (like OpenAL, which Allegro doesn't even really take advantage of). This means the engine is less than a third the size of Sphere 1.5! (By my count, 6.5MB, including the config utility and video plugins and excluding the editor)

minisphere truly lives up to its name! 8)

Also fixed: The audio deadlocks. I may not have mentioned it, but after the Allegro upgrade I started seeing random hangs when playing sounds. I'm guessing these were caused by OpenAL, since that's the biggest thing I excised from Allegro and the lockups have since stopped happening. *crosses fingers*

That would of course be an option, although it would require me to expose some sort of raw stream object to script, which would deviate pretty sharply from the Sphere 1.x API. Maybe for minisphere 2.0 (the planned Pegasus edition), but certainly not in this first version.

it would require me to expose some sort of raw stream object to script

An ArrayBuffer. The word you are looking for is ArrayBuffer. :P But It should be possible even with ye olde ByteArrays, though, shouldn't it?

We need to do a lot of work on Pegasus still. Right now it's still just an early draft. I agree with most of it, but there are lots of little points to iron out, and lots of stuff I don't think should be a part of the core API but rather an extension.

The ArrayBuffer is only part of it. That's just data after all--the engine itself still has to be able to know what to do with it. It's like saying you could implement networking entirely in script with just ByteArrays. :P

Also, I'm pretty sure Duktape doesn't support ArrayBuffers. (Not yet anyway. The developer is working on it from what I understand...)

As for Pegasus and not being finalized: let me just say I despise design-by-committee. I'd rather forge ahead now and work out the specifics later. I don't really mind refactoring and we want to get people excited about Sphere 2.0, which isn't going to happen unless they see concrete evidence in the form of a working engine.

I mean look at ES6. That's still a draft, but a lot of JS engines went ahead and implemented parts of it anyway. Duktape has the Proxy object for example--which I took advantage of to implement ByteArrays in minisphere. And seeing that in action in turn got me more excited about ES6. I don't see why we can't do the same with Pegasus.

The ArrayBuffer is only part of it. That's just data after all--the engine itself still has to be able to know what to do with it. It's like saying you could implement networking entirely in script with just ByteArrays. :P

Fair enough. I still need to actually expose this from my audio plugin, too.

As for Pegasus and not being finalized: let me just say I despise design-by-committee. I'd rather forge ahead now and work out the specifics later. I don't really mind refactoring and we want to get people excited about Sphere 2.0, which isn't going to happen unless they see concrete evidence in the form of a working engine.

Sure. Most of my concerns could even be fixed just by changing what is required to be called an extension and what isn't :)

I see you made FollowPerson() behave exactly like in Sphere 1.5, which is to say it takes the follower a bit of walking before suddenly warping in behind the leader. I always thought the FollowPerson() function was useless exactly *because* it behaves this way. Could you make it instead that the follower will try to catch up to the leader from whatever position they were already in when the FollowPerson() command was called?

The problem there is that doing that requires built-in pathfinding, something I'm not too keen on building into the engine. I don't think that's really the function's intended purpose anyway--it's just a minimal implementation you can use to make your party members follow each other around. Anything more advanced is left up to the game developer to do in script.

TL;DR incoming: See, I've learned something while working on this project, it's the thing that makes Sphere such an awesome engine: It provides a lot of built-in functionality, which allows you to get a game up and running very quickly, but it's also quite deliberately designed to get out of the way when you decide you want to step outside of its provided parameters. You generally don't appreciate this as someone on the outside looking in developing a game, but seeing the finer points of how the engine does things under the hood, I've started to appreciate the little subtleties.

A great example: I had to fix edge script triggering not once, but twice because of this. When I first implemented edge scripts, a cursory glance at the reference implementation (i.e. Sphere) yielded this code:

I naturally interpreted this to mean that edge script activation requires a valid input attachment (AttachInput). I later found out this wasn't the case when the Trial and Error intro turned out to be broken in minisphere, and, after another quick look--this time at the UpdateEdgeScripts() function--changed it to require an active camera attachment instead. This fixed T&E, but was still incorrect, which I didn't find out until Radnen sent me his Blockman game and I couldn't move between maps. The game manages the camera itself in script, so there's no AttachCamera() calls to be found. In other words, the edge script activation logic only cares about where the camera actually *is*, not who's holding it. Realizing this was an epiphany: I suddenly understood that the engine was deliberately designed this way so that you could replace AttachCamera() with your own implementation if you wanted to, and that doing so wouldn't break other things that you might not necessarily want to replace.

As for that input_valid variable? Turns out what it actually means is whether the map engine is currently accepting input at all (i.e. are we inside the main MapEngine() loop), regardless of whether there's a current input attachment or not. Poor choice of naming, which I of course rectified in minisphere (it's called is_main_loop there :P).

The problem there is that doing that requires built-in pathfinding, something I'm not too keen on building into the engine. I don't think that's really the function's intended purpose anyway--it's just a minimal implementation you can use to make your party members follow each other around. Anything more advanced is left up to the game developer to do in script.

Well, I honestly was just thinking about solving it like "move toward player at twice or thrice the normal speed without regarding any collision" (since it disregards collision anyway) just so the transition of a character being where it is to arriving near the player makes more sense. I never expect FollowPerson() to be used when the follower isn't already at least near the leader, and there wouldn't be a point to the function at all when it's implemented with its current looks-like-it-is-bugged behavior. And I rather like the simple function and would use it if it wasn't for this one small nagging thing.

Also, that is an extremely cool story! Pretty neat way for the engine to figure out the right thing. :D

Well to be fair, it doesn't have to deal with collision since the followers just follow the exact path the leader does and outside of edge cases with vastly different base dimensions, they're guaranteed not collide with anything either. This improves performance, which is important since the follow tracking has to move a lot of data around every frame itself.

But I do agree with the sentiment here. I'll see what I can do. Post an issue on GitHub about it so we can track it. :)

So much nicer than using a string for that; you don't get syntax highlighting for code in strings. :P Also, yes: minisphere has SetDefaultPersonScript. Sphere 1.5 apparently has it as well (I didn't think it did, but no unknown identifier errors when I call it), however it appears to be broken there as my test above didn't work in vanilla. It works perfectly in minisphere. :D So much eatiness...

Edit: Well, that explains that then. Apparently Sphere's implementation of default person scripts is only partial: It only ever calls the default script for ON_CREATE, none of the other default person scripts are ever touched. How did such an incomplete implementation like that ever make it into the official 1.5 release? ???

Well, the next release is coming along. This one is taking longer than usual since I want to get all the wrinkles ironed out first, as I'm planning for 1.0.10 to be the last 1.0 release before I start working on a few bigger changes for minisphere 1.1 (FollowPerson enhancements, config.exe...).

I finally fixed an audio deadlock bug that's been plaguing me since upgrading Allegro a few releases ago. I assume nobody else ran into it as I received no bug reports of the sort, which I suppose is a good thing. Here's what the changelog for 1.0.10 looks like thus far:

Oh, also, @Radnen: Did you ever test out the SetPersonFrame fix I posted on GitHub? I was waiting on you to test it before I merged it into master.

Yes, it fixed it. Also, minisphere is too much like sphere 1.5 in that it has the same animation bug that future boy nil fixed. You notice it in my blockman game when picking up bushes, rockets, etc. It has a glitchiness due to the last frame not being respected (when the last frame is met, make sure to go through it entire delay stack before switching over to frame 0).

What exactly is the bug? Odd that I would have replicated it, as I made sure to always initialize the delay when switching frames. There must be oddities with the animation setup that make it easy to screw up...

I'm 99% sure that Sphere-Group/Sphere is 1.6, with some more work done after the official 1.6 beta binaries were made. Well, plus the work Raahkin and I did to make it work again on OS X and Linux, respectively. It's got the particle engine, the new sound effect object, and some other secret new stuff like the zlib API that shouldn't be in 1.5.

It correctly cycled through all the frames (originally there was some log output here but it was a waste of space). Sphere 1.5 was somewhat odd as it stayed on frame 0 twice as long the first time around (8 frames instead of 4), but otherwise cycled through all 5 images as normal.

Are you sure your issue wasn't with SetPersonFrame() and not COMMAND_ANIMATE? Because that was the only difference I could find between 1.6 and minisphere, minisphere's SetPersonFrame wasn't resetting the animation frame counter.

I just made my first x64 build of minisphere, and it's working great! There's a good number of warnings due to conversions between int and size_t but other than that no issues that I've noticed so far. Note that Allegro and every one of its dependencies generated similar warnings; whoever had the bright idea that both int and long should be 32-bit in 64-bit MSVC needs to be shot.

The best part? The 64-bit build actually seems faster, especially noticeable with games that load a lot of resources upfront. :)

minisphere 1.0.10 is out. I'm including the 64-bit build as an experimental surprise addition to 1.0.10 so that it can get some real-world testing before it's officially unveiled in minisphere 1.1. :) Aside from that, this is basically a huge bugfix release to hopefully stabilize the 1.0 engine for real-world use.

So I had my first foray into 64-bit debugging in MSVC. It was a simple 10-second fix for a null dereference, but boy was the exception dialog (shown below) disorienting. I've been debugging 32-bit C/C++ apps for years, so I'm used to seeing this dialog, but all the extra digits in the memory addresses... wow. It took me a good 20 seconds I think to recover from the shock, it was dizzying. :P

Anyone have any suggestions for what they want to see in minisphere 1.1? Almost my entire v1.1 checklist has been checked off except for implementing config.exe, so I figure I should solicit feature requests now. :)

How do we check if we are running a game in minisphere? GetVersion() and GetVersionString() might have to take a parameter... not sure what though, here's the deal:

1. You can't overwrite the functionality of these functions because games check against them for compatibility, so they should return the API complacency. (v1.5 for the string and 1.5 for the number).2. You can't pass 'true' to them to get minisphere's version since in SSFML, I could also return it's unique version too.3. You pass a string, 'minisphere', to get minisphere's version. It returns nothing if you don't use minisphere. Trouble is, Sphere 1.5 will still return it's version number.

So... I guess the only way to detect sphere version is by feature detection. Namely we can use the features/apis function... whatever it was named.

Check whether GetExtensions exists. If it doesn't, that's stock Sphere. If it does, call it and check if 'minisphere' is included in the extensions list. That's why I added that function, and why I also added it to SSFML recently as well.

That said, do note that GetVersionString() in minisphere returns a string like this:

Just implemented a bunch of new APIs for follower management for 1.1. FollowPerson was one of those dark corners of the Sphere map engine that really needed some love; heck, the only way to get a person's leader was through engine-provided metadata returned by GetPersonData, and the rest of the info was just unavailable. minisphere 1.1 will add the following APIs:

GetPersonLeader

GetPersonFollowers

GetPersonFollowDistance

SetPersonFollowDistance

I have to thank DaVince for pointing out deficiencies in the Sphere implementation, or it never would have received these enhancements. You can now write a handler, for instance, that condenses follower chains when a person in the middle of the chain is destroyed:

Yeah, I would have changed the string back by now if there were a compatibility issue. From what I've observed, games that want to detect version level use GetVersion() instead, which returns 1.5 as always. Which makes sense, since then you can use comparison operators on it:

I've been doing that since minisphere's inception and haven't had a game break because of it yet.

I guess my fear there is someone is checking against the string. So far there hasn't been an issue tho. Yes, GetExtensions was what I was thinking about, I guess it's the only reliable solution.

Even if there is, it's their problem to solve. They wrote the game for Sphere 1.5, and it's pretty obvious that not every single stock 1.5 game works out of the box with minisphere (for example, any using the const keyword, or any using MP3 files).

Even if there is, it's their problem to solve. They wrote the game for Sphere 1.5, and it's pretty obvious that not every single stock 1.5 game works out of the box with minisphere (for example, any using the const keyword, or any using MP3 files).

Yeah, I guess you're right. New games shouldn't have that problem. I already modified Blockman to run in minisphere, I guess old games are just stuck with old engines.

Yeah, that would be trivial to add. Is there a valid use case for it though? I try not to add APIs just for the sake of it, trying to minimize perceived bloat.

GetTileName() is impossible otherwise, keep that in mind too.

Actually, if you want to reduce bloat, then it'd be nice to make a method where you get a POJO (plain old javascript object) of the map and it's tileset. You can then modify said POJO, re-update the map, and see the changes.

We can create Sphere 1.5 complacent wrappers around that POJO. This will ad 2 new calls to the map engine and literally remove anywhere between 20 and 50 API calls from Sphere.

Going one step further, it'd be neat to store the map POJO as JSON anyways. It has the added benefit of removing the need for analogue/persist for good (because you can modify the map state and save it into a separate save file with little-to-no effort).

That way, we can create either an in-engine way of handling save games, or someone can make an efficient, and easy to use save system for your games (person entities, maps, etc. are stored as POJO). I say in-engine since many new programmers struggle with saving a game and if we had a small API that's also very powerful, it could aid in bringing people to use minisphere.

Actually, if you want to reduce bloat, then it'd be nice to make a method where you get a POJO (plain old javascript object) of the map and it's tileset. You can then modify said POJO, re-update the map, and see the changes.

We can create Sphere 1.5 complacent wrappers around that POJO. This will ad 2 new calls to the map engine and literally remove anywhere between 20 and 50 API calls from Sphere.

Going one step further, it'd be neat to store the map POJO as JSON anyways. It has the added benefit of removing the need for analogue/persist for good (because you can modify the map state and save it into a separate save file with little-to-no effort).

This is exactly what my map engine does anyway since it is in script, and I can tell you it really is the way to go. More than half of the code by lines of my map engine is 1.5 functions, and even then I condensed them.Doing the same for tilesets, spritesets, and persons in particular is a really good idea, too.

Of course, I think the map engine is best done in script anyway...but even so, I suspect just having the 1.5 functions in script at least would go a long way to simplifying the implementation.

This would also encourage the idea of setting up a map object and then running it, instead of weirdly spooling objects, scripts, and persons. I believe this is the ugliest part of the map engine.

I used to hate the Sphere map engine with a passion, but it's odd--reimplementing it from scratch, I've developed a certain fondness for it. It's elegant, in a "diamond in the rough" kind of way.

I think my only real issue with the way the map engine is set up, is the unnecessary dichotomy between "map engine running" and "outside the map engine" caused by the fact that MapEngine() runs its own update loop. Every other issue (API, etc.) is merely cosmetic in my eyes.

Really though, I've begun to see the legacy API as Sphere's biggest strength (we've made it this far with it, after all, haven't we?). Some of the things it does seem... off to a seasoned JS coder (referencing persons by name, loose coupling between persons and map, etc.) but are nonetheless intuitive to someone who just wants to get a project off the ground quickly. Certainly more so than the morass of objects necessitated by the Pegasus spec.

That's not to say I view Pegasus as worthless, of course--quite the opposite, it's very much a step in the right direction. I just don't think we need to write off the legacy API as a second-class citizen--it's quite valuable in its own right.

I still think that style would be better. Being able to call up the list of persons, or just get a person by name, would still be a reasonable thing to do using that style.It wouldn't even be too difficult to allow passing in a name string optionally instead of a person object.

I agree that the Pegasus spec still needs work. A lot of it overly complex. I also agree that the old API is basically a good design. That's why I've only removed the old old drawing API in TurboSphere. The only major changes I'm really sold on so far is namespacing the API and adding basic OOP to it. Not anywhere near the OOP madness that Pegasus has, just small things, things that should really be properties instead of getters like RawFile.getSize(), and using real constructors.

The way I see it, the Sphere 1.5 API is perfect in every step of it's existence, but if you think about it, it doesn't need to be implemented in the engine. Rather, only a few API calls ever need to be exposed and that's the direct interaction with each file type and input/output method. So really you only need like a couple dozen API calls.

1. Maps/People/Spritests/etc. are full JS objects that you can create the Get/Set API from, script side.2. All objects become normal JS constructors, which you can make the Load*() API calls from.3. All graphics are ran through a vertex/shape API that you can make the primitives and images API from.4. All input is handled by global singletons for that game instance, where you can make the input API from (keyboard, mouse, joystick).5. All files use 1 IO API which you can make all LogFile/RawFile/File API's from.

If you really think about it you only need to expose like 12 to 20 actual, hard coded, necessary API calls to sphere in order to run 90% of the rest of the API. Graphics, persons + maps, IO, input just have to use the few objects exposed to code and that's it.

It'll truly 'unlock' Sphere. It's great because you can then do cool things like:

TurboSphere is headed this way with it's Sphere 1.* shim. This is really a good idea. Having very few Sphere API calls also increases the fact you get more 'freedom' from the engine. I used to think you could never make a game without Sphere MapEngine... oh how wrong was I. It was just that since it was there, you had access to it and since there was this huge API around it, it made it hard to give the illusion of freedom, but it's there, you had a lot of freedom, but the API never always showed it. Especially when you hit brick walls like enumerating the fields of an image, adding a property to an image, or heck, even getting the dang filename of an image.

Haha, I love that comment on the CreatePerson() function. From a purely theoretical standpoint, the Persons API doesn't seem to make much sense, does it? That is, until you actually go to implement it. Maps and persons in Sphere are actually very loosely coupled, which is big part of what makes the system so flexible. The tendency I think is to always want to view persons as being associated with a given map, when in fact they NEVER are, the map engine just happens to conveniently destroy some of them for you when switching maps.

Haha, I love that comment on the CreatePerson() function. From a purely theoretical standpoint, the Persons API doesn't seem to make much sense, does it? That is, until you actually go to implement it. Maps and persons in Sphere are actually very loosely coupled, which is big part of what makes the system so flexible. The tendency I think is to always want to view persons as being associated with a given map, when in fact they NEVER are, the map engine just happens to conveniently destroy some of them for you when switching maps.

That just goes to show just how much was hidden behind the scenes, the person manager, the command queue, the way edge scripts are detected(!), and the camera, and the player input. Bringing these hidden areas to the forefront can increase productivity, these can be safely exposed in an extended API. Older games just wouldn't know to call these extended functions, but newer games can, and take full advantage of them. I'm still impressed to this day FBNil's ability to know how sphere operates behind the scenes to take advantage of person scripts, delay scripts, etc. in his lithonite engine.

That's what made getting the Lithonite demo fully working in minisphere such an awesome moment. minisphere's map engine implementation was as much reverse engineering and extrapolation as it was directly studying Sphere's code. Which ultimately was a good thing--I can only take so much of the latter activity before it starts to wear on my sanity. Read the post at the top of page 22 for just one of the many reasons why that is. :P

But yeah, I was able to extrapolate a lot of the map engine's inner workings from studying Lithonite's tricks. It was quite fun, actually. :D

Quick warning to anyone using minisphere for production use: Don't try to to pass a function to SetPersonScript, it will crash. I accidentally passed a Duktape context to the internal set_person_script function instead of a person object, so it ends up overwriting Duktape state and everything goes to hell. SetPersonScript() with a code string works fine, though, so I won't put out a hotfix for it. It'll be fixed in 1.1.

Yeah, that would be trivial to add. Is there a valid use case for it though? I try not to add APIs just for the sake of it, trying to minimize perceived bloat.

I can think of good use cases for SetTileName(). First off, of course there's the fact that once you save a map it'll have this changed tile name data in it. But what about tiles in your game that you want to change the behavior on? For example, tiles with the name "hazard" all behaving like hazards until you tell some tiles they no longer have this name and thus no longer are hazards.

I'm sure there are more not-quite-straight-forward use cases. It's nice that this has been implemented now, anyway.

How about a DoesFileExist function? Not sure why it wasn't added with the other file/directory listing functions.

Already done. In fact it should be in 1.0.10 already. I ended up adding it after looking through the commit log on the old sourceforge CVS repo (when I was trying to get the 1.5 source to fix that animation bug) and seeing it. I think it might not have actually been exposed to script though? Anyway, yeah, minisphere has DoesFileExist() already. :)

I thought of two other things that I find useful additions to the API. These are additions I added for use by my map engine, so I have an actual use for them as opposed to SetTileName.

RawFile.read(), with no argument, reads the entire file.RawFile.readString() works the same as read, but returns a string. This can save on memory usage, when otherwise an ArrayBuffer or ByteArray would have to be garbage collected. Until then, you have at least two entire copies of the read in memory.

I thought of two other things that I find useful additions to the API. These are additions I added for use by my map engine, so I have an actual use for them as opposed to SetTileName.

RawFile.read(), with no argument, reads the entire file.RawFile.readString() works the same as read, but returns a string. This can save on memory usage, when otherwise an ArrayBuffer or ByteArray would have to be garbage collected. Until then, you have at least two entire copies of the read in memory.

RawFile.readString I probably would have done myself at some point. I already did that for sockets, in fact. :D I like the idea of .read() with no args slurping the whole file, it saves the step of getting the length first. Thanks!

As for garbage collection, do note that that's not as big an issue in minisphere as Duktape's primary GC method is refcounting. It only resorts to mark and sweep in case of circular refs.

So I noticed a missing effect in the Sir Boingers intro screen: the backgrounds are supposed to fade in and out to and from black, but they're not. They're scrolling and a new background is shown without any transition whatsoever.

The fade effect is performed by overlaying a fullscreen black rectangle that changes its opacity - code at line 465-481 in start.js. For some reason this doesn't seem to render in minisphere (and I made sure to compile the latest version - works full speed even on an old laptop, good work!)

Well, this has been a massive undertaking, but definitely worth it. In minisphere 1.1, all Sphere objects will have proper constructors and, where applicable, actual properties in addition to the old-style get/set methods. I even took some cues from TurboSphere when implementing a few of the constructors. :D Amazingly, the engine executable hasn't grown much, if at all. The 32-bit engine is still 1.5MB and 64-bit 1.75MB. Pretty awesome.

I'll be honest though, if I had tried to implement things this way from the start, I can guarantee it would have been a failure. minisphere 1.0 had to be what it was, a drop-in Sphere 1.5 replacement, legacy warts and all. It gave me something to work towards, the entire existing Sphere catalog. If I had gone for the modern approach right out of the gate, it wouldn't have been compatible with anything and would have gotten very boring very fast since the only thing I would have had is, at best, a bunch of contrived tests. But now that I have that compatibility, I can freely build on it to create something great. ;D

So I noticed a missing effect in the Sir Boingers intro screen: the backgrounds are supposed to fade in and out to and from black, but they're not. They're scrolling and a new background is shown without any transition whatsoever.

The fade effect is performed by overlaying a fullscreen black rectangle that changes its opacity - code at line 465-481 in start.js. For some reason this doesn't seem to render in minisphere (and I made sure to compile the latest version - works full speed even on an old laptop, good work!)

Apparently the copy of Sir Boingers I have doesn't have this effect? I have the one from the Downloads repo, and the lines in question look like this:

Yeah, I see the Rectangle() call. I added some prints before the primitive call and used a debug build of minisphere (which shows the console window), the alpha values are correct, but the Rectangle apparently isn't being rendered. Definitely something weird going on here.

So I took a closer look at the print() output and figured out the issue: The alpha values on your mask rect are negative. minisphere clamps colors to [0-255]. Sphere modulo's them, which I chose not to emulate because it screws up color tweening. You can fix the effect by changing the alpha math to ensure the alpha is always in the range of [0-255]. It's not a bug, it's a feature! ;)

Also, tip: If you put a 32x32 icon.png in the project root, minisphere will use it for the game's taskbar icon. :)

So I took a closer look at the print() output and figured out the issue: The alpha values on your mask rect are negative. minisphere clamps colors to [0-255]. Sphere modulo's them, which I chose not to emulate because it screws up color tweening. You can fix the effect by changing the alpha math to ensure the alpha is always in the range of [0-255]. It's not a bug, it's a feature! ;)

Yeah, I've sometimes made use of the fact that you can go beyond 255 and the color just loops.I'm not sure I even realized the number was going into the negative back when I coded that. Maybe I did. Anyway, I'll have to figure it out. Maths is not my strong point. :(

Quote

Also, tip: If you put a 32x32 icon.png in the project root, minisphere will use it for the game's taskbar icon. :)

Will do! For the next version, though, this one was just a bug fix release!

Admittedly it was a clever trick--send the alpha into negative to "reverse polarity" so to speak-- (-1) = 255, (-255) = 0. Unfortunately it won't work in minisphere. :P. I'll only go so far in the name of compatibility!

@DaVince: Let me just say I love the snarky remarks Boingers 2.0 gives when you die. The new levels were too hard for me, so I started playing the "old" level set - my favorite had to be 6 levels and about 20 deaths in, it told me "Well done" when I died and I cracked up. ;D The game seems very stable on 1.1b1, no crashes, errors or anything.

mini.js would be catchy, even if it didn't reflect the Sphere lineage.

Nah, too much JS-related stuff uses the .js nomenclature (Node.js immediately comes to mind), it's a dumb fad as far as I'm considered. It would be like me calling minisphere 'minisphere.c'. Admittedly that works better if it were actually all in one .c file (I used to do that way back in the day too :P), but...

So I've been thinking about the config tool I'm planning to add in 1.1, and it strikes me that almost no existing Sphere game actually uses the key mappings set using it (i.e. the GetPlayerKey() function). Thinking about why that would be, it strikes me that the likely reason is this: Sphere's config tool is, quite frankly, an atrocity. You have the engine for normal gameplay, but if you want to change keys, plugins, etc., you have to close the engine, run config, and then run the game again.

This whole state of affairs is a shame, as one of the many great things about Sphere is how much tedium it offers to handle for you without getting in your way if you want to do things differently. So me, not one to let a useful engine convenience go to waste, I came up with the following idea: An in-engine configuration screen. I could even make it a little pulldown strip at the top of the screen so you can change settings without interrupting gameplay. I could even allow per-game config this way!

This whole state of affairs is a shame, as one of the many great things about Sphere is how much tedium it offers to handle for you without getting in your way if you want to do things differently. So me, not one to let a useful engine convenience go to waste, I came up with the following idea: An in-engine configuration screen. I could even make it a little pulldown strip at the top of the screen so you can change settings without interrupting gameplay. I could even allow per-game config this way!

@DaVince: Let me just say I love the snarky remarks Boingers 2.0 gives when you die. The new levels were too hard for me, so I started playing the "old" level set - my favorite had to be 6 levels and about 20 deaths in, it told me "Well done" when I died and I cracked up. ;D The game seems very stable on 1.1b1, no crashes, errors or anything.

So I've been thinking about the config tool I'm planning to add in 1.1, and it strikes me that almost no existing Sphere game actually uses the key mappings set using it (i.e. the GetPlayerKey() function). Thinking about why that would be, it strikes me that the likely reason is this: Sphere's config tool is, quite frankly, an atrocity. You have the engine for normal gameplay, but if you want to change keys, plugins, etc., you have to close the engine, run config, and then run the game again.

This whole state of affairs is a shame, as one of the many great things about Sphere is how much tedium it offers to handle for you without getting in your way if you want to do things differently. So me, not one to let a useful engine convenience go to waste, I came up with the following idea: An in-engine configuration screen. I could even make it a little pulldown strip at the top of the screen so you can change settings without interrupting gameplay. I could even allow per-game config this way!

Yes please! And it'd be even nicer if you exposed some of the config settings through the API too, like the key bindings.

Also, input is kind of a complex beast. I was writing a long post asking for more full keymapping support that is analogous to modern gamepads, but thinking about it, this would NEED to come with a way to save the configuration in the game folder itself (and include it as a config in game.sgm or a config.ini in the same folder or something). Because some games have mappings where WASD moves you and the arrow keys do other stuff (or you need to use the mouse) while others would use the arrow keys.

It's probably a good idea to have the global config file which saves things like window scale and filter, and the game-specific section saves stuff relevant for only this game (like the input). I also think you can drop/not implement some stuff like disabling sound, because honestly, OSes just support disabling sound on individual apps now.

Oh! And sometimes you could expect different behavior from the keyboard and mouse compared to gamepads. You will want to stick with the raw keyboard input then. Sir Boingers is set up so that it both accepts the joystick API and keyboard input, but the keyboard input is all done with Sphere's keyboard-related functions because the game simply behaves differently when played with a keyboard. For example, on a keyboard, "up" makes you float, while with a controller it uses other buttons because that's easier.However, I consider this a "don't worry about it" case as I've set up the game to check both the keyboard and gamepad anyway, and so should anyone else with controls that aren't the same on different controllers. They're more specialized cases.

Yes please! And it'd be even nicer if you exposed some of the config settings through the API too, like the key bindings.

They kind of are though? That's what GetPlayerKey() is, but nobody uses it because the current config.exe is clunky (and huge--take a look at a Sphere 1.5 distro some time--config.exe is literally the biggest thing there, even bigger than the editor! :o). Unless you mean an API to set the mappings, in which case... eh. I think at the point your game wants to do that, it means you're already exposing your own configuration UI anyway, so might as well go all the way and manage the settings yourself. Let's not invite scope creep here. :)

Quote

Also, input is kind of a complex beast. I was writing a long post asking for more full keymapping support that is analogous to modern gamepads, but thinking about it, this would NEED to come with a way to save the configuration in the game folder itself (and include it as a config in game.sgm or a config.ini in the same folder or something). Because some games have mappings where WASD moves you and the arrow keys do other stuff (or you need to use the mouse) while others would use the arrow keys.

The current config GetPlayerKey() mappings are already based on a gamepad (an SNES pad, to be specific: a single D-pad with four face buttons and a Start button--Select is MIA for some reason), so it would be easy enough to expand the mappings. The thing is though, again, Sphere's design is set up primarily for making retro games, so the conveniences provided by the engine reflect that. Anything more advanced, in my opinion, should be done in script. This kind of thing is why the File API exists (referring to the .ini-style File object, not RawFiles), after all.

Quote

It's probably a good idea to have the global config file which saves things like window scale and filter, and the game-specific section saves stuff relevant for only this game (like the input). I also think you can drop/not implement some stuff like disabling sound, because honestly, OSes just support disabling sound on individual apps now.

Oh! And sometimes you could expect different behavior from the keyboard and mouse compared to gamepads. You will want to stick with the raw keyboard input then. Sir Boingers is set up so that it both accepts the joystick API and keyboard input, but the keyboard input is all done with Sphere's keyboard-related functions because the game simply behaves differently when played with a keyboard. For example, on a keyboard, "up" makes you float, while with a controller it uses other buttons because that's easier.However, I consider this a "don't worry about it" case as I've set up the game to check both the keyboard and gamepad anyway, and so should anyone else with controls that aren't the same on different controllers. They're more specialized cases.

I actually don't like the window scaling being global. It's one of my biggest peeves with Sphere 1.5--I generally keep 2x scale on because the majority of Sphere games are 320x240, but if I happen to come across one that uses 640x480 (or higher--T&E is 800x600!), the window is bigger than the screen and then I have to reconfigure it, which shrinks all my 320x240 games in the process.

Oh, and speaking of Sir Boingers, I'm actually not a big fan on the new control setup in v2. The 2010 version's setup was better, I think (Ctrl to bounce). A big issue with the new controls I've had is that, when bouncing and trying to move left and float at the time, the Up input gets ignored because of simultaneous-key limitations on cheaper keyboards (the keyboard on my Core i3 2-in-1 laptop, for example). This makes a few areas almost impossible and cost me a good number of avoidable deaths. I think this is why old console emulators used to use Ctrl and Alt for the face buttons, actually, since modifier keys don't contribute to the 3-key limit.

From what I'd expect, all to almost all of the configuration options should be in a built in menu bar of some kind, like when using Visual Boy Advance, so you can change all those options on the fly. It makes a lot more sense to me, but I'm not sure how feasible it would be to change which graphics and audio plugins you're using on the fly.

From what I'd expect, all to almost all of the configuration options should be in a built in menu bar of some kind, like when using Visual Boy Advance, so you can change all those options on the fly. It makes a lot more sense to me, but I'm not sure how feasible it would be to change which graphics and audio plugins you're using on the fly.

Yeah, that's what I was planning here, ability to change the configuration without stopping the game you're playing. Plugins aren't an issue as minisphere's backend isn't customizable--it's always Allegro. :)

Well, I decided on a whim that 1.1 doesn't represent a big enough evolution and am now going to implement the Sapphire API from TurboSphere. After looking at the method signatures and such, it seemed like low-hanging fruit to me. :)

If minisphere 1.1 doesn't end up being the most awesome Sphere implementation ever after this... well, I don't know what to tell you. :D

From what I'd expect, all to almost all of the configuration options should be in a built in menu bar of some kind, like when using Visual Boy Advance, so you can change all those options on the fly. It makes a lot more sense to me, but I'm not sure how feasible it would be to change which graphics and audio plugins you're using on the fly.

Well, I decided on a whim that 1.1 doesn't represent a big enough evolution and am now going to implement the Sapphire API from TurboSphere. After looking at the method signatures and such, it seemed like low-hanging fruit to me. :)

If minisphere 1.1 doesn't end up being the most awesome Sphere implementation ever after this... well, I don't know what to tell you. :D

From what I'd expect, all to almost all of the configuration options should be in a built in menu bar of some kind, like when using Visual Boy Advance, so you can change all those options on the fly. It makes a lot more sense to me, but I'm not sure how feasible it would be to change which graphics and audio plugins you're using on the fly.

Hmm....HMMMMM!

Yeah yeah, plugin support, I can take a hint. ::) I'll get there eventually... maybe. Honestly it's just not that important to me and adds complexity that's just not needed for most use cases. Maybe I'll do it when I run out of features to steal from other engines. ;)

As for Sapphire, I just need some clarification: Can a shape be created with a Surface as texture, or does it have to be an Image? With the way the engine is set up right now I could both (surfaces and images are the same under the hood), but I'm trying to be compliant here.

I wasn't bugging you for plugins...I was just thinking...TurboSphere could actually unload and load plugins on the fly, but the only issue with that would be that any objects constructed using a plugin that is then unloaded couldn't be used anymore, and when they are finalized bad things would happen...but it's an interesting idea.

I'm assuming UV is normalized [0-1], but what of coordinates? Are X/Y resolution-dependent or are they normalized too? And where is the origin (0,0) relative to the screen?

I'm probably going to change a few names here and there in any case (Shape:image->Shape:texture among others), so it won't be a fully compatible implementation, but the general API structure should be identical.

Unless you mean an API to set the mappings, in which case... eh. I think at the point your game wants to do that, it means you're already exposing your own configuration UI anyway, so might as well go all the way and manage the settings yourself. Let's not invite scope creep here. :)

That's what I meant, though. Setting options. But yeah, if you're going to have a menu bar it's not going to be needed. :)

Quote

Oh, and speaking of Sir Boingers, I'm actually not a big fan on the new control setup in v2. The 2010 version's setup was better, I think (Ctrl to bounce). A big issue with the new controls I've had is that, when bouncing and trying to move left and float at the time, the Up input gets ignored because of simultaneous-key limitations on cheaper keyboards (the keyboard on my Core i3 2-in-1 laptop, for example). This makes a few areas almost impossible and cost me a good number of avoidable deaths. I think this is why old console emulators used to use Ctrl and Alt for the face buttons, actually, since modifier keys don't contribute to the 3-key limit.

It's set up so you can use the Z key too. In the end I moved away from ctrl because it felt less natural for modern games, but I can bring it back easily enough.

Gangnam TurboSphere style! It draws a little 10x10 textured square at the top left of the screen. ;D

I feel like I should change the order of the arguments for the Shape and Group constructors though... it feels clunky tacking the image/shader onto the end of the array literal like that, it would be more natural as the first argument I think.

The default shader returned from GetDefaultShaderProgram must guarantee raster coords and have the origin in the upper left, just like how Sphere does it.

UV is normalized, but giving a number greater than 1 causes tiling just like how OpenGL and (or so I've heard) DirectX do it. UV is also automatically assigned to the order you gave if it is not present in the vertices. Triangles use the same coords, but just the first three. Same with lines and points.

I don't think it would be more natural with the Image/Shader first...for the primitives in Sphere, coords and parameters come first, colors and attributes come last. That's why I set it up this way, anyway.

I'll be curious to see how you tackle drawing text using Galileo/Sapphire. That's kind of a thorny spot so far. It works, but I think it could be handled better.

The default shader returned from GetDefaultShaderProgram must guarantee raster coords and have the origin in the upper left, just like how Sphere does it.

UV is normalized, but giving a number greater than 1 causes tiling just like how OpenGL and (or so I've heard) DirectX do it. UV is also automatically assigned to the order you gave if it is not present in the vertices. Triangles use the same coords, but just the first three. Same with lines and points.

I don't think it would be more natural with the Image/Shader first...for the primitives in Sphere, coords and parameters come first, colors and attributes come last. That's why I set it up this way, anyway.

When I said more natural, I meant the syntax. If a function is likely to be called with a multi-line array or object literal as argument, as here, it's awkward to have to add arguments after the literal. See the code sample above, especially the Shape initialization, for what I mean.

I'm curious about the automatic UV assignment... how does that work? Right now UV defaults to zero for all vertices in my implementation, which is pretty useless. Maybe I should take a closer look at the TS source...

As for that shader, that's a vertex shader, right? I wasn't entirely clear on whether it was that or a fragment/pixel shader.

I'm curious about the automatic UV assignment... how does that work? Right now UV defaults to zero for all vertices in my implementation, which is pretty useless. Maybe I should take a closer look at the TS source...

If you are curious:https://github.com/FlyingJester/TurboSphere/blob/master/src/plugins/Sapphire/script.cpp#L608-L679 (https://github.com/FlyingJester/TurboSphere/blob/master/src/plugins/Sapphire/script.cpp#L608-L679)I check the number of vertices against a lookup table with default UV numbers. As I iterate the vertices, I check if they have U, V, and Color properties, and override the defaults if they do.

That way, to blit an image you don't need explicit U and V, you just need the corner locations. This is pretty convenient, I find. It also allows overriding the color mask, but defaulting to full masking.

There are other things I could do, too. Maybe add the ability to specify GLSL version in the fragment and vertex constructor and inject that into the shader source? That would be nice if I also added a way to query valid GLSL versions. When the ShaderProgram constructor exists, I will add GetDefaultVertexShader and GetDefaultFragmentShader, so that you can use only a single part of the defaults. Then you'd really need to know the GLSL version.

You need both vertex and fragment shaders in OpenGL 3.2+ and 4. Since that's also valid for 2, that's how I did it. I never got much into shaders for OpenGL 2, maybe it's necessary there to?

Adding Geometry shader passes would also be a very cool extension. I don't really want to get into Compute shaders since that is an aborted feature.

I think Allegro might actually support shaders... I should try experimenting with it. :)

Is Sapphire (I'm assuming Sapphire is the frontend and Galileo the backend...) part of the Pegasus spec by any chance? It's actually been a while since I've looked at that repo and I don't remember if anything like this was specified in it.

Is Sapphire (I'm assuming Sapphire is the frontend and Galileo the backend...) part of the Pegasus spec by any chance? It's actually been a while since I've looked at that repo and I don't remember if anything like this was specified in it.

Sapphire is the name of TurboSphre's implementation (well, the whole TurboSphere graphics plugin). Galileo is the name of the API.

The spec is in the api/ts directory of Pegasus. I just updated a week or so ago, based on what TurboSphere actually implements.

Wow, just took a look at the Galileo spec and it really is a ridiculously simple API. I imagine it could be deceptively powerful in the right hands, though.

My only real gripe is with the way Vertices are treated. It specifies a full constructor for what is ultimately just data. And what's up with Shapes not being able to share a Vertex? That's just silly. :P

Well, not even 24 hours later, my Galileo implementation is almost finished (sans shaders, of course--that'd be getting a bit too ambitious for 1.1, although Allegro 5.1 *does* have the functionality). :D It'll be a fully Pegasus compliant implementation and its existence is reported by GetExtensions() as "sphere-galileo". Allegro 5 truly is awesome.

The only thing I really have left to implement is the automatic U/V assignment and modifiable vertex and shape lists for Shapes and Groups, respectively. Shouldn't be too much more work.

minisphere 1.1 will be a sight to behold once it's released. Best of all: You get all this new stuff, and it STILL runs old Sphere games! ;D

That's good. Galileo is meant to be close to how the lower level APIs work in concept, so it's pretty easy to actually implement. Reimplementing it in OpenGL 2.1 only took me a couple hours, most of the work was making it selectable between that and OpenGL 4 and ensuring I had not broken the OpenGL 4 stuff.

Apparently there's some infinite recursion somewhere and I have no clue why.

Edit Figured it out. I had minisphere set up to update the RequireScript inclusion tracking info only after executing the script, which is useless in case of mutual inclusion. Surprising that this bug didn't bite me until now...

Of course, sadly it turns out it doesn't work. I get a "not callable" error in segment.js line 6.

Hm, interesting. The issue seems to be that the Turbo object created in each script is localized to that evaluation. It's not actually being created in the global scope, apparently. I added an Abort call immediately after the format.js inclusion in segment.js to print out the value of Turbo, and got back 'undefined'. No idea what's up with that. If I RequireSystemScript 'turbo/format.js' directly, Turbo is not undefined, so...

Bear in mind it's possible that TurboSphere's map engine has some stuff in it that doesn't work on a language level in Sphere 1.5 or similar.

There is one other issue to running the map engine. I escape "#~" in paths to be the system directory. I had intended to just put the format JSON files into a local directory to use the map engine with other engines.

It looks like the biggest obstacle to minisphere being able to use the Turbo runtime right now is Duktape's lack of ArrayBuffers. He's working on it right now (milestone of 1.3.0 listed on the relevant GitHub issue), but it seems to be slow going.

Can you see where it properly needs one? I tried to allow it to use ByteArrays as well (or any object that has a `[]' operator). I may have left in a couple evil engine calls, though, like making surfaces directly out of ArrayBuffers.

Can you see where it properly needs one? I tried to allow it to use ByteArrays as well (or any object that has a `[]' operator). I may have left in a couple evil engine calls, though, like making surfaces directly out of ArrayBuffers.

Which is the most schizophrenic piece of code I've ever seen. :P You go from a ByteArray (returned by RawFile:read) to a Uint8Array, back to a ByteArray again, and finally to a string before parsing it as JSON. Were you just stress-testing the ByteArray stuff on purpose or what?

Also, bytearray.js RequireSystemScript's arraybuffer_bytearray.js without checking to see if a native ByteArray already exists.

Which is the most schizophrenic piece of code I've ever seen. :P You go from a ByteArray (returned by RawFile:read) to a Uint8Array, back to a ByteArray again, and finally to a string before parsing it as JSON. Were you just stress-testing the ByteArray stuff on purpose or what?

It's an extremely cheap operation to convert between ByteArrays and TypedArrays in TurboSphere. It just sets a couple properties of the TypedArray to be compatible methods for a ByteArray.

Previously, read() always returned an ArrayBuffer, and ByteArrayFromTypedArray has wavered between only handling TypedArrays and ArrayBuffers. Now it's able to handle either.So you're completely right, that code is just too much, making up for issues that don't even exist anymore.

Edit:Ah, I see. The whole file reader system needs a file reader for ByteArrays.

Last night I did a massive reorganization of the minisphere directory. It's now set up like a real cross-platform C app instead of the MSVC-generated structure it had before. Source and headers are in 'src', the MSVC project files are in 'msvc', and the engine is built in 'bin'. A small thing, but at least now it doesn't look like cross-platform support is an afterthought. ;)

@DaVince and @casiotone: Could you guys check that it still builds on Linux and OS X using SCons? I updated the build scripts to reflect the new structure but as SCons won't build it for me on Windows, I can't test that everything is working properly.

I think it chokes on the dying screen, as my new version uses the original IT files now and this is one that should play only once. I can hear about 0.2 seconds of the music before it segfaults.Curiously, the win screen does function, even though it also calls a non-looping IT file... (It loops anyway which isn't right though.)

I also have a request: could you make minisphere check if there's only one game in the games folder and just run it if that's the case? I don't want to put my game into a startup folder because that makes it more of a hassle to package the game without the engine.

Yeah, the looping thing is a bug in Allegro that's fixed in the latest build but hasn't been released yet. There's nothing I can do on minisphere's end to work around it, unfortunately. It does work properly on Windows because I compiled Allegro myself and included the appropriate fix. :). I actually had no choice, because there are no pre-built x64 MSVC binaries for Allegro, or at least I haven't found any...

Yeah, I noticed it works fine on Wine. Will wait for the next Allegro version then.

I also noticed that in Windows the file selector defaults to My Documents instead of the working directory. Might want to make the default path either minisphere's directory, or the games subdirectory (when found). :)

I've decided what I want to do for the configuration editor. The config tool will be written in JS and run by minisphere as any other Sphere game. config.exe will be a tiny stub that simply defers to the engine and points it at the location of the config "game" game.sgm.

Unfortunately this does mean that key mappings won't be able to be changed while in-game, but after a short-lived experiment trying to implement a graphical config on the native side (the only way to implement such a thing without interrupting the currently running game), I gave up. C--or any purely procedural langauge, really--just isn't suited for writing a GUI. It'd much less painful in an OO language like JavaScript. Besides, as with Sphere's old config.exe, it's really just meant to be a convenience; the preferred option will always be to implement your own config in-game to ensure UI consistency and whatnot.

On a sidenote, my other attempt at a config tool was in C++ using wxWidgets for a Sphere 1.5-style tool, but 1) wxWidgets is horrendously bloated (it took me 10-15 minutes to compile all the libraries on a 5th-gen Core i3--note that this is a CPU that can run the Dolphin emulator!) and 2) It very quickly reminded me why I hate C++. So yeah, that was a failure too.

Just my opinion, having had a long time to wonder about what GUI toolkits to use...

You should take a look at fltk. It is kind of intended for what you describe. It's extremely lightweight, and it makes only a very select usage of C++'s features. It is also extremely cross platform, and still provides easy integration with platform tools.

For instance, you could easily use Fl_x.h's stuff to create a new parent window given a Win32, X11, or Cocoa window handle to have as a child. I was considering using that to frame the window SDL2 creates for TurboSphere, so that I could have an SDL2 OpenGL window embedded in an fltk window that has a menu bar for this kind of thing. You could also automatically use the OS X menu bar instead of a separate one by using Fl_Sys_Menu_Bar.

I despise Qt and WxWidgets because they are ridiculously large and solve simple problems in the most complex way imaginable. I don't like GTK because its maintainers have no commitment to backwards compatibility at all. I rather like fltk because it doesn't have any of these issues. It can look a little dated with the default scheme, but that's really the least of what matters to me. The theme is very usable and simple.

I do like the GTK+ theme, if I have to use non-native widgets that's the one I'd prefer by far. But GTK is pretty bloated itself. The redistributable last I remember was about 20MB and there's no way to static link to it. No way I'm carrying around that kind of baggage for a config tool that half of Sphere users aren't even going to touch. I did take a look at fltk, and while I think most of those screenshots are pretty fugly, it does look very lightweight and simple to use.

But I really think the startup-game-style JS config is the way to go here. This probably sounds odd given my dedication to doing everything in native, but at the end of the day I don't consider this core functionality; it's just a nice extra. This way if a game doesn't need it--say, because it implements its own configuration menus--config.exe and the config folder can be left out of the distro. It's a different situation than, say, the map engine, where at least 3/4 of all Sphere games utilize its functionality in some way and so it's beneficial to have it built into the engine. (And I wouldn't have wanted to have to debug that thing in JS anyway--the MSVC debugger was invaluable during its development).

And I wouldn't have wanted to have to debug that thing in JS anyway--the MSVC debugger was invaluable during its development

Fortunately, both SpiderMonkey and V8 can be run so that gdb or lldb can view JS stack frames as though they were native frames :)Or at least V8 used to be able to. When I was on my way out of the V8 world, it had been broken for some time and there were murmurs of that being removed.

But I found that one major advantage of the map engine in script was simply that it is easier to write something purely behavioural like that in JS. It needs much less debugging because it has fewer bugs in JS.

But I found that one major advantage of the map engine in script was simply that it is easier to write something purely behavioural like that in JS. It needs much less debugging because it has fewer bugs in JS.

But I found that one major advantage of the map engine in script was simply that it is easier to write something purely behavioural like that in JS. It needs much less debugging because it has fewer bugs in JS.

It's also easily adaptable by the community. ;)

That's true, but also remember that, as discussed in this very thread, due to subtle, easy-to-take-for-granted design choices (such as that infamous edge script triggering double-snafu I hit) it's already pretty extensible as-is. Your Blockman game is proof of that. :D And Lithonite...

That's true, but also remember that, as discussed in this very thread, due to subtle, easy-to-take-for-granted design choices (such as that infamous edge script triggering double-snafu I hit) it's already pretty extensible as-is. Your Blockman game is proof of that. :D And Lithonite...

Well that's because of SetUpdateScript and SetRenderScript. Basically it let's you "have at it", that coupled with the copious number of getters and setter available to you, there's little that can stand in your way. That said it's still not 100% flexible and even Lithonite would have been easier to code / maintain if it knew to hook into certain areas of the engine easier. There's a lot of hack code too, as a result of Sphere's map API. But it is rather open.

I mean, most maps are indeed very simple structures. You have tiles, layers, entities, zones & triggers. Some objects have obstruction, some tiles have animations, some layers move or parallax. It really covers everything.

That said there currently is no way to exclusively draw a map wherever you want. It'd be nice to treat maps like a standalone object, such that you can muck with it's properties after loading, and draw portions of you choice of the map, wherever, whenever. That's quite hard in Sphere since you are limited to one map per screen. There are double camera tricks, but it can only happen on the same map... unless you write your own map loading call.

I want an engine where I can load up and string maps end to end, with some dynamic calls. Allocate some maps, and deallocate those of which that are out of screen, and then reload them when you are near again. I used this tactic in other game engines to create 'infinite' maps. Maps without borders, but are loaded by stringing maps end-to-end dynamically. The performance benefit is obvious here since you aren't loading a 999x999 sized map all at once.

That's actually a really good idea, I'll have to include the config core as a system script now. :). I was thinking it would look something like the Xrossbar menu on the PS3, with an optional game-specific background taken from the game.sgm root, similar to how icon.png is now. This way if a dev chooses not to make their own config, the default one won't completely clash with whatever they make.

That said there currently is no way to exclusively draw a map wherever you want. It'd be nice to treat maps like a standalone object, such that you can muck with it's properties after loading, and draw portions of you choice of the map, wherever, whenever. That's quite hard in Sphere since you are limited to one map per screen. There are double camera tricks, but it can only happen on the same map... unless you write your own map loading call.

I want an engine where I can load up and string maps end to end, with some dynamic calls. Allocate some maps, and deallocate those of which that are out of screen, and then reload them when you are near again. I used this tactic in other game engines to create 'infinite' maps. Maps without borders, but are loaded by stringing maps end-to-end dynamically. The performance benefit is obvious here since you aren't loading a 999x999 sized map all at once.

See, if I were writing an engine like Sphere from scratch (i.e. without a base to work from), I almost certainly would have done the map engine in script and included it as a system script (I probably wouldn't have chosen JS though, Lua would have been my first choice I think). But, knowing what I do now, I'd want a default map engine of some sort built into the engine. An additional RequireScript() doesn't sound like much to you or me, but let me just say from experience, it's a big deal for someone just learning Sphere. The first time I used Require/EvaluateScript in a game was something of a rite of passage; it was like I was graduating from "Sphere novice" to "advanced Sphere guy". :P Don't underestimate the value of being able to do a ton of stuff without importing a single external script--it's empowering and is, in large part, what's made Sphere so approachable over the years.

Moving on: Regarding your ideas, let me just tell you a story. Everyone thinks they want an object-oriented map engine, but I actually wrote one years ago in C++ and I hated using it. NPC management was a pain in the ass, and just in general, putting together a working game required a bunch of tedious micromanagement of entity objects. This wasn't a fault of the map engine itself--it was quite powerful--but simply that encapsulation isn't well suited to managing a map engine with all its various interconnected components. In minisphere for instance there is very much a circular dependency between the map engine and persons manager that makes it hard to fully componentize.

What it basically comes down to is that OOP relies on the assumption that, as long as someone, somewhere, holds a reference to an object, that object remains valid. So now, assume for the sake of argument that you do this:

var townMap = new Map('MarketTown.rmp');if (/* some condition that triggers this guy being there */) { var traveler = new Person("Some Guy", "TravelingSalesman.rss", map); // or maybe: townMap.createPerson(...)}// some more code and somewhere along the way, a reference to the traveler object is stored// and persists past map destruction

The problem is, if `townMap` gets unloaded somewhere along the way, `traveler` is implicitly disposed and it's no longer safe to use any references to it. Even though the object that holds the reference may have no way of knowing that. This is why I like Sphere's system of decoupling persons from maps and referencing them by name: If all you have is a name, there are no assumptions that the person exists at any given moment, and it's then natural to call DoesPersonExist() first to check. `person.doesExist()` is more awkward is totally against the OOP philosophy: The fact I have a reference at all and haven't explicitly disposed it should automatically mean it exists.

The alternative, of course, is to make Person objects completely independent from Map objects. But at that point we're essentially back where we started, just with some fancy constructors tacked on. And it's *still* not safe for the map engine to automatically destroy them since even in this case, object references are being passed around.

Being able to load and chain together multiple maps via independent objects would be nice, of course, I'm just not sure it's worth all the headaches.

@DaVince: I added some console output to the latest builds, including what you suggested, printing out the error message (and file/line) for uncaught JS exceptions. It also logs loading and unloading sounds, which I'm not sure whether that's being too verbose or not...

Mainly I'm just afraid that too many printf's will be a performance issue.

@DaVince: I added some console output to the latest builds, including what you suggested, printing out the error message (and file/line) for uncaught JS exceptions. It also logs loading and unloading sounds, which I'm not sure whether that's being too verbose or not...

Mainly I'm just afraid that too many printf's will be a performance issue.

It really can be on Windows. The console is silly slow there. Everywhere else, the slow part is the format string parsing.

LordEnglish: Hey, all I can say is OOP maps is a solved problem, the way we deal with entities may have to change. That said Sphere's API really does simplify a lot, but it will always be an amateur API in my mind.

That said even if you don't go OOP on maps you can still have a system where you load up a map and draw potions of it on screen, because I know that is a hard problem to solve in Sphere presently.

// basically you can only call this inside a MapEngine context// it loads the map, puts it's characters into the same entity batch as the map engine,// then draws it's tiles and obstructions starting from the specified offset (in this case 640x0)// functions like DoesPersonExist are still preserved and you still can't make assumptions on the existence of entities.var map = LoadMap("map.rmp", 640, 0);

The camera is the hardest part to figure out, because now we are giving freedom as to where you put the map. It's easier in fact to tell Sphere to instead, put the map on the edge of another map, moving or removing the edge script and making the camera realize there is in fact more to scroll to.

Now that I think about it some more, splicing maps together like this actually seems like a hack. It's essentially an optimization to avoid loading the whole map into memory at once, right? Which makes sense, but wouldn't it be better--and simpler--to solve the problem in the map engine itself (whether in script or native, OO or otherwise), where if you have a huge map, the engine can automatically load and unload pieces of it on demand, just like how, when you have a huge, multi-gigabyte file, opening it in hex editor is instantaneous because it only loads a few KB at a time.

Essentially we'd be letting the map engine "stream" the map, while still allowing you to work on it as one huge world in the editor.

It's not all that difficult to make a basic OOP map engine that is fairly simple to use. I did it, or at least got the rough outline of it as the core of the TurboSphere map engine. It's all object based, and it works pretty easily.

I did make persons belong strongly to maps. It's not that bad a thing to do, it works fairly well.

You don't need to make a doesExist method. You just need to maintain an array of persons for the map. If the person is not in that array, they aren't on that map.

But I also believe that the map engine does not belong as a native, core part of the engine. It's one thing to include one, but it's not a core function. Chad Austin came to this realization before Sphere 1.0 was even released. He decided it would be better to expose a simple but well thought out scene graph and scene manager rather than a rigid map engine.

Both those components are a part of Pegasus. I disagree with some others on the necessity of the scene manager. I think it's fine for this:

to hang the engine. If we subscribe to a Mozilla-style view of JavaScript, where it is the C or Assembly of the web or our games, we need to trust it with tasks we trust C with. Even like managing the event loop.

It's not all that difficult to make a basic OOP map engine that is fairly simple to use. I did it, or at least got the rough outline of it as the core of the TurboSphere map engine. It's all object based, and it works pretty easily.

I did make persons belong strongly to maps. It's not that bad a thing to do, it works fairly well.

You don't need to make a doesExist method. You just need to maintain an array of persons for the map. If the person is not in that array, they aren't on that map.

But I also believe that the map engine does not belong as a native, core part of the engine. It's one thing to include one, but it's not a core function. Chad Austin came to this realization before Sphere 1.0 was even released. He decided it would be better to expose a simple but well thought out scene graph and scene manager rather than a rigid map engine.

Both those components are a part of Pegasus. I disagree with some others on the necessity of the scene manager. I think it's fine for this:

to hang the engine. If we subscribe to a Mozilla-style view of JavaScript, where it is the C or Assembly of the web or our games, we need to trust it with tasks we trust C with. Even like managing the event loop.

Totally agree on that last part.

As for the object-oriented maps, let's consider a scenario:* As you describe, there is an array of entities that each map exposes.* Someone takes a reference to an entity from that array, and it gets passed around to a bunch of functions.* The entity reference is ultimately saved somewhere for later use, despite its volatility.* The map the entity came from gets unloaded. The entity goes with it.* The object holding the reference has no idea the entity has disappeared and attempts to call methods on it.* Game goes kaboom due to unexpected, and therefore uncaught, exception ("entity has been destroyed").

This can of course be dealt with by someone knowledgeable in OOP (don't pass around borrowed references), but let's not fool ourselves into thinking a good deal more vigilance is required. I myself have made mistakes like what I described above. This is the kind of thing that's likely to scare off novices, which is something we definitely DON'T want.

I don't know, I'm starting to feel like I have a totally different view of "what Sphere is" compared to everyone else here. Either that or I'm just better at remembering what it was like to be a novice... Either way, I'm leaving the Sphere 1.x map engine as part of minisphere. The entire engine is less than 2MB anyway, so it can hardly be considered bloat. Ultimately what it comes down to is that I'm a fan of "useful defaults": If someone wants to step outside the box that's fine, but sometimes it helps to know where the box is in the first place. ;)

Maybe some day I'll write a replacement map engine for Sphere in JS. But I'll be perfectly honest, I haven't yet felt the need to do so.

As for the stage manager: I honestly have no clue what the thing is. I saw it when I was perusing the Pegasus repo and even read the code, but I still have no idea what it's supposed to do.

I'm not saying that I don't think we should include a default map engine. Just that, for TurboSphere, I want it to be implemented in terms of the engine's API, and not exist as a direct part of that API.

As for the object-oriented maps, let's consider a scenario:* As you describe, there is an array of entities that each map exposes.* Someone takes a reference to an entity from that array, and it gets passed around to a bunch of functions.* The entity reference is ultimately saved somewhere for later use, despite its volatility.* The map the entity came from gets unloaded. The entity goes with it.* The object holding the reference has no idea the entity has disappeared and attempts to call methods on it.* Game goes kaboom due to unexpected, and therefore uncaught, exception ("entity has been destroyed").

This can of course be dealt with by someone knowledgeable in OOP (don't pass around borrowed references), but let's not fool ourselves into thinking a good deal more vigilance is required. I myself have made mistakes like what I described above. This is the kind of thing that's likely to scare off novices, which is something we definitely DON'T want.

I guess to me I don't really see why this would be all that different than if you used the name of a person that had been destroyed in a previous map in the 1.5 API.

I guess to me I don't really see why this would be all that different than if you used the name of a person that had been destroyed in a previous map in the 1.5 API.

It might just be my pragmatism kicking in. If all I have is a primitive type (string, integer, whatnot) for a reference, I fully expect the thing it references to be pulled out from under me and I'm more likely to remember to check for existence at critical moments as a result. Object references I treat as essentially being the object they reference, so I don't expect it to suddenly disappear without my knowing about it.

In that respect, though, the person does still exist. If they are no longer attached to a map, they could be placed back on a map, and it would work fine. It's just that you can't be sure if they are on a map unless you know what map they should be on. Since there can be a lot more to a person than what the faux-constructor exposes, this is a chief strength of this approach.

But in this scenario, you would be expressly drawing and updating certain maps. So you do know which maps are active and when, and you could find out pretty easily if the person was a part of an active map.

In my implementation, they could also (probably to some bad effect) be in multiple maps at once. But I haven't considered the issue of really drawing and updating multiple maps yet, other than seeing it's possible. Perhaps at that point, recursive map/person objects would be better? Or to only have a person reference their map and not the other way around? I have no idea.

Doing it as you do, making persons not attached directly to maps works better with this, then, since there is just a single list of persons that are active and updated with maps. If you were to reference the person's owning map from the person, too, that would (I suspect) be a simple way to support multiple simultaneous maps.

Now that I think about it some more, splicing maps together like this actually seems like a hack. It's essentially an optimization to avoid loading the whole map into memory at once, right? Which makes sense, but wouldn't it be better--and simpler--to solve the problem in the map engine itself (whether in script or native, OO or otherwise), where if you have a huge map, the engine can automatically load and unload pieces of it on demand, just like how, when you have a huge, multi-gigabyte file, opening it in hex editor is instantaneous because it only loads a few KB at a time.

I know what you mean, my Sphere Studio does that fast loading (well, technically it stores the integers into memory but that's far cheaper than the grid of tiles. I create these buffer zones, totally inspired by Google Map and I draw those on screen only when they come into view, but they always keep a weak reference to the tiles that belong to them).

That said, yes I am in support of better map streaming, but I still think that you are getting messy with sprites on far corners of the map, and managing huge obstruction grids, but to be perfectly honest I don't know how bad the performance drain really is. I just wonder if you can reference an entity by name and they better exist, even if they hadn't been loaded in yet since technically they are on the far side of the map and not yet "streamed in". This is why performance might be na issue which is why I wanted to go with the cell-like structure that even 3D games like Morrowind used when loading neighboring maps. With the programmer managing the cells there's no illusion to their existence, you'd know if you streamed them in.

I mean Morrowind had to deal with the same issues: referencing an entity on the far end of a map and then waiting until they suddenly deallocate. I've seen this happen and maybe it's a partial cause to the Crash to Desktop people witness. But most of the time even though the reference to the object goes away most classes seem to handle it just fine (damage does nothing, arrows pass through them, minimap indicators disappear, etc.) but then again you may also be right that it could be due to discipline.

And you are right again in that Sphere should be easy to learn. But many things are easy to learn and difficult to master (take StarCraft for instance). I think we can add a more advanced OO API in addition to a functional API like we have, that's all.

In fact, I have made an OO implementation of Sphere person's by wrapping all the get/set method.

[gist=563ba8a4bc6c199877a9][/gist]

I'll say the gist feature is my #1 favorite feature of these forums.

I'll also add that since entities are names I use a cache table in addition to the above so I can always reuse the API without creating more classes (though in reality this is very lightweight).

That's why I think the streaming should be handled in the map engine itself rather than the user splicing them together manually from outside. The map engine is in a much better position to handle difficult cases such as you describe (entities outside the current "load window", etc.) as it has more complete information. Anything done from outside involves a lot more guesswork.

That said, the Sphere map engine is very lightweight: a map is essentially just an array of integers, a tileset (usually not a huge image) and some entity data. Even a 1000x1000 map is about 4MB worth of tile indices per layer and a single tileset. There's basically no benefit to streaming it from disk when you have multiple gigabytes of ram to work with.

That said, the Sphere map engine is very lightweight: a map is essentially just an array of integers, a tileset (usually not a huge image) and some entity data. Even a 1000x1000 map is about 4MB worth of tile indices and a single tileset. There's basically no benefit to streaming it from disk when you have multiple gigabytes of ram to work with.

Yes I know it's no much but I guess I'm more concerned that a bigger map means someone out there will attempt to update 3000 entities simultaneously. But then I guess that's on them then. ;)

Then the only thing I'll add by saying I liked the cell approach better than streaming it all in is because you can grow your maps infinitely in any direction. With one large static map, you kind of pigeon-hole yourself into that size. But I guess maps can always be grown to the right and bottom if needed.

The main advantage to the cell approach that I can see is its potential for dynamism: splicing in a different map depending on different factors. SMB1 World 7-4 type stuff. So it's not entirely without merit. :D

@DaVince Just tried the latest version of Sir Boingers that you sent me via PM, I see you upped the framerate to 60. This made the gameplay very smooth, but apparently had a subtle effect on the jump physics that makes it harder to control. But no crashes. So yeah, it must just be that you have a stock version of Allegro on Linux that still has the buffer overflow bug. Apparently Allegro 5.1.10 is coming out soon, though. :)

What would be a good thing in the engine to be able to configure? Right now all I can think of is the key/button bindings, which hardly seems worth the effort. I need more stuff to be able to work up the ambition to do it. :P

Essentially I calculate the shape's bounding box, and then do a bit of linear interpolation on the vertices to get the U/V values. This works for any number of vertices with no predefined lookup tables needed. :)

There is a downside, of course: If you accept the defaults, the texture basically becomes a decal. This is the one upside of TS's method: If your 4-cornered shape is something other than a rectangle (a rhombus, say), the texture map remains rectangular (0,0)-(1,1) and the image is properly distorted.

Edit: So, new method, still works for any number of vertices but allows the texture to distort (note: assumes clockwise winding starting from top left):

var worker = Threads.create(obj);// do some stuff, and then later, perhaps during an update:Threads.join(worker); // block until worker terminates

...and it will only block the current thread (if any).

For what it's worth I think it might be a good idea to implement some sort of NuGet-type system, where external dependencies such as Link and this can be declared in a the game's metadata and be automatically retrieved. That's a project for another time, though.

For what it's worth I think it might be a good idea to implement some sort of NuGet-type system, where external dependencies such as Link and this can be declared in a the game's metadata and be automatically retrieved. That's a project for another time, though.

Is t that just about a way to load modules that already exist in the engine's search path, whatever that happens to be? I guess it could be extended to search the Internet or something, but I didn't get the feeling that was what it was about. That's more about modularizing stuff to avoid name clashes.

Is t that just about a way to load modules that already exist in the engine's search path, whatever that happens to be? I guess it could be extended to search the Internet or something, but I didn't get the feeling that was what it was about. That's more about modularizing stuff to avoid name clashes.

Well, it's kinda both. Dependency management, name clashes and a tool like bower that you can use to pull dependencies automatically from a server (which is what NuGet is like, or NPM).

But this is more like an editor feature if anything. Unless you want to go the node route and inherently work with modules (meaning we must change the way in which we program and expose the code to all of our games going forward).

One aspect that I find appealing is that, under the plugin model of TurboSphere, you can run dedicated servers for networked games. In the case of TS, you can actually lose the libraries you don't want. The distro becomes smaller. Of course, the flip side is that it is a more complex setup in the first place.

Being able to remove any portion of the engine is important to me. Should someone find the audio plugin unsuitable, for instance, they could write their own or use an alternative, but not lose the other plugins. A Linux model, as opposed to a BSD model, if you will.

But of course, this is an aspect that is rather different in philosophy than Sphere 1.5. It just so happens you can recreate a Sphere-like environment while still working this way.

True, I just don't feel, with minisphere being ~1.75MB for a complete 64-bit Sphere 1.x implementation (okay, so some stuff is missing like the Animation API, sue me :P) that works out of the box, plus all the extras it offers, it's worth adding the overhead of plugins (this is why I preferred the monolithic Allegro build before I switched to static linking--use more than about 2 Allegro components and the monolith DLL is actually smaller than the individual ones).

With TurboSphere the plugin model makes more sense, since it's designed for maximum flexibility. minisphere I see more as a "download it and have a ball" deal.

By the way you might want to update the note about minisphere in the TS readme--I don't think minisphere can be considered in "early development" anymore. ;)

I give to you: minithreads! This is a generic adaptation of the threader I'm using in my game Spectacles: Bruce's Story. It only works out of the box in minisphere, but would probably work in Sphere 1.5 with some tweaking.

minisphere 1.1b3 is now up and available to download. Tons of new features in this one (and a couple more bug fixes too)! The RNG object is one I'm particularly proud of. It's based on MT19937 (AKA Mersenne Twister), has a bunch of different generation methods, and allows manual seeding unlike JS's Math.random(). See the included API documentation for full details on it, it's pretty awesome.

I also took yet another leaf from TurboSphere's book and started on a JS-based "minisphere Runtime", previewed in this beta. 1.1b3 includes minithreads and minidelegate, the functionality of both of which have been invaluable during development of Spectacles and which I imagine will be useful in many, many games. I'm thinking the final 1.1 release will also include a version of Scenario as part of the runtime as well. These scripts can be used like this:

There are three things I want to see fixed sometime before I can even use this engine.

1. Fix the windowstyle bug for windows that have edge widths/heights less than 16 pixels. (See attached).2. Make GetPixel() much faster so all code I have written that incorporates pixel perfect collision can make my game playable. It's too slow right now.3. Fix a weird blit bug. (See attached). Things are offset by half the width of an image, but in other engines that's not the case. Like the hp bar, it's offset wrong. What do you get from image.width/2?

Edit: I will say that I'm impressed. You've really made it work on many games. :) Sometimes it's down to a single feature that a game doesn't run, so good you've got most features implemented.

That rotation bug was a known issue at one point... Then I forgot about it. :P I think Allegro's treatment of the origin during rotation blits is off or something. Either that or more likely, I interpreted it wrong.

The dashed windowstyle... Funny story about that. I didn't really do much testing of Blockman in Sphere 1.5, I was too determined to get it running in minisphere. As a result, I thought that was what it was SUPPOSED to look like. If I had to guess, I'm thinking Allegro is padding out small bitmaps to be 16x16 under DirectX, as the windowstyle oddities doesn't happen with an OpenGL build of Allegro.

And the GetPixel() optimization I keep forgetting to get around to. Thanks for the reminder!

And yes, I was VERY dedicated to making it compatible early in development. I spent literally half a day trying to figure out a bug that caused Aquatis to crash on the opening credits. It turned out to be a stupid refcounting error. :P

I fixed the Image:rotateBlit() issue. It was user error, as I suspected: Allegro treats the X/Y for a rotated blit as the center of rotation, whereas Sphere apparently aligns it to the top-left. It should have been fixed a long time ago, but I forgot all about it once I started working on the map engine.

Moving on... I added pixel caching for Surface:getPixel(). It definitely helped, but it's still ungodly slow. It might help if you stopped creating a surface anew with each collision check. Allegro stores all bitmaps on the GPU, so each time you call Image:createSurface(), a new texture has to be uploaded. Not only that, but it's putting a lot (and I mean A LOT) of stress on the garbage collector: I added some logging for images, and... well, let the console output speak for itself:

So during processing of a single attack, the game created (and possibly destroyed, depending on how aggressive Duktape's GC decided to be) over 1,000 bitmaps. The thing died right away, so my guess is a few attacks got coalesced due to lag, but still: 1,000+ bitmaps! That's insane. That's literally insane. No amount of pixel caching I can do is going to help that. I honestly have no idea why--or HOW--it works so well in Sphere.

HOWEVER, full disclosure--I don't think this is the only issue. What exactly goes on under the hood when you swing the sword? I'm consistently able to drop the framerate to 30-40 fps on my i3 just by slashing at thin air, but I get no log entries that a pixel cache was created during this.

The last thing I have to fix is that windowstyle glitch. I'm not sure how to deal with that yet. I may end up switching to an OpenGL build of Allegro. The only thing that worries me is that OpenGL tends to be slow on Windows, certainly slower than D3D. But it would fix the windowstyle issue, so....

Edit: Yep, same issue with the slashes--simply slashing at thin air creates and destroys nearly 100 bitmaps. Sorry to say, this game is VERY poorly optimized. :( If it were me, what I would do is call .createSurface() once for each relevant sprite frame and then cache those somewhere. This way you can just pull them from the cache and do .getPixel() on them with impunity. As long as the surface contents never change (which they shouldn't), you'll never get a pixel cache miss and Allegro won't have to upload hundreds of textures for every attack.

Edit: Yep, same issue with the slashes--simply slashing at thin air creates and destroys nearly 100 bitmaps. Sorry to say, this game is VERY poorly optimized.

I'm a bit unnerved, really. I honestly don't know what to say. But I'll get to that in a sec, first an explanation. I'll be gentle, don't worry.

So I have no idea how thin air slashing does that. I mean it's just COMMAND_ANIMATE frames. I mean, I did nothing outside the bounds of the map engine for the action system (except the pixel collision detector). I use Pythagorean distance first to check if there are frames to collide with before this whole hundred-sprite-creation thing begins to happen

// search and return a list of enemies in a 16 pixel radius at the front of the character. This is Attack() var list = this.getNearest(16, player.xv*16, player.yv*16); while (i--) { enemy = list[i]; if (this.check(this.input, enemy.name)) { // call the check method //... } }

Thin air slashing ought to put the sword well away from the nearest enemy sprite. And how on Earth could it create a hundred to a thousand frames? Look at the code and think about it. I call the attack script only once on frame change.

Technically my code only has to create bitmaps 2 times per frame (your source and the opponent source). I mean, I'm sure it'll create no more than 10 bitmaps max. I think your engine needs some work here. I mean, there are at least 100 to 1000 pixels to zip through on a dead collision check call, if it occurs. Are you telling me that each time I get a pixel your engine must create and destroy a bitmap? You have power over that my friend, not me. Especially if blank calls to COMMAND_ANIMATE does it. Well, technically running in your engine I can try to mitigate that, but at this point I'm not sure what's possible. I can cache the 2 bitmaps, but then I'm saving these 10 creations each time, the enemy constantly changes, mind you. So I could cache the payer. But if it's really each time a pixel is returned...I'm not sure. I don't want to have to lug around huge caches of enemies and players, or heck, maintain a cache pool if I can help it.

Above surfaces are created but only 2. Only 2 new bitmaps are created per call of check. Per the frames it's called on. Which is precisely frames 1 through 6 except 4. So 5 frames, which is no more than 10 bitmaps being created and thrown away. I check in SSFML, and yep, only 10 bitmaps. There is no lag. I usually don't try to optimize if there's nothing too crazy to optimize. The code I use here is also industry standard (using pythos first, then making sure you only check an intersection of bounding boxes. In fact I doubt more than 256 pixels are ever checked!!). It's really industry leading. It's quite good, my friend of friends. Assuming of course bitmap creation is relatively cheap. If it's not, I can fix this, and you're right about it being unoptimized, but I'd say only slightly so. Because it's either this or cache pooling, and do I really want to do that if this works well enough? I mean each frame the enemy and player changes, and then each direction, for each enemy. There are so many states each bitmap can be in at any given time I'd rather reconstruct than cache, especially if reconstructing like it is in SSFML and Sphere1.5 is as dang fast as it is.

Because...

I only optimize code I've profiled for, looking for bottlenecks. ;) It's really what any sensible programmer would do. You saying the game is not very optimized kinda stings since I strive for that, but only in areas where I needed it. I say your engine is what's unoptimized here buddy since my SSFML handles this even better than Sphere's. The difference being I've used SW bitmaps. Now, I've moved on to HW sprites and noticed compositing was really fast but simple things like updating and creating new bitmaps as well as getting pixels was really slow. So I'm moving back to SW for good even if it means it's "slower".

Edit:I profiled getPixel in SSFML and between 6000 to 2000 pixels are checked. Which is fine. Worst case scenario is 48*48*10 which is 23000ish pixels. Swinging empty air does nothing. No pixels, no bitmaps, nada.

Sorry, I didn't mean to offend you--the game itself really is awesome, and the thousand bitmaps shocked me, too. I'm only able to go by what the few logging calls I've added, but I honestly have no idea why it's creating so many. Hell, I can just walk around aimlessly and get about 5-10 "created image via clone" log entries per second. It makes no sense, because this doesn't happen in Specs or any other Sphere game I've tested. Just yours. Blockman is doing something differently but I don't know what yet. I don't doubt the issue is on my end, though.

What's weird is that it's NOT generating multiple images for the actual pixel check--a successful attack generates a long string of pixelcache hits on the same two images. It's just that it seems to be creating a lot of them in-between each check. Weird.

Totally agreed on not making premature optimizations, don't take that the wrong way. I myself advocate the "don't do it" school of optimization--it's the reason minisphere's codebase is still so clean. :D I admit I jumped to conclusions when I said the game was unoptimized, but as I said, this is literally the ONLY game I've tested that causes so many images to be generated in such a short timeframe. Out of probably a hundred games, both big and small. "Engine bug" was naturally the last thing I would have considered.

So yeah, I thank you for clarifying the under the hood operation--I will now run the MSVC profiler to figure out where all the images are being generated.

Spriteset bitmaps are never written to (only replaced wholesale), so the image cloning was completely unnecessary. I changed the offending clone_image() call to ref_image() and that sped things up a ton. My bad! :-[

Now, if you're wondering why I'm cloning spritesets at all, well, this calls for some background: As you know, I strive for compatibility, and the semantics of Get/SetPersonSpriteset() in Sphere are... odd, to say the least. If you call GetPersonSpriteset() and change stuff around (replacing images, directions, etc.), the changes aren't reflected immediately--you have to call SetPersonSpriteset() to commit the changes. And then, if you make further changes after that, you have to set it again. This is ridiculous and completely counterintuitive, but I have to emulate it to remain compatible in odd corner cases (Aquatis was a wonderful source of these), and doing so means cloning the spriteset every time someone calls either function. And since you use GetPersonSpriteset() a lot... yeah.

One thing I still notice, even with this change, is that I get a lot of this when just walking around aimlessly:

To clarify, those are direct reads of an embedded image from an open file (such as happens when loading a tileset or spriteset). Not sure what's up with that, probably something else stupid I'm doing somewhere.

There is a silver lining, of course... I guess it's a sign of a mature project when you to get to the stage of having to deal with low-level issues like this. :)

Moving on... I added pixel caching for Surface:getPixel(). It definitely helped, but it's still ungodly slow. It might help if you stopped creating a surface anew with each collision check. Allegro stores all bitmaps on the GPU, so each time you call Image:createSurface()

This is why Surfaces are meant to be totally in software. They are supposed to be relatively quick to create, destroy, and manipulate, much faster than Images.

Moving on... I added pixel caching for Surface:getPixel(). It definitely helped, but it's still ungodly slow. It might help if you stopped creating a surface anew with each collision check. Allegro stores all bitmaps on the GPU, so each time you call Image:createSurface()

This is why Surfaces are meant to be totally in software. They are supposed to be relatively quick to create, destroy, and manipulate, much faster than Images.

It would be literally trivial for me to have Allegro create surface bitmaps in memory... but wouldn't blitting Images to Surfaces then be SLOW since you're crossing the hardware boundary? I guess I should do some tests, thanks for the tip.

Edit: Yep, that did the trick! No pixel caching needed! ;D (scratch that, the pixel caching is still needed even with s/w surfaces--apparently al_get_pixel() is slow no matter what.

@Radnen: In case it wasn't clear, your getPixel() woes are fixed in the latest build. Now I just have to tackle that windowstyle issue...

It would be literally trivial for me to have Allegro create surface bitmaps in memory... but wouldn't blitting Images to Surfaces then be SLOW since you're crossing the hardware boundary? I guess I should do some tests, thanks for the tip.

Drawing Surfaces is OK to be slow. It's notably slower drawing Surfaces than Images in Sphere 1.5. That is one of the tradeoffs of Surfaces, and why they are different than Images. Surfaces should be quick to read and write and cheaper to manage, Images should be fast to draw. Other performance aspects are generally irrelevant.

@Flying JesterI knew there had to be a fundamental difference between the two (surface and image) beyond the superficial "you can write to one but not the other". I just couldn't figure out what until you specifically pointed it out. Luckily the way Allegro is set up, it was trivial to have it allocate surfaces in system memory instead of on the GPU. Internally it's still an image_t structure, just that the underlying bitmap is created with different flags.

Honestly I'm pretty dumb for not figuring this out sooner. There's a reason there are methods to convert between the two types!

but as I said, this is literally the ONLY game I've tested that causes so many images to be generated in such a short timeframe. Out of probably a hundred games, both big and small.

I'm glad it was a good test case then. :) My game is really the only mature Sphere ARPG. Other games even Aquatis and T&E use separate views for their battles (take place in turn based arenas) so spriteset related action based things might not happen in the same manner. And I doubt they use pixel perfect collision to the degree that I do.

BTW Lord English I do understand in Sphere and am willing to accept that drawing surfaces and converting to surfaces is expected to be slow and is on the users end to mitigate those calls with their own crafty solutions. But creating a few surfaces here and there ought not to be slow. The next test in Blockman is entering a cave and seeing if the fullscreen darkness "shader" plummets the fps. I'm not the only game to do this since I used SDHawk's (blast from the past) advice on it.

Edit: BTW, running around in Blockman does create dust plumes under his feet, these can be what triggers those surface creations when walking around. Though I don't know why surfaces are created... It does load a new spriteset each time rather than reuse one. It's a stupid Sphere thing since CreatePerson forces you to load a spriteset per entity. I cache spritesets in SSFML, but it has the issue that perhaps each entity can share modifications made against them. Though I haven't seen that in the games I've tested, most games usually copy or reload from file a new spriteset via LoadSpriteset() whenever they modify a users sprite.

They aren't surfaces created, they are images, read as raw RGBA data from an open file. Three things do this: load_tileset(), load_spriteset() and load_windowstyle(). So yeah, thanks for the tip on the dust plumes, I hadn't noticed those. :) There is a way you can avoid recreating new entities every time, just use SetPersonVisible and reuse them... But I agree it's pretty dumb that it doesn't let you pass in a Spriteset object to CreatePerson(). I think I'll go implement that now.

There is a way you can avoid recreating new entities every time, just use SetPersonVisible and reuse them...

Neat idea, but you can have more than 2 dust plumes on screen so I'd have to craftily cycle anywhere between 2 to 4 them and that's a kind of complexity I didn't want to do. It seems that there is one pervasive issue with Sphere's API. Without client-side pooling and caching most calls to the Sphere API copy and clone data with reckless abandon. It's either you trust the underlying engine does a good job handling that for you, or you write lots of boilerplate whenever you need some simple effect.

... it's pretty dumb that it doesn't let you pass in a Spriteset object to CreatePerson(). I think I'll go implement that now.

That's a good step in the right direction. Oftentimes and in most other game engines many duplicates of objects like bushes, grass, footsteps in sand or snow, coins, etc., reuse the same asset to reduce the memory footprint. So, being able to directly tell Sphere that we intend to reuse the same spriteset in any number of entities can really aid in speeding things up. Creating and destroying entities is usually a cheap thing to do, I mean it really only encodes a few properties (mainly positional, nothing a matrix can't solve, really).

Also, imagine drawing to screen 30 entities with the same sprite atlas. You'll have sped drawing up considerably since you aren't changing the source texture each time. Games like DaVince's Sir Boingers can be sped up with this technique.

Now, I'm not sure here but Sphere has to cache Spritesets like my SSFML does. I can't imagine loading the same spriteset 300 times in a giant room with lots of coins in it. But who knows? It might do that? I'm not sure, I'll have to profile a demo.

... it's pretty dumb that it doesn't let you pass in a Spriteset object to CreatePerson(). I think I'll go implement that now.

That's a good step in the right direction. Oftentimes and in most other game engines many duplicates of objects like bushes, grass, footsteps in sand or snow, coins, etc., reuse the same asset to reduce the memory footprint. So, being able to directly tell Sphere that we intend to reuse the same spriteset in any number of entities can really aid in speeding things up. Creating and destroying entities is usually a cheap thing to do, I mean it really only encodes a few properties (mainly positional, nothing a matrix can't solve, really).

Done. It a rather simple change, actually. Just some additional bookkeeping, and even that wasn't really an issue either as spritesets are already refcounted internally.

While we're on the subject of profiling and performance, you know how Blockman takes an coon's age to load fonts under minisphere on startup? I fixed it. Turns out the reason it was so painfully slow was because I was locking and unlocking each individual subimage (fonts are atlased) when loading characters. That's 256 lock/unlock cycles, meaning data has to be uploaded to GPU every single time. Now I lock the entire atlas ONCE, load all the glyphs, and then unlock it. That's only one GPU upload. The "Loading Fonts" text goes by so fast now you can barely even see it. ;D

Now those slow map loads have me wondering...

Edit: Okay, map loads are much faster now too, after an edit to the tileset loader. It was the same issue as with fonts, the issue was just less pronounced as most tilesets don't have 200+ tiles in them and even then, you're only loading one at a time. I should make a similar change the spriteset loading code, but it will be more difficult as spritesets aren't atlased. At the time, it didn't seem worth it to atlas them since you're only usually drawing one image from a spriteset at a time. But I might just do it anyway now to speed up map loading...

I just refactored minisphere's image locking. It's safe to nest locks, any lock requests past the first just reuse the existing lock, which is refcounted. Allegro would just outright refuse to lock the bitmap a second time, which is how my atlased loaders ended up so slow. Now I can lock the atlas at the beginning of the loader, and the individual read_subimage() calls will just reuse the existing lock.

This is awesome, as now I can easily implement spriteset atlasing. :D

Edit: Not only have I implemented sprite atlasing, but I also went ahead and added a spriteset caching feature. Radnen, could you run your map load tests again on the latest source? I'd be curious to see the results.

/* This used to be an iOS/Android only workaround - but * Intel is making GPUs with the same chips now. Very * small textures can have garbage pixels and FBOs don't * work with them on some of these chips. This is a * workaround. */ if (true_w < 16) true_w = 16; if (true_h < 16) true_h = 16;

Unfortunately this means windowstyles can't be tiled in hardware--I have to do it manually and take the performance hit.

Alternatively, I could comment out those two lines and see what happens. I have an Intel GPU laptop (Core i3), so I'll know if anything's amiss.

Unfortunately this means windowstyles can't be tiled in hardware--I have to do it manually and take the performance hit.

Tile it in hardware anyways. If you witness sizes less than 16, switch to manual. But anyways 16 was the sphere windowstyle default. I usually use that size and larger, but sometimes things slip through.

So I did a stress test in Sphere 1.5, SSFML 0.9.0, and minisphere 1.1b4

This is running at 26fps with 500 entities in SSFMLhttps://www.dropbox.com/s/cnaylep3xytgqdl/stress-ssfml.png?dl=0

This is running at 21fps with 250 entities in Minispherehttps://www.dropbox.com/s/8p9u3kzejhu8nvv/stress.png?dl=0

This is running at 17fps with 250 entities in Sphere 1.5 in SphereGLhttps://www.dropbox.com/s/4nflt2g7cg4mkgc/stress-sphere15.png?dl=0

All fps's are +/- 5.

And well... Sphere 1.5 couldn't do 50 on Standard32. This test was on Intel Core i5 3.3@3.6ghz, with an Nvidia GTX970, 8GB 1066@800Mhz ram. I think it's the JS logic that's bottlenecking the two good engines, and the graphics plus the logic for Sphere 1.5. In SphereGL I got by no different than minisphere, which is telling. You are not taking advantage of the hardware on the computer, it tells me you're still mostly drawing in immediate mode which is what kinda plagued SphereGL and Sphere in general. I know this since I know your JS engine is faster in most cases to Sphere 1.5.

My max target for the space game is 300 enemies on screen. But this rest is more of a curiosity. In the game you never see more than 20 anyways, unless there's a giant space battle programmed into it. But I think the stress test is still neat. No engine crashed BTW.

Ok, so... minisphere 1.1b4 loaded blockman much faster! The combat was also nice and smooth. :) But it did crash after playing for a while when I swung my sword at an enemy. So there's something there, maybe a get pixel call out of bounds?

I could speed up the windowstyle loading too if I atlased them, but then hardware tiling doesn't work. The main loading bottleneck was fonts and spritesets (and maps), which have been speed up a ton not only due to atlased loading in 1.1b4, but also spriteset pooling.

But yeah, most of the drawing is done in immediate mode because for some strange reason, Allegro doesn't always honor transformations when using batched mode. This is needed because I use a transform to scale up the window for 320x240 games. I'd rather take the performance hit than end up with dodgy rendering.

I assume you noticed your windowstyles render properly now? I bit the bullet and compiled Allegro with the 16x16 texture clamping commented out. So far I haven't had any issues, so... *crosses fingers*

As for those crashes, I've seen a few of them myself, but I haven't tracked down the cause yet. Hence why minisphere 1.1 is still in beta. ;)

You might want to stay in immediate mode for now. I'm taking a small risk batching everything. I'm meaning to create a small batching API to make it explicit. But I have found through my testing that even implicit batching is decent enough, and really only helps when you have much of the same sprite, like the above where the enemies and particles and bullets were the same 3 textures.

I guess if you stay in the map engine, implicit batching really is not needed since sprite atlasing covers that. The implicit batching I do to speed up the space game only really works when I program knowing that this behavior exists and that I can draw images in a custom engine rather than use spritesets in the map engine. There is a slight speedup drawing names on their own layer rather than in an A/B pattern. But it's minimal.

So it didn't make it into 1.1b4, but I just added a console and BGM manager to the mini runtime, both originally coded for Specs.

The console is output-only (for now), but optionally lets you log output to a file, and because it uses minithreads, lets you pull up the console at any time during gameplay. This little tool has been invaluable in debugging Specs glitches, and is generic enough that I thought it'd make a good addition to the runtime. :)

The BGM manager right now is a bit of a fixer-upper, but the intent is to turn it into a simple stack-based music switcher. You push to change the song, and pop to return to the previous one (perhaps resuming where that one left off). I might also add a "layer 0" as well for field music, which can be changed in place but only plays when there are no other tracks on the BGM stack.

So I got bored and implemented basic command support in miniconsole. It's a very easy-to-parse command format--e.g. battle rsb2 for a test battle in Spectacles. So now anyone that wants to implement a basic console in their game will have one ready to go!

Then the player could pull up the console and type in:bear munch lauren

And the map person named "lauren" would get eaten by the bear and disappear. How it is parsed is, the first token is the object name (bear) as passed to mini.Console.register(), the second token is the command name (munch), and the remaining tokens are passed as string parameters to the relevant method. The actual call is also wrapped in a try/catch to try to prevent game crashes due to bad console input.

minisphere 1.1 is going to be delayed by a bit, it seems. I apparently broke something when adapting Scenario and now it locks up sometimes during scene execution. I haven't been able to track down the cause. It's odd, the game seems to completely lock up, but closing the minisphere window works, which means FlipScreen is being called.

I suspect a bad interaction between the Scenario threader and minithreads is causing a deadlock. I didn't even think that was possible with cooperative threading (making a distinction between a deadlock and an infinite loop, before anyone calls me on it), but...

So I think I'm going to end up releasing minisphere 1.1 without the runtime.

As it stands right now, all runtime components rely heavily on threads. And as I've just found out, minithreads has a rather massive design flaw: Because join is emulated with recursion, joins don't always do what you expect: Assuming two simultaneous joins, satisfying the first one is--by definition of recursion--necessarily contingent on the second one returning. Even if the first join would otherwise be satisfied first, in practice it can't be because one further down the rabbit hole is still blocked. Sometimes--aw, who am I kidding, way too often--this can even cause a deadlock.

For whatever the reason, as long as I've been using this threader in Specs, this never bit me before now. I guess Specs alone just didn't tax the system enough to flush it out--it wasn't until I tried to reimplement Scenario in terms of joins that it showed up, and struck HARD as Scenario absolutely requires reliable concurrency. What sucks is that it took me all day to figure it out, after many exhausting hours of misguided hacking trying to fix what couldn't be fixed.

Curious how I finally figured it out? I added two GetSeconds() calls to Scenario's tween scenelet, one in start and another in finish. And lo and behold, one particular tween that was supposed to take half a second... didn't finish up until 12 seconds later. I puzzled for a bit, and then it dawned on me what was going on... and I felt like a complete idiot. :-[

Curious how I finally figured it out? I added two GetSeconds() calls to Scenario's tween scenelet, one in start and another in finish. And lo and behold, one particular tween that was supposed to take half a second... didn't finish up until 12 seconds later. I puzzled for a bit, and then it dawned on me what was going on... and I felt like a complete idiot. :-[

That's not being an idiot, sometimes sanity checks once and a while help. Now, how are you going to solve it, that's the question. Deadlocks usually arrive because of a lack of concurrency handling, every threaded system has mutex locks, semaphores even busy-wait loops, you just need to pick solution(s) that work.

But I don't think this is a deadlock. It might be a race condition since after 12 seconds it finished rather than .5... a deadlock is most usually... dead! A race condition means things are vying for cycles and other loops/threads get pushed back. In fact I'm sure that 12 seconds is variable. Is it 13 next time, immidiate another, 5 seconds?

Note that it loops until the requested thread(s) finish. This works well enough--if there is only one outstanding join. Trouble is, Scenario is often waiting on many things at once. At this point, the recursive system breaks down.

Let's simplify things a bit and say we have four running threads, call them A, B, C and D.* A joins B, which prevents A from being updated until B terminates. So far so good.* .join() is running its own loop, so B, C, and D keep updating.* At some point (A is still waiting on B to finish), C joins D.* B terminates. A's join now can't be satisfied because, by definition of recursion, it is itself blocked by C's join. D may not terminate until some way down the line, which means it's unintentionally holding up the works.

And yes, this system can give rise to a deadlock very easily. In the simplest case, this will do it:* A joins B.* B joins A.

In practice, such cycles will be (and were!) much more roundabout and therefore difficult to debug.

Note that, due to the way the system is designed, the effects of this may not be immediately obvious as other threads will continue to update (just like preemptive threading!). However, if what A is trying to accomplish is necessary for the game to continue (hence why B wanted to wait on it in the first place), this will put the game in an unrecoverable state.

I made the error text mandatory instead of optional to encourage meaningful asserts. If an assert fails (the condition is false), the specified error text will be displayed in a modal popup allowing the user to choose whether to continue or terminate. As with Abort(), the optional stack offset is used to blame the failure on a function earlier in the call stack.

Hm... now that I think about it, Assert should probably behave differently in the console vs. release engines. In a release build (engine.exe, engine64.exe), a failed Assert should terminate the engine unconditionally (without giving you the yes/no options), while the Console build (console.exe, console64.exe) would log the assert to stderr and give you the option to try to continue.

As for that threader issue, what I think I'm going to do is modify the semantics of join. Rather than block the caller directly, it will store the joined tids in the calling thread's "join list", and that thread will not get any further update() calls until all the joined threads have terminated. This will require a few architectural changes to Specs, but so be it. I'll definitely miss the blocking .join() though. It almost perfectly emulates Pthreads join, but that "almost" turned out to be the killer.

I think it has to do with the domain bounds, between script engine and native execution because even with native side pixel caching, engine based caching is faster to retrieve from. The only downside to the above is, notice the rotate, I have to call the update method each time to get a fresh list. But my code only rotated the image once. The speedup isn't huge, though. Testing on 500 static images, the engine used to halt entirely in our engines. With this addition there is no visible halting, everything is just slow, like 10-17fps slow, but consistent which says this is much faster. Though in practice it may be slower, especially if you modify the surface a lot with rotations and other methods (I only wrapped the rotate method).

In Sphere1.5 the above errors with an out of memory error, after about 40 entities.

This makes sense. When calling getPixel() directly, even though the engine is caching it, you still have the overhead of a function call per pixel. In Duktape, a JS->C call is identical to a JS-JS call except for the last step (call into native instead of bytecode)--in fact it may even be faster because some of the call setup can be skipped (arguments object creation, etc.). But the fact remains that calling a function in JS is a lot more expensive than in native. Caching the pixels locally avoids that, as then the JS engine just has to retrieve values from an array, which is trivial.

By the way, the out of memory errors in 1.5... You will see those a lot. It only allocates 5MB to the JS context!

I just added a new API: DoAsync(). This queues a script to be executed on the next FlipScreen. It's like what setTimeout(fn, 0) does in a browser. I added this mostly because of minipact, since according to the Promises/A+ spec, promise resolution must be asynchronous, outside the usual program flow.

So using promises for minithreads turned out to be inadequate. They work well enough for Scenario which creates a bunch of one-off threads and runs them in parallel, only occasionally stopping to resync timelines. But for more complex threading, like waiting on a menu thread during a battle, things get awkward because the battle thread still updates in the meantime.

What I'm going to do is change the semantics of join(). It will still return a promise, but it will ALSO exclude the calling thread from further update() calls until the threads being waited on finish. This way join() would still work mostly like it does in Pthreads without holding up the works with recursive event loops, and the promise would take care of post-join logic (such as queuing a move, etc.)

Edit: On second thought, I'm not even going to do that. Blocking join works fine for 90% of use cases, it's only interlacing joins that cause issues. I'll just make a note not to do that in the documentation. :)

@RadnenI figured out the Blockman crashes. The getPixel calls were fine, none were out of range--though I added bounds checking anyway, since Sphere also checks it (an out of range getPixel() will throw in 1.5). The crash was here:

As part of update processing for persons, they can end up being deleted (if a command generator script destroys one, say), which is exactly what happened here. Once I reproduced the crash, I checked the variables. i = 3 and s_num_persons = 3, which meant one was deleted, but it was still trying to access the person structure, causing a crash. Should be an easy fix.

1.1b5 is out. A couple bug fixes in this one, as well as two new APIs: Async() (required for promise compliance, see changelog) and Assert(), very useful for debugging. This will be the last beta ahead of 1.1, now I want to concentrate on finishing up the API documentation before release, and maybe write that config tool...

I decided to go in a different direction with the customizable key mappings. I added a new API, SetPlayerKey(), to change the key mappings at runtime; any such changes are then saved out to disk on shutdown. What I'm thinking is, I will add commands to miniconsole so that any game using the minisphere Runtime can have its keymap changed by the player through the console. miniconfig as a separate thing will still exist, of course, but its scope will be enlarged: Allowing key mappings to be changed for any game minisphere has previously run or otherwise knows about.

This will allow me to work on miniconfig at my own pace, rather than having to rush it to make the 1.1 release. I can release it separately when it's ready. :-)

I like the idea. I've always wanted many config related options to be game specific. Hence why I never used the config.exe tool to set up key mappings, that and having the ability to set them and save them in game is always nice.

@RadnenSo I finally got around to implementing gradient circles, and was therefore able to test out the cave lighting effect in Blockman. Results: Success! Not only does the effect look great, but it runs at full speed. See screenshot below. ;D

No, I had to do it myself using libmng and loading the frames into locked surfaces. You'd think Allegro would have it, but nope. Luckily I was able to use the Sphere source as a reference again, to lessen the learning curve a bit.

Edit: It's funny, I wasn't originally going to do it, I was just going to have some stub APIs in place to allow games using the functions to get by, but once the stubs were in place, I said ah, why not. I'm used to the hassles of compiling dependencies on Windows by now, so what's another library? :P

Edit 2: I got the 64-bit Windows build of minisphere back down to under 1.7MB by rebuilding everything optimizing for size instead of speed. :D I don't appear to have taken a visible performance hit by doing so, but time will tell...

minisphere 1.1.1 is up. This adds the animation support and finally fixes GradientCircle, which I've been too lazy to fix up until now. Also, the windowstyle rendering should be fixed on all platforms as I added a workaround (i.e. tile in software) for images < 16x16.

I've decided to go to an Allegro-style "tick-tock" versioning cycle for minisphere: Even-numbered versions (e.g. 1.0) are stable and only receive bugfixes, while odd versions (e.g. 1.1) are considered WIP and can get new features (or have them removed) at any time. I like this setup because it allows more public testing to be done on new features before they get committed to a genuine Stable release.

1.1.3 has been posted. Just a maintenance release, nothing groundbreaking this time. ;)

At this point it seems the only thing I'm really missing is a particle engine. Sphere 1.6 had one from what I understand, and that's one thing that would definitely benefit from being implemented natively, I think. It can be done in script, but I'd imagine it might be slow then.

Which of course breaks in minisphere, and probably Sphere 1.6, because both support named layers. If this were consistent, I could write it off as the game making misguided assumptions about the underlying engine... but then I see just as often:

Considering how the code is full of jokes (like new retard()), that wouldn't surprise me. Then again, he also told me that he was shitty at coding. KR was the project that helped him learn, and he didn't fix old code. That really turns things into a mess.

And thanks a lot for the new release. ;D

Edit: yep, this game is pretty broken. After fixing a line of SetPersonLayer() and saving a PNG camouflaged as a BMP as an actual BMP, the game runs, but there are lots of problems. Can't enter most doors, can't talk to most people. I'm just impressed it's working this well besides those problems.

Edit: yep, this game is pretty broken. After fixing a line of SetPersonLayer() and saving a PNG camouflaged as a BMP as an actual BMP, the game runs, but there are lots of problems. Can't enter most doors, can't talk to most people. I'm just impressed it's working this well besides those problems.

Actually, on further testing... I think I broke something. Person-person collision is screwy. I definitely remember being blocked by those NPCs on my initial playtests, but now you can walk right through most of them... which also means you can't talk to them because the engine does a collision check to find persons to talk to.

Edit: Ah ha! I figured it out. This is a long-standing engine bug that it took this horrendously buggy game to uncover. I must have been mistaken about the collision working before, that was probably one of my Sphere 1.5 tests before I got minisphere to run the game. Anyway, the bug is that minisphere doesn't normalize the spriteset base. Sphere does, and it seems KR has several spritesets with degenerate bases where x1 > x2 and/or y1 > y2. This causes the obstruction checks to fail.

It took me forever to figure this out because I was operating on the assumption this was a layering bug. Not even close! :P

See, this is what's made minisphere what it is: no matter how broken my test game is, I work on the basis that, if it works properly in Sphere but not in minisphere, then the issue must be on my end (I was perhaps too hard on Blockman earlier, but regardless, this applied there as well). I'm still very dedicated to compatibility. :) Of course, there are two cases where I draw the line: I won't relax type checking for API arguments (you're calling into C code, the engine has every right to police it), and I won't emulate bugs.

But if a bug means a game can be playable... It's a tricky situation. You want a clean version of Sphere with no bugs in it, but if you have to incorporate a bug to make a game work... it's not always straightforward isn't it? But then again I guess you could call those bugs "features". :P

It can sometimes be a very fine line to walk, I won't deny that. For example, the color-cycling trick in Sphere is based on what is technically a bug (namely: byte overflow in color components isn't checked for) and when it was brought to my attention I had to think long and hard whether to emulate it. Ultimately I chose not to in the name of consistency (CreateColor can reasonably be considered "canon" and that clamps the values), which of course breaks compatibility. However, it's a trivial enough thing to work around (you can do modulo arithmetic yourself), so I don't consider it a dealbreaker.

Hm, so it appears minisphere's handling of triggers is borked, which is why you can't enter buildings in KR. Unfortunately this doesn't surprise me, that was one area I didn't do much in-house testing on. My test map for Specs does include a trigger, but it's only one. KR tends to cluster them together, and it seems the activation rectangle for individual triggers is so small for whatever reason that they often don't activate at all.

Edit: I did some runs through the debugger. The issue is a weird race condition between KR's custom movement code (I have to give whoever programmed the movement system credit, they basically independently invented Lithonite) and an optimization in minisphere where I only check for trigger activation if the input person has moved since the last frame. For whatever reason the person almost always reports as not moving. I'm not 100% positive yet, but I THINK the root cause is that the game confuses the engine by constantly detaching and attaching input.

Going to make a new post for this because I want it to be seen. This was quite an interesting pursuit.

Got it! I was right, KR detaching and reattaching input during custom movement throws it off. Currently minisphere has an optimization (premature, as I now see) where it runs a trigger check if and only if two conditions are met: 1) There is an input person, and 2) that person has moved since the last frame. In this case, when the engine runs the trigger check, no input is attached because the game reattaches it in a person script. And that script runs on the frame AFTER all movement has ceased:

Note the trigtest(); in the reattachment script. This would normally mitigate the issue, but the function is bugged. Long story short, this game is very, VERY lucky to be playable at all, even in vanilla Sphere. The ONLY reason it works in vanilla is because Sphere always walks the trigger list on every update, even if the input person is stationary. It looks like I will have to do the same if I want to support this corner case.

So yes, this game is broken, but the fact that it works in the original engine makes it interesting: In many cases it's hanging on to its stability by a thread, so the smallest difference in engine behavior under the hood can break everything. If ever there were a testcase to punish premature optimizations and incomplete reverse engineering, this is it. :P

I'm not sure trigger checks need this kind of optimization. I'd let it check as often as I want, after all it's hardly a bottleneck. The more I get away with in native, the better.

What I am interested in here is the reattachment of the player. When the input is not attached, triggers are not executable through the engine (I end up calling ExecuteTrigger() or somesuch). If the idea of the above is to trigger a trigger a frame before the input is attached I'm not sure how that goes. I guess it's the re-attachment of the player that suddenly executes the trigger because the check is indeed being made all the time, every frame. Once it sees the input is reattached, bam, it's triggered. I think that's kind of clever, really.

Yeah, I'm not sure what the purpose of the trigtest() function is there, it's completely redundant as Sphere will run the trigger anyway post-attach.

And now that I think of it, I don't think it was an optimization after all: the same condition ("did the input person move?") covers zone processing as well. And there it's 100% necessary, otherwise the zone script will keep firing even if the player stands still.

So yes, this game is broken, but the fact that it works in the original engine makes it interesting: In many cases it's hanging on to its stability by a thread, so the smallest difference in engine behavior under the hood can break everything.

This actually explains perfectly why certain segments of the game started breaking randomly on later Sphere versions. For example, I remember the couch moving scene later on in the game sometimes working, sometimes not.

It'd probably be better to fix the game here rather than your code specifically, especially if it means performance regression for all other games. I mean, the game needed some fixes anyway.

It'd probably be better to fix the game here rather than your code specifically, especially if it means performance regression for all other games. I mean, the game needed some fixes anyway.

In this particular case it's not a big deal, as you'd incur the performance hit, such as it is, of constant trigger checks anyway as long as the PC is moving (which is why I now suspect it wasn't an optimization at all, just an oversight). The only speedup to be had from this is when the player is standing still, which truth be told, isn't very useful.

However, in the general case, I agree with the sentiment. I'm not about to bend over backwards to get this game to run as-is, but if it should uncover what is clearly an engine bug, I do want to try to fix it. :)

Trivia: Technically my trigger implementation isn't fully compatible with Sphere's, as I found out last night when comparing the two engine sources. Sphere tracks current trigger activation per-person, whereas minisphere only has a single "current trigger" variable. What this means is that, in Sphere, if the PC steps on a trigger which causes input to be attached to another person, if the input is later returned to the original person, the trigger won't reactivate. In minisphere it would because trigger activation is tracked globally.

Edit: Yeah, even with the trigger and zone fixes I just committed, there's no way this game is going to run in minisphere without some serious edits. There's way too much of passing strings to APIs expecting numbers. Regardless, it looks like I've fixed all of the actual bugs: The game looks like it would be playable if not for all the type errors.

Okay, v1.1.5 has been posted, and with it I've decided to declare minisphere 1.1 stable. Most of the KR glitches are fixed by this release and outside of that my tests haven't uncovered any showstoppers, so I'm thinking it's time to retire v1.0. The performance improvements in 1.1 alone are worth the upgrade. I'll leave 1.0.11 in the downloads repo, but minisphere 1.0 should be considered no longer officially supported and won't receive any more fixes.

Go crazy!

(Note that I didn't bump the version to 1.2, as I was originally going to do for stable releases. I decided it was an unnecessary formality.)

TechDemo_Lithonite2.0 works perfectly on engine.exe, but crashes engine64.exe after selecting to play it from startup. console64.exe informs me that it reaches "Initializing input" before the crash.

Edit: Just realized I can try to debug it with Visual Studio, which I actually forgot I had on here, because I've never really used it.Anyway, it had this to say:Unhandled exception at 0x000000013F997AB9 in console64.exe: 0xC0000005: Access violation reading location 0x0000000000000055.

It crashed at initializing input, interesting. And this is the 64-bit engine... Hm. I know that happens on XP, preventing the engine from being used there. For some reason on some systems it likes to segfault when initializing the Allegro joystick routines, and there's nothing I can do because it's internal to Allegro.

There's no difference between engine and engine64 other than the latter is a native x64 binary and is theoretically faster as a result. Functionality is the same, so you lose nothing. :)

TechDemo_Lithonite2.0 works perfectly on engine.exe, but crashes engine64.exe after selecting to play it from startup. console64.exe informs me that it reaches "Initializing input" before the crash.

Edit: Just realized I can try to debug it with Visual Studio, which I actually forgot I had on here, because I've never really used it.Anyway, it had this to say:Unhandled exception at 0x000000013F997AB9 in console64.exe: 0xC0000005: Access violation reading location 0x0000000000000055.

mezzo, could you redownload 1.1.5 and try engine64 again? I just uploaded a hotfix that should fix the crash you're seeing. In theory this should also allow the engine to run on XP...

Doesn't seem to work, the only difference seems to be that the error is occurring at 0x0[zeros]019 instead of 0x0[zeros]055, and as far as I know that could just be a memory shuffling thing.

Huh. I know there was a bug I found in Allegro where if it fails to initialize XInput it will crash instead of falling back on DirectInput like it's supposed to. Long story short, it initializes XInput and then doesn't check the return value from the init function. I fixed it in my own copy of the Allegro source and recompiled, and it got past that step on my XP VM, so maybe I uploaded the wrong file...

Do you have the latest DX runtimes installed? Contrary to what you'd think, even Win8.1 is missing parts of it out of the box.

Hm, there definitely shouldn't be any issues under Win7. Oh well, you said the 32-bit engine (engine.exe) works fine, right? I guess you'll have to use that. Like I said, they are both compiled from the exact same code, so you won't lose any functionality.

So I was able to reproduce the crashes mezzoEmrys saw with the 64-bit engine. Apparently Allegro doesn't appreciate being fully shut down and then reinitialized in the same session, which is what happens when ExecuteGame() is called. At least for me, the crash doesn't always happen, only sometimes. I will have to refactor the way ExecuteGame() works (I'll put it on the checklist for v1.2), but for now there shouldn't be any issues outside of startup games. In general, actual games have no need to call ExecuteGame().

Anyway, minisphere 1.1.6 is up, and with the recent fixes it should now work in Windows XP. 8) @Defiant, if you are still watching this topic, could you test it for me?

I'm just a regular juggernaut with this project, aren't I? I just implemented module support, slated for minisphere 1.2:https://github.com/fatcerberus/minisphere/tree/module-support

I converted kh2Bar to a module to test it out and so far it's working as intended. This is awesome!

At present minisphere loads modules from ~/modules (or failing that, ~#/modules i.e. relative to the engine "system" dir). I was originally going to use ~/scripts/lib, but as I already used that as a preferred search path for RequireSystemScript, I figured a separate directory was the better option. That'll make it easier if someone wants to code up a NuGet-style dependency manager, too.

So the more I play around with modules, the more I realize, they're not always a suitable replacement for old-fashioned RequireScript(). For one-off dependencies that are only used in maybe one or two places, e.g. kh2Bar, it makes sense to use a module, but for more pervasive dependencies (Link, miniRT...) I've found that a RequireScript() at the top of the main source file is much clearer than var whatever = require('whatever') (or worse, a bunch of inline require()s littered throughout the source which Pegasus seems to advocate).

So the more I play around with modules, the more I realize, they're not always a suitable replacement for old-fashioned RequireScript().

This is particularly true with smaller libs. What we have right now is much more like a < script > tag, which for many things is more suitable. But we actually go a step further with RequireScript over EvaluateScript.For something like my 1.5-style map engines, or (I'd suspect) your threader a module would be more suitable. But for my older MJ map engine, it would be silly.

That's kind of why I don't really care too much about module support. I don't really consider the namespacing to be too important, since it's pretty simple to do that yourself (and all modules I've ever seen already do), and we already handle a basic but quite effective form of dependency management.

The thing I really love about RequireScript is that, besides providing built-in protection against multiple inclusion, it can also be used to enforce load order in complex libraries. In miniRT, for instance, the very bottom of miniRT.js has this block:

// now that everything is in order, we can pull in all the miniRT// component scripts.RequireSystemScript('mini/miniBGM.js');RequireSystemScript('mini/miniConsole.js');RequireSystemScript('mini/miniLink.js');RequireSystemScript('mini/miniPact.js');RequireSystemScript('mini/miniScenes.js');RequireSystemScript('mini/miniThreads.js');

The components are listed in alphabetical order, however miniThreads actually has to be initialized first, because everything else in the runtime depends on it. And it indeed does get initialized first because the individual component scripts also have a RequireScript for it, and therefore it gets its initializer registered with the runtime before any other component. This kind of thing I found is very difficult to do with modules because of the focus on encapsulation.

Nonetheless, this was a trivial addition I could have done ages ago (it's built into Duktape, and even if not it could be polyfilled easily using RawFiles and eval), and implementing it now puts me in a very good position to start work on some form of Pegasus support.

minisphere 1.1.8 is up. This fixes diagonal movement commands not working as well as the long-standing issue where animation for diagonally-moving persons was too fast due to double-queuing of COMMAND_ANIMATE.

Note that, as a result of the recent changes (the way COMMAND_ANIMATE is handled internally has changed), persons will now keep animating even if they run into something, a la early Pokemon. Technically this is a bug, but it does have a certain charm to it, so I'm not actually sure I want to fix it. :) What do you guys think?

Edit: Huh. That's appropriate--look at my post count. :P I almost don't want to ever post again now, it's just too perfect. ;D (1025 being 413 + 612 and the date of Cascade, the most epic thing to ever happen in Homestuck)

Check the documentation folder for minisphere-api.txt. Most of the new stuff should be documented, it's the legacy functions I skimped out on (which you have the 1.5 doc for anyway). I'm slowly filling those out too as I go along though.

minisphere 1.2 development is officially underway. ;D The latest commits add the following APIs for Zone management:

AddZone() and RemoveZone()

GetZoneSteps() and SetZoneSteps()

SetZoneDimensions()

SetZoneScript()

Three of these (AddZone, RemoveZone and SetZoneDimensions) look like they were planned for Sphere at some point and experimentally implemented, but were never exposed to script. AddZone in particular has the entire function commented out in the source. ??? So seeing that, I figured "Why not?" and implemented them.

SetZoneScript was inspired by this thread:http://forums.spheredev.org/index.php/topic,1194.0.html

The first minisphere 1.2 beta is available, go check it out! This includes the new zone and trigger APIs mentioned above as well as CommonJS support. :) Oh, and the API documentation has been fleshed out some more.

So out of curiosity, I ran the loop tests I discovered hidden in the Sphere-SFML test game source with all three current engines. The results are attached as screenshots.

The cliffnotes version: Obviously SphereSFML won because Jurassic is awesome, however one thing shocked me: The huge divide between minisphere and Sphere 1.5. I'll get to that in a minute, though. Before I get started, my test rig is an AMD A10-6800K @ 4.1 GHz with 8GB RAM and running Windows 8.1 Pro x64.

As you can see in the screenshots, Sphere 1.5 averaged around 1300ms per test. The only ones that were under 1000ms were the two that increment twice per iteration. This pattern shows across all engines, though, so apparently the loop condition check is expensive?

SSFML 0.90: The best result by far was "For i++ in Step", which got 17.2ms(!). Makes sense, that's the common case for a for loop, so Jurassic optimizes for it. What's interesting, though, is that Jurassic falters when it hits the i += 1 tests. If you're JITting, then i += 1should compile to the same machine code as an increment, right? But apparently it doesn't. Weird. Ignoring the outliers, SSFML averages ~50ms per test, and around 130ms if you include everything. Very impressive.

Now we get to minisphere (1.2b1). If this is any indication, Duktape is literally 3-4 times faster than SpiderMonkey 1.5. I knew it was a highly optimized engine, but this still blew me away. Here again, though, i += 1 is way slower than a postfix increment for no discernible reason. It's only a 100ms difference though, so not really an outlier. Average across all tests: ~385ms.

So the bottom line is, not only is minisphere leagues faster than Sphere 1.5, but it holds up well against a JITted engine as well. And from what I hear, the Duktape dev is working on even more performance improvements, so that gap should narrow even further in the future.

It's funny how an engine not necessarily built around speed still out-performs Sphere 1.5. I guess SpiderMonkey team really just focused on getting it to work, not even they focused on optimization.

Jurassic lacks static type JIT optimizations. If you are doing a for loop and it knows you are doing integer adds it should use increment. This was on the table of optimizations to be made but the author never got around to it. I thought the C# JIT would do optimizations for you if you can supply it the MSIL bytecode, but perhaps it comes down to what environment or context you give it and the author hadn't optimized for these cases.

That's raw speed for you though. I've since moved to a different test where I call into a function like CreateStringFromByteArray(), the performance varied greatly. When I ran that in a loop in SSFML it took 400ms to do what Sphere 1.5 did in 20ms. But I found out that there is a way to rewrite the way Jurassic notices the method bindings (rather than letting it guess the methods, you can tell it, which is much faster) and upon doing that to my code, I was able to get it down to 40ms. Sphere 1.6 did the test in 60ms so obviously things got even slower between bindings from 1.5 to 1.6. The for loop test was faster in 1.6, however, making the benchmark rather odd.

So I'd do a benchmark with raw JS (which is this) and JS->native calls like CreateColor() or CreateStringFromByteArray() and just see what they bring to the table. Because, Sphere code will make use of many Sphere API calls in loops and they all ought to run fast or otherwise I'd just do -*everything* in JS and only expose file and input I/O as well as a basic drawing API and have the map engine and everything else live in script to remove the native call overhead. I think for Jurassic this might be the fastest since everything's IL anyways. But it's just the optimizations that it'll lack.

Yeah, obviously I knew this benchmark was useless for real-world performance testing, I was just interested in raw performance of the JS engines. I'll definitely try adding some API calls to the mix at some point though.

I do want to do a JS map engine at some point though, perhaps for minisphere 2.0. I'll keep the built-in default one in the engine, but I want to try my hand at writing a more OO map system, which JS is far better suited to than C. Things like SetDefaultPersonScript might be more difficult with objects, though...

So I'd do a benchmark with raw JS (which is this) and JS->native calls like CreateColor() or CreateStringFromByteArray() and just see what they bring to the table. Because, Sphere code will make use of many Sphere API calls in loops and they all ought to run fast or otherwise I'd just do -*everything* in JS and only expose file and input I/O as well as a basic drawing API and have the map engine and everything else live in script to remove the native call overhead. I think for Jurassic this might be the fastest since everything's IL anyways. But it's just the optimizations that it'll lack.

A huge advantage of newer SpiderMonkey is that it is quite capable of this, since it's the stance Mozilla takes with the web now. JavaScript for everything.

Yeah, obviously I knew this benchmark was useless for real-world performance testing, I was just interested in raw performance of the JS engines. I'll definitely try adding some API calls to the mix at some point though.

I do want to do a JS map engine at some point though, perhaps for minisphere 2.0. I'll keep the built-in default one in the engine, but I want to try my hand at writing a more OO map system, which JS is far better suited to than C. Things like SetDefaultPersonScript might be more difficult with objects, though...

You could always check out how I did it. My map engine has fairly complete API coverage (mostly missing FollowPerson stuff), even if it isn't totally accurate, and it is fully object oriented.

Yeah, I'll probably take a more in-depth look at the Turbo engine at some point. I would want an object-oriented API though as well though, not just under-the-hood. For the most part the 1.5 interface is perfectly serviceable, but there are places where it's... awkward. Things like Get/SetPersonX/Y and whatnot.

I do have to caution you that the person spooling you do pre-MapEngine() isn't 100% compatible with Sphere's behavior and is likely to catch you off guard at some point. I know it did for me on multiple occasions during development. Sphere--and minisphere--actually create a concrete person object (not just metadata) when you call CreatePerson(), and non-transient persons survive a MapEngine cycle. This latter behavior is where the spooling will break down, I think.

Word of advice: When stubbing things out during development, particularly lesser-used functions, make sure the stub can't be mistaken for correct functionality. :P This is what I did with font.clone(), and it literally JUST got fixed today. The stub I wrote for it simply incref'd the original font and returned that. Since fonts are rarely cloned and the behavior is fairly close to what it's supposed to do, I ended up forgetting about it. The only, ONLY reason it got fixed was because I was writing the documentation for the Font object and happened to notice it while reviewing the code.

Other bugs fixed today as a result of the review: font.setCharacterImage() not updating the font metrics, font.wordWrapString() not handling whitespace properly and causing crashes under rare circumstances (namely, small wrap widths), and better handling of long stretches of characters with no whitespace.

New minisphere 1.2 feature: the Sphere object. This is an alias for the JS global object and is similar to window in a browser, allowing you to create global variables from strict mode code as well as serving as an optional namespace for built-in APIs if you're so inclined:

minisphere 1.2 is up. I've decided to quit with the betas from here on out and just release. minisphere has been on such a rapid release cycle anyway and I've been very good about fixing bugs, so there's really nothing to gain from pre-releases for this project.

Anyway, 1.2's flagship feature is CommonJS support. This means require(); now works in minisphere if anyone is so inclined to use it. :) I've also bumped the reported API version to 2.0. It's not Pegasus, but between Galileo, CommonJS modules and the object constructors introduced in 1.1, I feel the engine identifying as lowly Sphere 1.5 is a bit disingenuous at this point. :P

Congrats on the new release. I took it for a spin. Impressive. Using Linux with wine. I had Full screen issues, due to the keyboard not binding to the screen, had to alt+tab out and in again.Very much interested in seeing zones working. (saw a post in march that is was enabled... but 1.2 does not have it?)

About the speed with S1.5. It was build with JS1.4 (or was it JS1.5?). I succesfully tested JS1.6, 1.7 and 1.8rc1 through the years (before that fateful day my laptop blew up) and JS wise, they were faster, and also allowed new JS functions, but did nothing to the FPS of games (unless you were not using the mapengine, but most did), while using up much more RAM. A the moment, the API of JS changed so much (see the releasenotes from JS31) that lots of interface calls have to be rewritten. As Spidermonkey gets up to par with V8, I expect more from it now. But am discouraged, as I am not even getting zlib compiled without errors. (switched to MSVC++2010, God knows where my bought DVD is... never got to use it). Any way, the easiest way was ripping JS from old Firefox distro's. Some required also a NS4 dll, next to JS32.dll and some of those builds were slower.

For now, I think spending time on testcases is much more fruitful. I can not even get zlib to compile at the moment... (zlib\src\contrib\masmx86\inffas32.asm(649): error A2070: invalid instruction operands)... so that is... bad... of course, I got a new MSVC, and do not remember what I required to set up to get it all working again. If somebody can point me to a wiki that works...

Zones definitely work. The Lithonite tech demo is included with the engine and should be fully functional. Literally nearly the entirety of the 1.5 API is implemented, the only thing that generally stops a game from working is the stricter argument checking (Boolean arguments aren't automatically coerced, etc).

Check minisphere-api.txt in the documentation folder for full documentation, including all the new stuff. ;D

Not sure what all that was about SpiderMonkey and zlib though. I'm guessing you're trying to build Sphere 1.x? Wrong thread for that. :P

Somehow... I rechecked the version: 1.2 does contain 2 binaries: 64 bits and 32 bits. Can not run it on VM Windows XP SP3 (64bits is not executable, as expected. and the 32 bits abends with "minisphere was unable to create a display window"). On wine, the 32 bit runs. But zones do not work. Packaged binaries are from Jun 6 01:35

I also detected a problem with layers that move automatically: When next to a map border, the map does not move, but the sprite does, instead of staying in the center of the screen, while the map moves, it is the sprite that moves while reaching a border. In those cases, the layers moves away from the cursor keys, as if the map was still moving. (need a example game for that?)

I have a suggestion: would you consider a "global install" version of Sphere? One where you'd put all the games in an App Data folder on Windows or in $HOME/.local/sphere (or $HOME/.sphere) on Linux, and the actual executable in Program Files and /usr/bin? That would be useful for a few reasons:

A) It allows Sphere to become available in package managers, which in turn would attract new usersB) You can just run the command "minisphere" from anywhere that wayC) You separate the binary from the data that can be changed (like the games folder), which means no write access problems

Thinking about it, this is mostly beneficial for Linux. Though point C benefits both Windows and Linux, and probably OS X too.

Quote

Using Linux with wine.

That begs the question... why? The native Linux version functions perfectly fine. :PAlso, good to see you back!

Oh, and yes, I'd like an example game for the layer thing because I have no idea what you're talking about :P. I assume the zone thing you're doing is some edge case where my behavior differs from Sphere's as well, so I'd like to see a testcase for that too. I just tested a few games with zones myself and they work fine, so your use case must be different.

Oh, and yes, it won't run in an XP VM, I tried. I think it can't initialize OpenGL due to lack of hardware acceleration, so Allegro display creation fails.

That begs the question... why? The native Linux version functions perfectly fine. :P

Because I was testing minisphere 1.2 (and the zip contains only a windows build?). I am a bit lost though, lots of reading/catching up to do in 1 year. And all interesting posts, so I can not skip along...

Thanks for the welcome back! Good to see you guys again! Hope you are all doing well.

I attached a fog demo. Just run up, and you see the fox moving too fast, then, behave normally once the sprite is centered.

Will try to get it on a windows 7 machine to test it there. For now, no luck getting zones running. Just in case, can you point me again to the binaries... just in case (I grabbed them from the first post, that was updated... but...)

I've made a few changes since the release in the Git repo, but none that affect the map engine. So yeah, this is baffling. I see what you mean about the layer thing though. I copied the parallax logic pretty much as-is from Sphere 1.x (in my own coding style of course :) ), so I must have screwed something up there. I'll look into it and fix it and post minisphere 1.2.1.

Okay, I diagnosed the parallax bug. Sphere does camera correction before parallax, whereas minisphere currently does it after. This messes up the offsets when parallax is involved. I should have caught this in testing, but as not many Sphere games in the wild use parallax and my own tests involved a repeating map (so there are no edges), it didn't show up.

Ah, so it's a regression in GetCurrentZone(), not zone handling specifically. That used to work (Lithonite was one of my big compatibility targets during development, just so you know :D), but apparently now it doesn't. Thanks, that screenshot was a huge help! On my end it ended up reporting it as Zone 769 half the time, which of course broke the mirror demo with an "invalid layer index" error. I'll look into it.

Do you happen to know where I can get Sully Chronicles? I don't see it in the Spherical repository. I'm assuming it has to do with the parallax too though, maybe not parallax specifically but autoscrolling, which is part of the same calculation.

I should still have Sully Chronicles on my computer. Should. Gimme a minute.

Quote

Because I was testing minisphere 1.2 (and the zip contains only a windows build?). I am a bit lost though, lots of reading/catching up to do in 1 year. And all interesting posts, so I can not skip along...

Ah, okay. Basically, you just get the code from Git and compile it yourself - the dependencies are very minimal (only need the Allegro dev libraries and libmng).

Sully is now available in the incomplete/demo games folder: https://drive.google.com/open?id=0Bw-4UFVty4u1UGhwY2dKMFdySlE&authuser=0Note that this game is VERY incomplete.

I took the liberty to test it out a bit too, though in an older version (on Linux, haven't updated/compiled it in a while). The layers were all screwy, and the mod music isn't playing. Gonna recompile and see how it is with the latest.(Edit: yep, same deal with latest)

Yep, I was right, it was the parallax. For SC, for whatever reason the parallax flag is set on the Foreground layer, so minisphere treats it as a repeating layer, while the map itself is non-repeating. Since the parallax code didn't do preemptive camera correction like Sphere does (I thought it would be enough to only correct the final offset), this caused parallax layers to scroll out of sync with the rest of the map. If these had been repeating maps, everything would have been fine.

Both the GetCurrentZone() bug and this issue are now be fixed as of this commit:https://github.com/fatcerberus/minisphere/commit/3a9498d6daeea5264ecceed17026714071ec2a79

Thanks for the bug reports guys, as always. :) minisphere 1.2.1 will be up shortly, with both of these fixes included.

So I decided to try to make my ancient Pokémon GoldenSky/SilverSea project compatible with minisphere. This was basically my first big project, and where I gained learned the bulk of my scripting experience. And you can tell - the code is a mess all over. :P

Along the way, I noticed a few interesting things:I declared var Font, var WindowStyle, var Surface. Needless to say, this worked in the original Sphere but minisphere complained because the objects are in use. I got this error, which baffled me until I finally figured out what was going on:

After fixing those (and also converting the used MIDIs to Ogg files), I was pleasantly surprised to see it RequireScript() through my dozen other script without complaining whatsoever. Awesome.

However, now I've stumbled across another difference between Sphere and minisphere: GetKey() is not aware of KEY_CTRL. Either that, or GetKey() doesn't return key codes at all. This means you cannot get past the menus. I filed a bug report. :)

Yeah, that "invalid base value" error from Duktape is the bane of my existence. What it means, specifically, is that you're trying to access a property on a variable which is not object-coercible (only null or undefined, in practice). It could at least tell you the name of the variable you're trying to access (SpiderMonkey does), but instead all you get is a vague "invalid base value". Nothing I can do, unfortunately. I'll have to file an issue on the Duktape repo about it.

I declared var Font, var WindowStyle, var Surface. Needless to say, this worked in the original Sphere but minisphere complained because the objects are in use.

I have no idea how that ever worked. By definition when you do that you're overwriting (or at least shadowing) the prototype on the Font constructor, so everything should break. Yet somehow in Sphere that works normally... very odd.

Speaking of crappy code, I discovered another bug thanks to that "Crap RPG" you posted a while back: minisphere's text rendering didn't handle tabs properly. It tried to render the tab character directly instead of inserting spaces and didn't even honor it as a word break for purposes of word-wrapping. It was also fixed in short order. :)

Lots of fairly important bugs fixed, too, especially (for my current project) the hidden layer for obstructions one. I had just settled for fully transparent tiles, now i can actually make them visible in the editor :D

I just realized I may be able to fix the "invalid base value" issue when variables are declared overwriting Sphere constructors. I don't actually have to--it's a very bad practice I don't like to condone, but Duktape's error message for it is so obtuse that working around it is actually preferable at this point.

The issue arises because minisphere stores internal metadata properties in the object prototypes. So when you declare a variable named, say, Font and then call a function which works with Font objects (e.g. GetSystemFont), the engine tries to access the Font prototype (this is why there is no line number--the error happened on the native side), which fails the same as if you did this in script:

To elaborate on that: the boundary between native and script in Duktape is very thin. Duktape's bytecode interpreter internally calls many of the same functions its public API does. That's the reason why half of the Duktape API is macros and a big reason it can be as fast as it is.

Luckily Duktape also has this thing called the "stash" where you can store JS objects out of band such that they won't be garbage collected but are not otherwise accessible from script. I could keep the object prototypes in the stash so that, if Font.prototype itself became inaccessible, the engine could still access it internally through the stash. This would be enough to stop the errors, I think.

Hey guys, glad to see work being done on new versions of the Sphere engine. I haven't played around with it yet, but does minisphere have all the same built in functions as Sphere has? IE. Can I follow old sphere tutorials or is there a new wiki/tutorial area specific to MiniSphere?

minisphere is for all intents and purposes fully compatible with Sphere 1.5. There may be a few obscure functions missing and the type checking for function parameters is stricter, but other than that anything you can do in one is done the same in the other.

minisphere also has a ton of new functionality not present in Sphere--you will have to look at minisphere-api.txt to find out how to use the new stuff.

I just realized I may be able to fix the "invalid base value" issue when variables are declared overwriting Sphere constructors. I don't actually have to--it's a very bad practice I don't like to condone, but Duktape's error message for it is so obtuse that working around it is actually preferable at this point.

it finally compiled! Checking the fog demo... nice work! However, still buggy. You see, the fog layer also needs to stay in sych with the background layer, so if I move, it is not scrolling in respect of the player, but of the other background.So starting the fogdemo, when I move left/right, the fog seems to be following the player, instead of following the ground.

MiniSphere Source is clean and understandable. Still need to peruse it to commit an index map into memory. I like what I have seen so far! Kudo's Bruce!

I am impressed with duktape. At under 3Mb uncompressed source, compared to the 20Mb bz2 compressed tarball from spidermonkey.

The layer bug could have been fixed earlier if you had filed a bug, I would say.

To be honest, I didn't realize it was a bug at first, I thought it seemed intuitive enough that it did that. Didn't even think to check it on 1.5, since I was writing a game from scratch targeted at minisphere anyway. It wasn't until I saw your issue that I thought to check it.

@FBnilI'm pretty sure minisphere should render the fog the same as Sphere 1.5. At least it looked that way in my tests. Are you sure you have the latest master from GitHub? I'm also already using Duktape 1.2.2. If the copy in your source is older, you have an outdated minisphere build.

As for ColorMatrix objects, I'll add those to the list for the upcoming 1.3 release. I knew I was missing something!

What are we doing wrong with OpenGL? I knew there's something messed up about how we are implementing OpenGL, because if you think about it, it can be used to display vast fully-realized high fidelity 3D scenes in 60fps, but we can barely make it all of our engines run more than 20000+ 2D entities on screen at the same time, quickly.

Take for instance this stupid WebGL test, (it's by no mean 'stupid'): http://www.goodboydigital.com/pixijs/bunnymark/

I can render 200000 - two hundred thousand - dancing bunnies and still got 60fps out of the rendering window!! If there are 4 vertex points per object, then we have 800000 verticies, which is still less than a typical 3D scene has on screen. A good PC can handle billions of vertices per second. But, let's say your computer can handle 1 billion verts on screen per second, that makes 800000 verts take only .0008s or .8ms, plenty of room to handle 16.67ms of time per frame. So of course this runs at 60fps. I'm just shocked we can't get this performance out of our native engines. Is Chrome's V8 coupled with WebGL really that damn fast?

I'm doing everything in the book right with my SphereSFML. I'm sending 1 batch of vertices to the pipeline, with a single base texture (atlas, sprite batch, etc.) and I can't get anywhere close to 60000 at 60fps, let alone 200000! And I'm doing some basic logic rather than just dead, simple images (I'm rotate blitting them).

I tested the bunny thing, I got to about 20,000 bunnies before the framerate started dropping off, and it actually started to hiccup before that, around 10,000. Of course this is with the iGPU in my AMD A10-6800K, so I'm sure I could get more bunnies with an actual graphics card. Full disclosure: Firefox.

See here:https://github.com/fatcerberus/minisphere/commit/a14d2b2bd0c6c2648634b141587cc91c5178d93a

Everything is now implemented except for surface.applyColorFX4() because I haven't figured out how to bilinear-interpolate the matrices yet. I'll have to look at the Sphere 1.6 source again.

Edit: Holy crud, ApplyColorFX4() is a beast of a function, I have no clue what it's even doing! It does some crazy interpolation not only on the matrices, but on the pixels themselves. applyColorFX() was easy, but this... well, remember how I said I wouldn't use code I don't understand? Yeah, this is a perfect example. :P I will have to study it a bit more, I'm not just going to paste it in.

I tested the bunny thing, I got to about 20,000 bunnies before the framerate started dropping off, and it actually started to hiccup before that, around 10,000. Of course this is with the iGPU in my AMD A10-6800K, so I'm sure I could get more bunnies with an actual graphics card. Full disclosure: Firefox.

On chrome I got 200000(60fps), on Firefox I get 200000(50fps). I notice the test dips more under Firefox, meaning Chromes V8 is indeed faster in a real example or they have a more optimized WebGL context(?). I have a really nice Nvidia GPU, the GTX970 which didn't cost me a whole lot compared to the 980 or the 980ti (which is an inane amt of cash for such little more power1).

It's just weird, that's all. It might be the overhead, and I think it's the Sphere API calls. I think web has a better, leaner link between the OpenGL and the JS.

The Sphere API is probably it. A JS function call is much, much more expensive than a native call no matter how you slice it, for a lot of reasons. arguments object creation is a big one - this document from the Duktape repo was very enlightening and an interesting read:https://github.com/svaarala/duktape/blob/master/doc/arguments-object.rst

Thanks L.E. did a git pull. Now my techdemo complains that the code is not "strict" enough (back to that then, make all my libs compatible with MS). And thanks for looking at those ApplyColorFX4() is useful though, as a crud way to emulate lights and shadow.I do remember there was an explanation for it somewhere. Do you even sleep? I sleep and there are so many messages.

Meanwhile, I used tcc to compile some of the examples of duktape. Then compress them with upx. tcc has its limitations, gcc -os (compile and make the smallest size) is still way better at making smaller files.

"Drunken Wee master" needs BezierCurve .... was that even a function? ... yes... yes it was..."surface.bezierCurve(c,step,x1,y1,x2,y2,x3,y3,x4,y4) ". I do not even remember these functions...

@Radnen: Maybe you create and destroy object calls each loop? Maybe you require a table where you keep them alive each loop?

I have... odd sleep patterns. And rest assured applyColorFX4() is getting implemented. I figured it out once I started reimplementing it what it was doing, it's simple bilinear interpolation on the individual cells of the 4 matrices. The way the code is written in Sphere 1.x doesn't make that obvious though. Needless to say, my version will be much better annotated. :D

Not sure what that "not strict enough" thing is about... Sounds weird.

Bézier curves might be more difficult though. The thing is, I don't really understand the math behind them and Allegro doesn't (to my knowledge) have a function built in to draw them.

Edit: As of about 5 minutes ago, applyColorFX4() is implemented. I'm thinking my implementation may not be the fastest thing ever, Sphere does some weird thing with bitshifts that I don't quite understand, and I use fmin/fmax to clamp the pixels, which is probably a massive performance hit (doing int->float->int several times for every pixel has to take a toll). The base code should be very easy to follow though:https://github.com/fatcerberus/minisphere/blob/1fe34c2d603a5c49613db212c53ca8a1d3e2ccb7/src/image.c#L318-L381

The BunnyMark only gets me as far as ~35000 bunnies before the FPS starts dropping, but then again I'm on a notebook with an NVIDIA GT540m and a 2Ghz Sandy Bridge CPU, so not exactly the most exciting thing.For me, as long as games perform well, I'm happy, and in that regard minisphere is doing a lot better than original Sphere. (There is a level in Sir Boingers that starts lagging out once I add only a few more cupcakes; minisphere uses about 50% on a single thread at that point and 17% more on another.)

Quote

@DaVince: Yay! new game from DaVince comming up!

Whoa. I'm humbled. :> Now how about you make one again too? I liked your old games and demos. :)

What are we doing wrong with OpenGL? I knew there's something messed up about how we are implementing OpenGL, because if you think about it, it can be used to display vast fully-realized high fidelity 3D scenes in 60fps, but we can barely make it all of our engines run more than 20000+ 2D entities on screen at the same time, quickly.

Three really important things I know I don't do are instancing, geometry/compute shaders (or Cuda/CG interop), and LOD.

Either way, TurboSphere can push 50,000 shapes and stay at 60(ish) FPS (So still more efficient than the BunnyMark on my machine). More or less vertices, depending on how they are divided between shapes and groups. I would highly suspect that's because I use OpenGL 4, which means that the single Group.draw() call to draw all those shapes results in only a fraction that many OpenGL calls. This is why the Galileo API is the way it is. It stops you from needing thousands of calls for thousands of sprites. That's also why I dropped the old API altogether. It's really not how OpenGL or D3D or any modern rendering technology works, and it shows.

But we will always be slower than dedicated 3D engines. They will always have specific functions built in, which the engine can be optimized for at the cost of flexibility. I'm more content to lose a little performance be be generally useful :)

Didn't original Sphere never throw exceptions because implementing exceptions was a difficult mess, or am I wrong on that? Even if it did though, it'd be pretty inconsistent with everything else. I've never seen try..catch in Sphere...

Didn't original Sphere never throw exceptions because implementing exceptions was a difficult mess, or am I wrong on that? Even if it did though, it'd be pretty inconsistent with everything else. I've never seen try..catch in Sphere...

I thought it did? For instance, you could try...catch a LoadImage in case the image didn't exist?

Canonical Sphere scripts certainly don't use exceptions much at all, either way.

Huh. Well, how about that. I was certain there was a whole issue around this, but guess not.

...And here I have this whole script/function dedicated to loading resources and doing its best determining whether a resource exists or not and providing placeholders for years... Time to update that script to make use of it, I suppose.

I think that if you do implement error message copying, you could get away with simply copying the message to the clipboard once you click the screen.But then again, the errors output to the terminal too, so how necessary is it really? Well, useful for reporting the errors, I suppose. :P

This is why the Galileo API is the way it is. It stops you from needing thousands of calls for thousands of sprites. That's also why I dropped the old API altogether. It's really not how OpenGL or D3D or any modern rendering technology works, and it shows.

But we will always be slower than dedicated 3D engines. They will always have specific functions built in, which the engine can be optimized for at the cost of flexibility. I'm more content to lose a little performance be be generally useful :)

I think you're right about the API. Sphere's immediate drawing routines are the issue here, even if you do creative batching like in SphereSFML. There are newer tricks that are easier to use had Sphere's API been different, which is the case for Galileo.

Agreed. However I won't drop the legacy routines as they serve as a convenient stepping stone. Don't underestimate the value of having a fully Sphere-compatible engine. It makes porting painless, so then you get access to all the nifty new features (like Galileo!) pretty much for free. And then eventually you do start using them, and before long you wonder how you ever lived without the neat new additions. ;D

Basically minisphere is set up to let you learn new ways of doing things at your own pace rather than being forced into it, which from my own past experience I can say tends to make you resent "the new way". Better to be able to ease your way into things than being thrown to the wolves.

That said, while the legacy primitives are included in the engine, I deliberately didn't document them for precisely the reason Jester mentioned. They are available for backwards compatibility and easy porting, but for all intents and purposes they should be considered deprecated at this point.

Today I added an optional max_size parameter to bytearray.inflate() and InflateByteArray(), to defend against inflation bombs. I left the default dynamic allocation behavior in for when a max size isn't provided however, as that may sometimes be preferable for trusted data, such as local save files. Any inflation of data coming over a socket should definitely include a max size clause, though, I totally agree with that.

minisphere 1.3 is nearing release, I just want to do some updates to miniRT and then it should be good to go. Unless I decide to add more features, I swear there was another new feature idea I had but now I've forgotten it...

Yeah, nobody who saw this engine would believe it was one guy who put it together in 3 months, huh? Nonetheless... ;D

I started development towards the end of January, minisphere 1.0 was released mid-to-late April.

It's funny, I'm generally bad at finishing projects I start, but minisphere... I don't know, it's been very easy for me to keep the wheels of development turning with this project for some reason. Which is a good thing of course, I just don't understand it. :P

I remembered the feature I wanted to add: SPK support! I always aim to have at least one killer new feature for each version bump, so 1.3's will be archives. For game packages I want to support, at the very least, SPK and ZIP. To do this, there's apparently a zlib-licensed library called "PhysicsFS" that will let me access files directly from archives:

- Obviously, direct filetype association with spk files would be nice. Double-click the SPK, play the game.- Renaming the zips with a different extension (like .spk2 or .spherezip or something). This makes filetype association easier for Sphere zips. (Compare to .cbz "comic book zip" files, which are just archives filled with pictures)- The game launcher detecting these packages if you put them in games/, of course. :)

And some more special ideas:- If you distribute just the engine binary + an spk file, it'll pick up on the spk file so you don't even need a games or startup folder, it'll just open that when you start the engine.- The ability to load multiple spk/zip files. Could be useful for loading the game and then loading extra resources on top of it (like a mod, a levelpack, etc.)

Since minisphere reports as Sphere 2.0 now, we can definitely make an .spk2 format. I think we'd have to standardize on an archive format though. Zip seems the best option, as it can be supported easily enough with just zlib, regardless of what minisphere ends up using to support it. Plus it seems to be what most compressed formats go with. OpenDocument and Office 2007+ docx files are just relabeled zips, for example.

7z would of course compress better, but would hinder performance as decompression can be slow, especially if solid compression is used. Ideally I'd want a format with decent compression but without sacrificing too much random access performance. A non-solid deflate-based format like zip fits the bill, I'd think.

Where things get hairy is handling write access. RawFile is the biggest issue here--the same API is used to open a file for either reading or writing, but you can't really write to a package at runtime. It might be necessary for me to step back and look at refactoring the asset management first, before baking in package support.

I would also have to make sure running a game from a package is transparent. This is an issue I know Sphere has had: some things just don't work when running games from an SPK. It's a big reason I gave up on packaging games back when I was using 1.5. Which is a shame, because being able to distribute a single .spk for your game is nice for when the person on the other end may not really know what to do with a zip file.

You know, I'm actually beginning to wonder if the FS sandbox imposed by the original engine wasn't deliberate, but just a necessary evil of supporting packages. Not to say you can't dispense with the sandbox by using fallback clauses, but for consistency's sake Chad Austin might have decided to just sandbox always, regardless of the packaging method or lack thereof.

Since minisphere reports as Sphere 2.0 now, we can definitely make an .spk2 format. I think we'd have to standardize on an archive format though. Zip seems the best option, as it can be supported easily enough with just zlib, regardless of what minisphere ends up using to support it. Plus it seems to be what most compressed formats go with. OpenDocument and Office 2007+ docx files are just relabeled zips, for example.

7z would of course compress better, but would hinder performance as decompression can be slow, especially if solid compression is used. Ideally I'd want a format with decent compression but without sacrificing too much random access performance. A non-solid deflate-based format like zip fits the bill, I'd think.

I believe that a combination of tar or cpio and zlib or xz is the best. tar and cpio provide the same strengths, but are far simpler.The reason I never got around to fully supporting spk's was that writing to a file from a game that is running from one is very complicated, as you mention. I finally said enough, and gave up on packages, since at that point the benefits seemed very small for the amount of complexity they introduced.

My final plan is to just unpack the package to some local directory and run the game there. If it looks like I've done that before, I merge the existing directory with what I unpack, favoring existing content. This bypasses many of the issues associated with packages, at the expense of having both a packaged and unpackaged game on the local disk at once.

In the interest of making package support as painless to implement as possible, I've decided it would be best to standardize on a file system. I call my initiative SphereFS, and it'll be a key pillar of the Sphere 2.0 API. More details forthcoming, but suffice to say it will be backwards compatible with the Sphere 1.x sandbox but would allow, e.g. absolute paths via an escape.

SphereFS support will have its own extension designation in minisphere, sphere-spherefs. Once I've fleshed things out some more, I will post a new thread in the Engine Development forum.

Re Bezier curves - Fortunately for you I understand the maths and once wrote a script to use in Sphere. It's in the Wayback of the old wiki somewhere. I also C++-ed it for my hello-phoenix project (https://github.com/apollolux/hello-phoenix/blob/master/hello/ncurve.hpp) on my GitHub. The de Casteljau curve algorithm is essentially a divide-and-conquer one, but you may also need to limit the recursion depth if you don't check for point distance (NCurve in hello-phoenix does both, but I think the JS version only tests point distance).

Re spk/zip - If you choose to implement reading of renamed zip files as the next generation of spk and you want to keep a three-character extension, I recommend spz. If it's renamed 7z, sp7.

Re SphereFS - Feel free to make a "Future of Sphere" post for it, maybe including spitballing sphere:// or sph:// protocol handling or something too for a bit farther into the future.edit: seems you already posted, I didn't finish catching up +neo

Ugh, the package support wasn't even the most painful part of the SphereFS implementation, it's the abstraction that's the killer. The whole engine was written with the assumption files will exist on the local FS, forcing me to not only have to implement custom sfs_fopen() etc. but even things like GetFileList() ended up getting broken.

The biggest issue though is loading images and such through Allegro. If it weren't for Allegro's memfile add on (file-mapped memory!), a clean abstraction wouldn't even be possible--I'd have to resort to temp files.

...nonetheless, I finally got it up and running this morning. :) A few things, like MNG loading, are still broken, but for the most part the engine is back in working order and will run a game from either a local folder or an SPK.

SPK is implemented by an spk_fopen() function which unpacks the requested file into memory and an emulated spk_fread() etc. which operate on the buffer. This avoids a potentially lengthy unpacking step on startup without sacrificing too much performance, as memory is fast so the only additional overhead over straight disk access is the inflate step.

The end result is that the rest of the engine doesn't know or care where or how the file is stored, it just gives SphereFS a sandbox pointer and a filename and gets a file handle in return. It's a very clean setup this way. :D

edit: It actually might be possible to support writing to an SPK, now that I know how the format is set up. Every file, and the index itself, has an explicit offset stored in the headers, which means it's trivial to just append a new or modified file to the end. For existing files you just modify the index entry, and new files can be tacked onto the end. Of course this could cause the SPK to grow inordinately large without some method of compaction available... Just a thought.

- Obviously, direct filetype association with spk files would be nice. Double-click the SPK, play the game.- Renaming the zips with a different extension (like .spk2 or .spherezip or something). This makes filetype association easier for Sphere zips. (Compare to .cbz "comic book zip" files, which are just archives filled with pictures)- The game launcher detecting these packages if you put them in games/, of course. :)

And some more special ideas:- If you distribute just the engine binary + an spk file, it'll pick up on the spk file so you don't even need a games or startup folder, it'll just open that when you start the engine.- The ability to load multiple spk/zip files. Could be useful for loading the game and then loading extra resources on top of it (like a mod, a levelpack, etc.)

Going to take these one at a time. Now that the SPK support is actually implemented, I can tackle these.

- Filetype association is best left to an installer, methinks. Since the official distribution is for Windows, I think I can handle that. minisphere 1.3 will be the first to be distributed as an installer. That is, assuming Google will let me upload it to Drive, I think it might block uploading .exe files? But yes, association with SPK would be nice.

- I'm thinking zip support won't make it into 1.3 after all. Having actually implemented SPK and seen the inner workings of the format, it seems more than adequate for its intended purpose. Plus it's insanely fast: I saw literally no performance difference at all running Specs from an SPK vs. directly. They are even fast to compress, too--the Sphere 1.5 editor made a 35MB SPK out of my Specs project folder in seconds! This to me is a clear case of "if it ain't broke, don't fix it" :P

- Self-evident, skipping. :)

Now, the "special" ideas:

- This is an awesome idea and not too difficult to implement either. Only one question: If both a single SPK and a startup folder are present, which one takes precendence?

- This adds extra complexity to the engine, probably out of the scope of the 1.x releases. A good idea for minisphere 2.0, though, I'll add it to the GitHub issue for that. :D

- This is an awesome idea and not too difficult to implement either. Only one question: If both a single SPK and a startup folder are present, which one takes precendence?

I'd say the startup folder, because that folder existing is evidence the entire package was not made to be a standalone game. Perhaps the game could still appear in the games list; I believe the default startup game just starts the game if it's the only one it finds anyway.

As for the special ideas: they're just ideas. But it's awesome that you're tackling both of them anyway. :P

I just enabled write access for games running from packages. Actually modifying the SPK file at runtime would be time-consuming to implement and the file isn't guaranteed to be writable anyway, so if a game requests write access to an existing file, it is saved in ~/Sphere/.spkcache/[filename.spk] (the Linux meaning of ~, not Sphere's :) )

Note that this differs from Sphere 1.5, which puts the cache in packages under the engine. Since nowadays we have to assume the engine directory is read-only, this needed to be changed.

Re non-local files - For now, I recommend keeping all the various Sphere format file I/O functionality focused on local files. For non-local files, we can certainly consider expanding the network functions' capabilities to include a cURL implementation/shim or something as sugar for the existing socket functions for non-vanilla pre-2.0 engines and eventually fold them into official 2.0 API. Once the kinks are worked out, this folding in would also eventually allow non-local file reading on the Sphere format file I/O.

Then again, if it turns out to be trivial to change file I/O in minisphere to allow at least networked file I/O (as in less than 2 hours or so to add) feel free to add it now, show us some working tests, and we can have it much sooner. I'll then fully support such an endeavor as marked to be made official ASAP.

Then again, if it turns out to be trivial to change file I/O in minisphere to allow at least networked file I/O (as in less than 2 hours or so to add) feel free to add it now, show us some working tests, and we can have it much sooner. I'll then fully support such an endeavor as marked to be made official ASAP.

The beauty of SphereFS is that it canonizes the Sphere 1.x sandbox. For example when you call LoadImage("foo.png") under minisphere 1.3, you are not requesting <game path>/images/foo.png, the canonical name of the asset is literally:images/foo.png

And names of this form are what get passed around inside the engine, not actual file paths. SphereFS itself handles the final path resolution and I/O behind the scenes. So yes, network I/O would be very easy to implement. The tricky part is the synchronicity--the default APIs for loading assets are blocking in nature, which would slow them down running over the wire.

Long story short, the actual network file I/O isn't the issue, it's the API.

As of the latest master, minisphere will auto-launch a single .spk file placed alongside the engine executable, making game distribution drop-dead simple. I just have to work out a couple more glitches and 1.3 should be ready for release. ;D

Oh, not mentioned in the changelog, but minisphere 1.3 is fully Unicode-aware under the hood. Person names, etc. are all UTF-8 internally, so you can feel free to use any characters you want in them and the engine won't choke on it. :)

I think part of the speed problem is that I pass colormatrix_t objects around by value, so a lot of copying goes on, even more so for applyColorFX4(). But I also know Sphere does clever tricks with bitshifts for this operation, which I'm sure speeds it up considerably. minisphere also calls a function to do the matrix interpolation, so that adds even more overhead if the compiler doesn't inline it.

I purposely didn't optimize it for this initial implementation, though. I wanted to make sure I understood the theory behind it first. I know now that it's just simple bilinear interpolation, but it wasn't easy to figure that out with all the magic tricks going on. :)

int is 32 bits on Windows, a colormatrix_t has 12 of them. So 48 bytes, or 96 bytes on a platform with 64-bit ints.

Edit: Honestly I'm starting to think most of the performance hit is that locking a bitmap in Allegro is just insanely expensive for no apparent reason. I could understand it when I was using hardware textures, but switching surfaces to software offered no real performance improvement in, e.g. getPixel() until I also added the pixel cache for that.

So I ran the profiler on minisphere to figure out what was causing the massive slowdown on my battle screen, and came back with some... interesting results.

As you can see on the Summary page, the function causing the majority of the bottleneck is js_Font_drawText(). No surprise there, I already knew minisphere was slow at rendering text. However, the runner-up shocked me: js_new_Color, the Color constructor. You can see the breakdown for that in the second screenshot. Apparently creating Color objects on demand on expensive!

For good measure, the third screenshot shows the main culprit in the text rendering bottleneck: al_hold_bitmap_drawing(false); This should be ridiculously fast, as fonts are atlased so Allegro can just send all the vertices at once. But apparently not...

For good measure, the third screenshot shows the main culprit in the text rendering bottleneck: al_hold_bitmap_drawing(false); This should be ridiculously fast, as fonts are atlased so Allegro can just send all the vertices at once. But apparently not...

I'd be curious how the Turbo runtime's font renderer runs in Minisphere.

I still can't get minisphere to load the Turbo runtime successfully due to all the circular RequireScripts. How do you have RequireScript implemented in TS? I evaluate the script AFTER entering it into the tracking list, to avoid infinite circular recursion. So what ends up happening for me is that, after requiring map_engine.js, at some point in the require chain it gets to segment.js and Turbo is undefined because it's still in the middle of resolving the RequireScript chain.

That's very strange. In TurboSphere, RequireScript enters a script into the list of evaluated scripts immediately after it checks if it was previously evaluated, which is right before it evaluates the next script.

But every one of the runtime's scripts should have the declaration of the Turbo object before anything that uses it--you should be able to require any one of them, and in any order, and not have that issue. It seems odd to me that Minisphere would complain about Turbo being undefined, unless the RequireScripts are not sharing all declarations until after they have completed or something similar. Or somehow our implementations are really that different? I think we do it the same way, and I can't really think of another way that would even come close to working properly.

I know I had this same problem with miniRT, and I was only able to fix it by centralizing everything to a single script (miniRT.js) which pulls in all the others at the bottom (not the top). And when I mentally followed the call chain, it made sense--if the RequireScripts are at the top and there's a circular reference, then when you hit the effective "bottom" of the tree (conceptually there is no bottom since it's a circle but in reality there is because of the implicit include guard), Turbo is undefined because all the scripts higher up in the call chain are still in the middle of include resolution, so nobody's actually had a chance to define it yet.

So yeah, not sure why this works in one engine but not the other.

Edit: Shame on you for calling malloc and not checking for null! :P Actually though, I've stopped checking it myself. I figure by the time a malloc returns null there's not much I can do in the way of recovery anyway so may as well just let it crash.

Edit: Shame on you for calling malloc and not checking for null! :P Actually though, I've stopped checking it myself. I figure by the time a malloc returns null there's not much I can do in the way of recovery anyway so may as well just let it crash.

Yeah, in general there's just no point. In very almost all cases, an OOM is unrecoverable from any perspective. I could fail fast, but if I suspect an OOM I can use a debug malloc that aborts when it would return null.

Hey, if I have to document the code I might as well have some fun with it, right? :) You'll find I also tend to write funnier comments when I'm frustrated, like the "HERE BE DRAGONS" ones I have at the top of a few particularly hairy functions. Then you have my personal favorite minisphere comment of all time, in persons.c:

minisphere 1.4 is up! I fast-tracked this one since I didn't really have any other ideas for a release, but the CS support is enough of a change to warrant a version bump, methinks.

To be clear: You can now specify .coffee files directly in a RequireScript() call, and require() will recognize .coffee modules as well. No need to include the CS compiler with your game and manually invoke it, minisphere will load and use it from the system directory automatically.

The funny thing is I don't even really like CoffeeScript that much...

edit: I also recompiled everything with /O2. It seems I sacrificed a lot of performance when I optimized for size a while back, not really worth it to reduce the engine size by half a MB.

Syntactically, coffescript is nice to have for a few areas: Classes, loops, and some areas of logic that may get too verbose. But I've found that libraries like my Link.js go a long ways in making sure iterations on lists and management of larger code sections is easier to maintain.

There's a point in professional JS in which you use code to write less code to code (like my post signature). I find that if you tackle every loop like this:

Then you are doing JS within JS wrong. CoffeeScript had a good use to write out JS shims for old browsers which isn't exactly needed for Sphere. Sure there are JS features that have been added since Sphere 1.6, but if you use CoffeeScript solely for minisphere I doubt you'll get the most out of it.

Yeah, I personally don't like a lot of things about CS. Postfix if/unless, for one, confuses me to no end, and indent-based scoping... Ugh. I prefer to write pure JS. I still added CS though because I like to give people the option. :). I try not to impose my own preferences on others.

I certainly think that the syntax can be just a little ambiguous. I tend to be OK with ws-awareness, it's just a choice, and one I don't mind.

I've only used a little bit of Coffeescript. On the whole, it just seems to be a different syntax for JS (not too much better or worse). The only feature I thought was really nifty was how constructors could put named parameters directly into fields. That would be really nice to have in JS.

minimally rewrote agrapher to run with minisphere. It requires the system scripts typeof.js and colors.js (this one is updated with more things).It draws functions and creates an image of that. See png attached.

So far, although similar at first glance, the grid and lines are offset a little, thus the image is not the same. I'm still investigating what exactly is different.(s7.png is sphere 1.6 generated and ms.png is minisphere generated).

looking at it with gwenview reveals that the grid (which are transparent blue lines), are not the uniform color they should be, where, a lighter dot should be produced at intersections. This could be because of the way primitives are composed now. While irfanview does not show this difference. (the offset, is viewable in both image viewers, thus a real difference)

The sphere editor image viewer shows even more contrast in the grid produced by minisphere.

@L.E.: Thanks for the tips

edit: I know what it does now: minisphere, when printing a semi transparant color over the black canvas, actually makes the black canvas transparent, instead of blending, then leaving the alpha alone.

I fixed the offset. I just had to add 0.5 to the coordinates passed to Allegro. Standard off-by-one error.

As for the colors, I think ultimately, with minisphere you're at whim of the hardware when using the legacy primitives. A screenshot of my result is posted, and as you can see it's actually darker than the image produced by Sphere 1.5. Which is the exact opposite of the result you got.

Ah, it is darker because it is transparent blue, over black, which makes it very black, then rendered as non-transparent pixels (alpha 255). It seems the transparency of a pixel also affects the RGBA of the destination, while this should only happen when it blends colors.

Ah, it is darker because it is transparent blue, over black, which makes it very black, then rendered as non-transparent pixels (alpha 255). It seems the transparency of a pixel also affects the RGBA of the destination, while this should only happen when it blends colors.

Thanks, I'll have to look into that, I may have screwed up the blend modes for surfaces.

Not sure what's causing that segfault though, and I'm not near a computer to run it through the debugger at present. I'll look at it tonight.

Well, the monotone notes are now fixed at least. I forgot to reapply the gain, pitch, etc. when restarting the stream.

Somehow you keep finding the best testcases for minisphere, uncovering so many obscure bugs. It helps me out a lot. ;)

Now to take another look at that grid.

edit: I figured it out, Allegro by default does blending for all components, including the alpha channel. I have to use a different function to set a separate blendmode for the alpha channel:https://www.allegro.cc/manual/al_set_separate_blender

Surprising I didn't notice this before, as I do some blending with surfaces myself. I'll see about a fix.

Which appears to be impossible to do in hardware--or at least with the blend modes Allegro provides. In most real-world cases the full RGBA blending works fine, for example the textboxes in Specs and... whatever the startup game does.

For what it's worth, the closest I could come to Sphere's actual behavior is this:

Dont break spectacles! fixing the Alpha channel can be done in scripting as well (or maybe a new function). This will become useful for me once spritesets can be updated dynamically (to be able to swap clothes, armour and gear;and if those functions are not available, I can work around that by mixing to disk, and reload the spriteset).Ill look better into a testcase for the crash on Windows (my platform is Linux now, so maybe it is a library, and not minisphere).

Slowly recovering my ranma demo. You see, long time ago I did remove all duplicate files from my backup, but then lost the original directories (svn) in a laptop crash. Thus, all I have now are spritesets and maps all over the place, without knowing which is newer and more complete.

Lord English, more stuff broke with the current version(Tue Jun 23 02:43:42 2015 -0400), see the attached print demo. All skewed canvas drawings are invisible (or are not being printed). The code is unreadable. I guess I was more focused on functionality at that time. (I guess that is the change that you wanted to roll back).I also get a bit funky in puff-puff, where NPC's are able to grab powerups. A 9x9 layer is not stretched anymore and surfaces are not mirrored (the firedemo/sun). And in the highscores, the stylewindow is not filled in, something is printed, in very light blue, bot not inside it. Also, the skewing there is weird, the right-side of the logo is not wobbly as expected. I will break that down into smaller bugtests during the week. So do not worry... lots of genuine bugs to come!

There are successes also:Kamatsu's pathfind.js runs out of the box, as well as my demo around that library (see picture).I am modifying pathfind.js, as it uses strings as indexes, and numbers are (should be) faster. Will need to benchmark that.

Its fun to read your log. I saw also that stray printf, but thought nothing of it.Tested the coffee script, but as I do not know it (bar that webpage that had some example code). It was fun to get it in.

mod sound is still a bit off for me.. the channels pan totally right/left, but I'm not sure if that is allegro or that it can be controlled in ms.

* print example is 100% ok again (better than 2 build back, as the integration symbol in the formula now displays fine, just as the extra wide plus sign, so something in the resize is now done right again)* puffpuff highscores still not ok (and the colorbars are back to that because of the old transparency behavior). Image attached. Like I said, will make a simple test for that.* The sound on Linux seems worse than on windows. But it is in the wine version of Sphere 1.7 too (1.6 with the ctypes working). so a mod is 4 channels: left,right,left,right and not slightly panned off center, as I remember making the music. So it is probably linux. I will have to edit the music in impulse tracker again, create an .it file, and test that. So ignore my comment for the moment, it is not minisphere. (audiere used to sound very good on windows... )

Hm, I wonder what's causing the window to be transparent like that. As for the blending, the only way I can see to fully emulate Sphere 1.x would be to use a shader. The fixed-function pipeline just isn't capable of it, and doing surfaces entirely in software is unfeasible as Allegro blitting performance for memory bitmaps is atrocious.

Indeed, the tricky part is that Sphere does RGB blending using the source alpha, but explicitly sets the alpha of the destination to full opaque. Kind of odd, but as you can see, a lot of existing code relies on it.

Edit: wait, I see it now. Never mind me, I need to pay better attention. :)

Hm, I did some reading, and glBlendFunc() actually sets the multiplier for the source and destination pixels, even with GL_CONSTANT_COLOR/ALPHA (so the "constant color" is actually a mask and is thus a misnomer). So basically what your snippet does is overwrite the destination alpha channel with the one from the source image, the same as if you did this:

It doesn't unconditionally set the destination pixel to full opaque like Sphere does. :( So yeah, I'm pretty sure I will have to use a shader. No big deal, I already have the plumbing in place for shaders, it's easy enough to throw a few into the system folder for blending modes.

edit: That said, I did just send a pull request to implement constant-color blending in Allegro, since it's indeed a useful feature and I have no clue how it didn't make it in before now. :P

I just implemented engine-wide shader support in minisphere. Previously shaders only applied to Galileo rendering, and a null shader (i.e. Allegro default) was used everywhere else. Now minisphere looks for system.vs.glsl and system.fs.glsl in the system directory on startup and uses them if they are found. These will be used to implement the Sphere 1.x blend and mask modes properly.

The engine will still work if the system shaders are unavailable, in which case it will fall back on the FFP (which will be inaccurate) and the aforementioned null shader.

edit: BAH! It turns out you can't do blending in a shader because the fragment shader doesn't have access to the destination color, only the source fragment color. Figures.

The only thing I can't figure out is why the fireball on the title isn't displaying. I added a call to surface.save() to that part, and the image is empty, all black. No sun. Yet when I ran through the debugger the color values are right. Apparently surface.setPixel() is broken.

The other bug I saw with this game is that the death animation isn't right, the car moves to a seemingly random location while it spins out. I think MapToScreen() is glitched, but it works fine in Specs...

I also figured out that MapToScreen() is bugged for small repeating layers due to aliasing (internally it just does a reverse mapping from ScreenToMap, if the layer repeats within a screen it's ambiguous where you are in relation to it). I'm too tired to come up with a fix now though, I will work on it in the morning. I'm also not sure why the enemy cars are picking up the power-ups...

Okay, figured out why cars can pick up flags and stuff in Puff-Puff, it's not technically a bug. Sphere 1.x only calls the touch-script for input person collisions, minisphere does it for all entities. Despite that the behavior is not fully compatible, in almost all cases, minisphere's semantics here are preferable. Persons should be able to respond to anyone touching them, not just the player(s).

For Puff-Puff specifically, the workaround is to add this line to the top of the relevant touch scripts:

Okay, figured out why cars can pick up flags and stuff in Puff-Puff, it's not technically a bug. Sphere 1.x only calls the touch-script for input person collisions, minisphere does it for all entities. Despite that the behavior is not fully compatible, in almost all cases, minisphere's semantics here are preferable. Persons should be able to respond to anyone touching them, not just the player(s).

Despite being incompatible I do like this system. It makes making a RPGMaker like eventing system easier to manage if other entities collisions can be handled gracefully. Otherwise it'd be hard to get back that kind of info without running your own loop of checks (which is rather redundant), and prone to failure.

Nice! I suppose this will warn you of building issues before I get the chance to complain (:P) about it, right? :)

Yes, plus it paves the way for a future official Linux release, as I'll know ahead of time whether the build is broken (so errors don't pile up). What shocks me is how *silent* the build is, even in the clang build. No warnings whatsoever. I wonder what warning level SCons is using...

"-pedantic" makes the build 99.9% accurate to the standard you selected (which defaults -std=c99). Clang and GCC are far closer to the C99 standard than MSVC is (or really any other compiler except for Solaris Studio), so I would suspect that it bring up all kinds of new and exciting problems.

You can also add "-ansi" instead of "-std=c99" to get C89, which is very close to what MSVC 2010 has, except that it also disallows single-line comments. C99 didn't really work at all until at least MSVC 2012.

Well, sized ints are a matter of the library itself, not the standard. While technically a compiler should limit the library a program can see when compiling for a certain standard, this tends to only happen with C++.

Then there's Solaris Studio. (Almost) fully C++14 and C11 compliant, still running on a C++03 and C89 library :/

Thanks a TON! It is unbelievable how fast you update and commit.Good code too, will re-test stuff later-on. I'm trying to get the networking working, but I seem to either not "getting" it, or there is a bug:

I wrapped it in a try loop, of course, but even then, a webbrowser connects, but then "hangs" (as opposed to an immediate "unable to connect" error). So we know it is connecting, but it seems it is not able to start up communications.

Thanks a TON! It is unbelievable how fast you update and commit.Good code too, will re-test stuff later-on. I'm trying to get the networking working, but I seem to either not "getting" it, or there is a bug:

I wrapped it in a try loop, of course, but even then, a webbrowser connects, but then "hangs" (as opposed to an immediate "unable to connect" error). So we know it is connecting, but it seems it is not able to start up communications.

Oops, I accidentally still had accept() exposed as "acceptNext" from when I originally implemented the Sockets API. The latest Git build fixes it.

Amusing side note: Don't ever attempt to use -Wall with MSVC. It generates thousands of "warnings" that aren't even real warnings--noise like "Oh hey, I inlined this function for you" or "x amount of padding added to this struct" and other such nonsense.

As for pedantic warnings, the only thing I can see is implicit declarations of standard library functions--which means I just forgot an include. Even Duktape itself was silent.

edit 2: Well that's kind of annoying. Apparently scons quits after the first file that has errors. I like MSVC's build system, it will keep going anyway so you get to see if anything else has errors without having to keep restarting the build.

edit 2: Well that's kind of annoying. Apparently scons quits after the first file that has errors. I like MSVC's build system, it will keep going anyway so you get to see if anything else has errors without having to keep restarting the build.

I hated that stupid paperclip. Thank god they had the decency to never implement Agent in MSVC, could you imagine the nightmare? :P

I always did have a soft spot for the cat though. Annoying as it was I used to enable Agent anyway just to see the cat roll around and play, it was cute. I turned off all the stupid "hints" though, of course. ;)

minisphere 1.4.3 is up. This is the first release to be distributed as an installer! This is convenient, as the installer will automatically associate the engine with SGM and SPK files (the 64-bit engine is associated on 64-bit Windows). Go try it out!

Oh, I was going to include Sphere Studio, but it doesn't work when run from Program Files, it just terminates immediately, I assume because it tries to save its .ini file in the editor directory...

obj/color.c:32:3: warning: initializer element is not computable at load time [enabled by default]

In ansi C (and actually up to C11), initializer lists must be entirely made up of compile-time constants. Of course, common compilers can handle this kind of thing, which is why it ended up being in the C11 standard.

So it seems I broke screenshots at some point... Oops. I changed it to put them in ~/Sphere Files/Screenshots (home dir, not Sphere's definition of ~/), but forgot to have it create the screenshots folder. So yeah, screenshots don't work unless you create the folder manually first. It will be fixed in the next update.

minisphere 1.4.4 is up, fixing the screenshot bug. The installer now pre-configures Sphere Studio as well (without clobbering existing settings), and creates presets for minisphere. This should hopefully make the engine much more accessible to newbies! :)

edit: Make that 1.4.5. I discovered a bug in the installer, it won't give the option to install Sphere Studio. This fixes it.

I also split minisphere into two downloads. The GDK includes Sphere Studio and minisphere Console, while the redistributable only includes the standard engine and sample games.

So, funny story: I'm all tapped out of ideas for how to improve minisphere any further. This is probably a good thing since it means the engine is pretty much a complete, comprehensive package, but it's driving me bonkers with boredom. :P

I keep hoping for one more big feature idea so I can get minisphere to v1.5, but no such inspiration yet...

minisphere 1.4.6 is up with a few minor fixes. I found a bug where screenshots could be washed out because the backbuffer's alpha channel was incorrectly preserved when saving. I also fixed the lack of a taskbar icon for games with no icon.png.

Additionally, I dug up the SVG version of the Spherical icon NEO posted a while back and scaled it up 768x768, so now minisphere has a proper Win10-ready icon. :)

Good news, guys: minisphere 1.5 is only a few days off. :D Progress has been a bit slow because I'm in the middle of a huge overhaul under the hood of Sphere Studio (I have to earn my collaborator status you know! :P) but I just finished up implementing Mixers and so far everything looks good. I do still have to add documentation for the Audialis additions and the Mixer object needs a few more features (volume adjustment, for one), but otherwise I'm pretty close to wrapping this up.

Keep in mind that SoundStreams will be limited to 8-bit unsigned in minisphere 1.5. This makes them easy to manipulate with Sphere ByteArrays, whereas any other sample format would be unwieldy to work with under these circumstances. Once Duktape releases a version supporting ArrayBuffer/TypedArray, then I'll open up more sample formats. ;)

To clarify on how the Mixer object works: It actually encapsulates both a hardware voice and a software mixer. In 1.5.0, both of these were created with the parameters passed to the Mixer constructor. This failed in the case of 8-bit, as Allegro will create an 8-bit voice but refuses to create an 8-bit mixer. For good reason, too--it'd be difficult to do any kind of decent mixing at all with only 8 bits of precision! :P

As of 1.5.1, the hardware voice created matches the Mixer() parameters, but the mixer itself is float32. This ensures the call will succeed so long as the underlying sound hardware supports the requested bit depth and channel count.

So I found a great use for Audialis already: Crossfading BGM. Previously this would have been a pain, since the BGM volume is generally global, while crossfading requires manipulating individual streams' volume settings. Under the Sphere 1.x API, something like setting the BGM volume in the middle of a fade would prove to be very tedious indeed.

Under Audialis, I can just set the volume on the BGM mixer when adjusting global volume, and adjust the individual stream volumes separately to handle crossfades. It makes the code very elegant.

The above won't disturb a crossfade-in-progress. Further, this allows the global volume to be faded at the same time, for example in a cutscenes where you want to fade down the BGM to half while simultaneously switching tracks.

Another good use would be to implement an in-game volume setting menu. You create two mixers, one for music and one for sounds, and the volume slider adjusts the volume of the mixers without having to touch the individual Sound objects.

I just had to build it from scratch last I tried on OS X. The build is not especially pleasant on OS X, but it's manageable.

This Allegro wiki article (https://wiki.allegro.cc/index.php?title=Install_Allegro5_From_GIT/OSX) says get it from SourceForge, but SF is in "maintenance mode" right now. Don't know how long that will last, so can't build 5.1.11 either.

I don't suppose one of you can put up the Allegro 5.1.11 and libmng source for me to download?

Setting up jump points for longjmpLooking for a game to launchOpening game ''engine(32428,0x10ff94000) malloc: *** error for object 0x7fe271831200: pointer being freed was not allocated*** set a breakpoint in malloc_error_break to debugAbort trap: 6

edit: Running a game with just `Abort("Hello, mixer!");` in the game() function results in the following error on closing:

These are weird. They look like double free bugs, but I would think they should have shown up in the Windows and Linux builds by now if so. Does it always crash shutting down Audialis? Or is it in a different spot each time?

Then, I suggest typing `frame s 1` to see the second frame, and continuing this (but with increasing stack frame numbers) until you get an actual snippet of source with line numbers rather than just assembly.

Really unfortunately, llbd is much more verbose and difficult to use than gdb :(

@NEO:Okay, from what I can tell from the console output, the first one it looks like the file dialog on OSX is returning true when it shouldn't, judging by this line: Opening game ''). That should be simple enough to fix.

The Audialis shutdown crash I think I have a lead on, but I'd need to see your entire console log, from "Parsing command line" on.

The problem very well could be audio. Among other things, I got warnings about missing libdumb and libvorbis for some reason during early attempts to compile, and when I followed the wrong instructions early on and CMake'ed it to be a Framework it kept giving "unexpectedly closed" errors during the process.

Interesting, apparently for whatever reason your system doesn't like uint uniforms in shaders. That same shader compiles fine on every Windows machine I've tested on, although I can't speak for Linux as I've never seen DaVince's startup listing. In any case, the uniform in question wasn't even used (it was part of a failed attempt to implement blending in the fragment shader), so I removed it and also cleaned up the CoffeeScript output (I forgot to add newlines).

I did manage to fix (or think I fixed) the crash on canceling the file dialog. Apparently al_show_native_file_dialog() returns true on OS X on cancel, even though it returns false in that circumstance seemingly everywhere else. Then again, I probably just misinterpreted the documentation:

I originally interpreted "failure" to mean "the user closed the dialog", but that might not have been the intent, since Allegro provides a different function, al_get_native_file_dialog_count(), which returns the number of files selected. If the user cancels, the documentation says explicitly that this will return zero. So that's what I used.

Just compiled 1.5.3 and same errors when trying to free audio, but seems like it gets there much faster now so whatever you did to fix OSX open file dialog seems to work. How do I set a breakpoint to confirm the above?

I don't think setting a breakpoint there would help much unless you had a really good knowledge of Allegro. You basically need to know exactly what is going on in the function directly above the one you set a breakpoint at the edge of.

You need to set breakpoints either before you type `run` or at the prompt you get by hitting ctrl+c at the terminal while the program is running (or when another breakpoint is triggered, either from a set breakpoint or from a segfault)

I don't recall the syntax for setting it at edges of certain functions. This is where lldb's syntax is really annoying. Everywhere else it's basically just an extra letter here or there, but with breakpoints its fairly obtuse compared to gdb, Intel's debugger, and MS's command line debugger.

MS has a command-line debugger? I never knew that. The only one I ever remember is the DEBUG command in DOS. And that was more of a disassembler than a debugger anyway.

As for this crash, the most interesting part to me is the stack trace. There is no user code on the stack at all--only Allegro functions and system calls. this makes no sense to me since the last thing printed to the console is "Shutting down Audialis", whereas in a clean shutdown there are a few more steps after that. So there should definitely be engine code on the stack at that point, but there clearly isn't. I'm baffled.

edit: Hey, I have an idea! Any chance you could run the engine under valgrind? That tends to find weird memory bugs like this.

Okay, so in this case it's crashing trying to free the main mixer. So why on earth does the stack contain no minisphere code whatsoever...? The only thing I can think of is that some sort of exception is being raised and Allegro's shim for main() is catching it, obscuring the real source of the bug.

That's what I suspected at first too, but the stack says otherwise: there's a call_user_main() in there, which wouldn't make sense for a worker thread, and I also see an exit() in there, so it's running atexit stuff. Looks like the main thread to me.

Wait a minute! I seem to remember that Duktape calls abort() in the case of unrecoverable errors. Allegro isn't throwing any asserts even though it's clearly a debug build (Allegro source shown in lldb), which means I may be barking up the wrong tree. CoffeeScript triggered a recursion error during startup, while it works normally here. So something wonky may actually be going on in Duktape...

Hm, well it was worth a shot at least. Having studied your backtrace AGAIN (it was very illuminating, thanks!), I notice an exit() call in there. So something, somewhere is calling, I assume abort() in response to the crash, and that could be why main is no longer on the stack (do exit()/abort() unwind the stack?). That's why I suspected Duktape, because I know it will do so in case of an unrecoverable error.

I find it interesting that it still crashes in response to canceling the file dialog, but in a different spot than the crash on shutdown. I'm curious now, will it run normally if you give it an actual game (not a Hello World stub) to run and only crash on shutdown, or would issues show up sooner...

By the way, not related to the crash, but could you add a define for DUK_OPT_DEEP_C_STACK to duktape.c and let me know if CoffeeScript starts working again (i.e. the RangeError disappears)?

Now if only I could figure out what's causing these crashes... I won't rule out that the bug is on my end. I know I've encountered similar issues in the past where things that should fail end up working on Windows preventing me from reproducing them. For instance, a while ago DaVince discovered a crash in 1.2.2 that I couldn't reproduce, caused by a double call to fclose(). This has the same effect as a double free in Linux but in Windows it doesn't raise any red flags whatsoever--it succeeds without complaint. I only figured it out after poring over the RawFile code for a while.

Now if only I could figure out what's causing these crashes... I won't rule out that the bug is on my end. I know I've encountered similar issues in the past where things that should fail end up working on Windows preventing me from reproducing them. For instance, a while ago DaVince discovered a crash in 1.2.2 that I couldn't reproduce, caused by a double call to fclose(). This has the same effect as a double free in Linux but in Windows it doesn't raise any red flags whatsoever--it succeeds without complaint. I only figured it out after poring over the RawFile code for a while.

If I could understand Allegro better I would help poring over Audialis, since if it likely ends up being a double free to allegro_audio it's almost certainly there.

*sigh* I am so far behind in my independent programming studies and now currently lack motivation to learn anything useful :'(

The debugging feature should work, as it just uses the Duktape debug API. A client needs to be written using Duktape's remote debug protocol to take advantage of it, however:https://github.com/svaarala/duktape/blob/master/doc/debugger.rst

1.6.1 fixes a bug in the Sockets API where listening sockets wouldn't accept connections from IPv4 clients (including local clients, i.e. those connecting to 127.0.0.1).

I can also definitively say the debugging support in 1.6 works great. I got a proof of concept plugin working in Sphere Studio that just sends a "resume" message to the engine. The game runs upon receiving this message, so everything's in order so far! Now to implement full debugger support in Sphere Studio... ;D

NEO, could you try building the latest Allegro from the github mirror and let me know if the crashes are gone?

Rebuilt Allegro, pulled latest minisphere, removed MNG stuff as usual (I'll eventually go find libmng and build it to resolve this bit), recompiled. Ran my one-liner and exits clean! Ran and canceled choosing a game and exits clean! Ran CellarRush.spk and got an error that it failed to load sound file '../music/dungeon-v2.ogg' and exits clean!

For reference, building Allegro has consistently given me warnings about inability to build in loading of many audio formats like vorbis and speed.

Alright! Except for me advancing on the MNG front and figuring out how to fix audio building without building all the libs from scratch (it'd be nice if homebrew would update Allegro) it seems Sphere on Mac can indeed progress further! Now to resume my Pang96 conversion... ;)

I downloaded this a few days ago and I could run Sphere Studio just fine (even though I ran into problems trying to actually make anything), but now it doesn't even launch at all. When I try to run it just doesn't open. Help?

Everyone: Next release will change the debugger semantics (allowing a debugger to be attached at any time) and include a debug-enabled build of Sphere Studio. :)

Edit: Also in the pipeline: ArrayBuffer support. I bit the bullet and procured the latest build of Duktape to enable this. From what I've seen, the Duktape master is extremely well-tested, so I'm not too concerned about catastrophic bugs there. :) There are also supposed to be some performance improvements in the latest builds!

EDIT: But now when I try to add files to my project, it gives me unhandled exception errors about "illegal characters in path" and "Object reference not set to an instance of an object". When I try adding a spriteset it says "Can't load spriteset: ?.rss".

The spriteset creation is probably a bug caused by my recent changes (it's going through a bit of upheaval at the moment), I'll look into it. Not sure about the illegal filename characters though... That seems weird.

The spriteset creation is probably a bug caused by my recent changes (it's going through a bit of upheaval at the moment), I'll look into it. Not sure about the illegal filename characters though... That seems weird.

I guess I'll use the editor provided with Sphere 1.5 for now. I just need to figure out how to get it to work with Minisphere.

Well, that didn't take long... I had to bump to 1.7.1 because I forgot to include a Duktape fix for improper breakpoint triggering in 1.7.0 (breakpoints inside if statements would trigger even if the condition itself wasn't hit).

I tried out the debugger and I must say it's rather well done! I'm impressed. :) It doesn't handle infinite loops though, like a main game loop. But for certain function calls it's good to step through them and see what they do.

The packager is neat too. This is feeling like a real editor now. This editor with minisphere + debug is far more robust of a tool than ever before.

If you step over a MapEngine call, it won't return to the debugger because MapEngine() runs its own loop. If you use the analogue.js included with 1.7 you can set breakpoints inside map scripts though. :)

I don't know if you noticed, but in the variable viewer there's also an "eval" textbox... you can enter code there while execution is paused to inject stuff. Whatever you enter will be evaluated within the current scope so that you can modify local variables, etc.

If you step over a MapEngine call, it won't return to the debugger because MapEngine() runs its own loop. If you use the analogue.js included with 1.7 you can set breakpoints inside map scripts though. :)

Yeah, that makes sense. I'll definitely try out the eval, it was very helpful to have that in the .NET debugger and so to do that in minisphere - that's just wow, that's amazing!

BTW +1 for analogue shoutout, this is not something you could have done easily in the map editor.

Note that the analogue debugging is only possible because I modified analogue.js to use EvaluateScript() to pull in the mapscripts. This is incompatible with Sphere 1.x because EvaluateScript() doesn't return anything in that engine for some reason.

Unfortunately this change was necessary because otherwise Duktape doesn't assign a filename to the script and therefore breakpoints won't work. Overall I don't think it's a big deal though--I would say the vanilla engine is well and truly obsolete at this point. ;)

This may have been covered already, but there are 32 pages. minisphere doesn't accept constant (const) variables?Also, it doesn't really look like the engine doesn't really say much about what went wrong. It just says "Parse error"

Yeah, "parse error" is all Duktape will give. Not much I can do about that. And yes, const isn't ES5 compliant so it's not supported. The Duktape developer is working on adding ES6 features though, so hopefully it'll make it in soon. In any case, it's mentioned in the readme.

So who thought minisphere would ever be this successful? Least of all me. In less than a year we now have a 99% compatible replacement for the vanilla engine, a bunch of new Sphere 2.0 stuff and even a stepping debugger, something I think Sphere has needed for a long time. And all this from an experiment that I thought would never get off the ground...

At this point, at v1.7 I feel I can call minisphere fully mature. Which means, I think it's time to get started on that JS map engine. :). Now more than ever, with a full debugger, being able to step into map engine code will be very useful, I think.

I'm tempted to ask you to fork minisphere once that's done so that one version has only the vanilla stuff for 1.5/1.6 (i.e. disable all the experimental/minisphere-specific API), we'd commit that to vanilla Sphere, then officially recognize minisphere as the vanilla successor and all the experimental/ms-specific stuff would be considered "proposed additions to Sphere 2.0" or "draft status" (using W3C terminology), then it's an arms race between the big three Sphere engines.

In this scenario, for lack of a better analogy minisphere becomes WebKit, TurboSphere becomes Gecko, SSFML becomes IE/Edge, YASE/sphereclone (http://forums.spheredev.org/index.php/topic,72.0.html) might be Opera/Presto unless casiotone decides to resume work on it or it gets folded into another engine project, the various web-sphere implementations are still web-based, and all other attempts at Sphere-compatible engines still exist but we haven't heard from them in a while.

I don't know, at this point I feel like that would just be needlessly extending the vanilla engine's life for no real gain. If I were to add the missing primitives the engine would be 100% backward compatible as-is (save some audio formats), no need to make a build with removed functionality. We WANT to get new users to use the new stuff, and having separate stable and unstable/experimental versions might scare them off of doing so. In fact the additional bells and whistles are the biggest reason I recommend minisphere over vanilla--a build limited to just the 1.x APIs would Have no real advantage over the original engine, IMO. Duktape is faster, yes, but not enough to make-or-break.

It's tempting to want to wait until Sphere 2.0 has stabilized to commit to anything, but part of the reason I took the initiative with minisphere in the first place was because that process was going nowhere--note the sorry state Pegasus ended up in.

I think our best bet is to embrace the extension system I already have implemented and, instead of standardizing "Sphere 2.0" wholesale, we work on standardizing the individual components. So you would have a standard for Audialis, one for Galileo, etc., each with a unique extension string exposed through GetExtensions() and they would all be Sphere 2.0 components. This is how the Ecmascript specs are built, and the process seems to work very well.

It's tempting to want to wait until Sphere 2.0 has stabilized to commit to anything, but part of the reason I took the initiative with minisphere in the first place was because that process was going nowhere--note the sorry state Pegasus ended up in.

Yeah, that's why I made Sphere Studio. There was a time when Vexo (man, what happened to these people :() said every year someone comes up with the idea of a new IDE and it always fails. I was thinking if I used a proper language and environment, say C# and WinForms I can make an IDE three times faster than anyone else (imagine doing it - alone - in C or C++!) and I'd have managed, clean code to work off of. .NET was built around the concept of being a desktop application developers language, or rather for Software Engineering projects in general.

I don't know, at this point I feel like that would just be needlessly extending the vanilla engine's life for no real gain. If I were to add the missing primitives the engine would be 100% backward compatible as-is (save some audio formats), no need to make a build with removed functionality. We WANT to get new users to use the new stuff, and having separate stable and unstable/experimental versions might scare them off of doing so. In fact the additional bells and whistles are the biggest reason I recommend minisphere over vanilla--a build limited to just the 1.x APIs would Have no real advantage over the original engine, IMO. Duktape is faster, yes, but not enough to make-or-break.

It's tempting to want to wait until Sphere 2.0 has stabilized to commit to anything, but part of the reason I took the initiative with minisphere in the first place was because that process was going nowhere--note the sorry state Pegasus ended up in.

For all intents and purposes, the primary advantage a vanilla API minisphere would have over classic Sphere is the existence of reliable modern dependencies and cross-platform consistencies across modern systems. minisphere comes with Duktape bundled and only requires the easy-to-package Allegro, and is guaranteed to work on all three common modern systems (and probably will work on Windows < 7, OS X < 10.9, various older Linuxes, maybe the BSDs); Classic requires a slew of first-party dependencies that may or may not bundle/compile/package/etc cleanly and easily on modern systems (I'm sure y'all remember the PITA modernizing audiere was), and is only guaranteed to work on older Windows (I don't remember if 1.5 worked easily on >=Vista or not), OS X < 10.7 with the separate dependencies bundle, and maybe some Linuxes.

But yes, I understand the desire to "get new users to use the new stuff;" remember I was a web developer trying to convince clients to modernize sites to support Firefox & Chrome back when IE6 was still a thing ;)

I think our best bet is to embrace the extension system I already have implemented and, instead of standardizing "Sphere 2.0" wholesale, we work on standardizing the individual components. So you would have a standard for Audialis, one for Galileo, etc., each with a unique extension string exposed through GetExtensions() and they would all be Sphere 2.0 components. This is how the Ecmascript specs are built, and the process seems to work very well.

Ecmascript, CSS3, and HTML5 use this modular draft system, and I agree with its methodology. The doc for GetExtensions says the strings returned are mostly self-explanatory, but honestly I feel the new ones (basically any string that's not "sphere-legacy-api") need some sort of explanation, and I'd probably like to see some sectioned, e.g. sphere-audialis sectioned into sphere-audialis, sphere-audialis-wav, sphere-audialis-mp3, sphere-audialis-midi, sphere-audialis-ogg, ..., as R/W capabilities warrant. I assume the preferred way to check for certain functionality is (GetExtensions().indexOf(theCapability)!==-1) ?

The doc for GetVersion says minisphere 1.4 and needs the version number updated, FYI.

Does it? ill have to fix it. I make a point to update the GetVersionString() return value every major release, but may have missed an annotation elsewhere. The actual function should return the correct API version (2.0) in any case.

indexOf is the best way to check for extensions, yes.

But anyway, I don't think actively stripping out functionality helps anyone when the engine is already compatible with vanilla. Vanilla compatibility is neatly encapsulated by the sphere-legacy-api extension, if you need to code against the new stuff you check for the appropriate extension and either degrade gracefully or fail outright. That's why the system exists.

Speaking of which, I don't know that it's a good idea to overly compartmentalize the extension system as you're suggesting. Extensions are shorthand for a set of APIs, supported formats don't really need dedicated extensions as more formats might be supported via plugins or whatnot, a la TurboSphere--and depending on the backend used, may even change between platforms...

As for documentation, again, each extension string represents an API. So to find out what each represents if it's unclear, you have to read the API reference. ;) Both Galileo and Audialis are covered via short descriptions and function documentation. Even SphereFS is explained in that document.

Overall I just think that releasing a stripped-down engine is akin to saying "here's a modernized IE6, we know you're not ready for all the new technologies yet but at least it's new, right?" Maybe that's just me though.

But anyway, I don't think actively stripping out functionality helps anyone when the engine is already compatible with vanilla. Vanilla compatibility is neatly encapsulated by the sphere-legacy-api extension, if you need to code against the new stuff you check for the appropriate extension and either degrade gracefully or fail outright. That's why the system exists.

[ ... ]

Overall I just think that releasing a stripped-down engine is akin to saying "here's a modernized IE6, we know you're not ready for all the new technologies yet but at least it's new, right?" Maybe that's just me though.

I understand your approach better now. I was of an old mindset of "test if GetVersion() > X for Y functionality" to do stuff and forgot for a while that a modular extensions system like yours and testing for extension existence is indeed almost always the better option; it's the core tenet of Modernizr, among other libraries, and Crockford preaches about the methodology so hard in JS: The Good Parts that I really should have known better.

...crap. That it took me this long to put 2 & 2 together about this means the depression I seem to have is getting worse; the fact that I'm apparently losing focus and acuity in THIS aspect of my life is a pretty bad sign for me.

Yeah, that's pretty much it. Technically GetVersion() never has to return anything > 2.0 now since 2.0 implies the existence of GetExtensions()--and if THAT exists, you should be using that to test for feature support beyond the vanilla subset.

So I'm working on a modification to Duktape that will allow minisphere to break into the debugger if an error is thrown. Attached is a screenshot of the dialog which would be displayed by Sphere Studio if this is successfully implemented:

I think I want to make a command line debugger for minisphere. Being able to do it in Sphere Studio is great (I always prefer an IDE for debugging), but this would allow debugging on any platform minisphere runs on, not just windows. Especially if I coded it in C.

Okay, 1.7.7 is up, fixing misbehavior when infinite recursion is encountered--"double error" for a normal run, or an outright crash with the debugger attached. Now it properly throws a RangeError in this case, which will be caught by the debugger.

I decided for minisphere 2.0, I'm going to deprecate ByteArray. It will still be retained in the API for backwards compatibility, but all the new APIs (such as the new Sockets API) are being updated to use ArrayBuffers and TypedArrays instead.

I'm also going to try my hand at writing a new map engine in JavaScript. Despite my misgivings in the past, I think this will ultimately be a good thing to have, if only because you'll be able to step into map engine code while debugging. As with ByteArrays above, the classic map engine will be retained with its API fully intact.

Let me just say for the record here that SCons is a hellish nightmare to work with. Things that should be simple like pulling in sources from minisphere to use in Cell cause no end of grief under SCons because it doesn't make a clear distinction between source and object files and treats one as a stand-in for the other. That is, if you use the same source file in two programs, it compiles it once and tries to link the same object file into both programs. And then if you try to use different compiler options between the two, SCons throws up its hands and gives up ("Two environments with different options for same target").

It doesn't help either that the SCons documentation is absolutely atrocious. It took me forever just to find (on an obscure Stack Overflow question) that the solution was not to pass the .c file to Program() directly, but use the Object() method like so:

That didn't work either. At all. Seriously, whoever wrote this piece of software should be drug out into the street and shot.

edit 2: So it started building properly again for no apparent reason. Well, I'm not going to complain, but it doesn't do much for my faith in this build system. I wonder if CMake is any better. In any case, SCons provides a good baseline of what not to do in Cell. :P

Chad Austin is in the credits for SCons. That's how I originally found it.

The docs are bad, mostly because SCons wiki was destroyed by spambots a few years ago. I usually use the archive.org'ed version of it, since it was never properly rebuilt.

SCons doesn't make any distinctions about what anything is. Everything has a way of being created, and may be needed for something else. If you only care about compiling that C file, then you pass in that C file. Since you care about more than that (compiler options), what you care about is the resulting object files. This is how any dependency driven build system works.

An alternative (I suspect the intended way) is to use static libraries, since using the static library builder lets you do what you want--different options on the same source to create different object files. In general, static libraries stand in for individual object files in SCons when you don't want to build something in just one step.

Okay, but if I use the same .c file in two programs, why does SCons think its a reasonable default to only generate a single object file for that source, even though the two programs may (and probably do) need to be compiled with different options? That's what I meant by using sources as a stand-in for objects--if I tell it to build a program from main.c, SCons interprets that as "build a program from the object file created from main.c"--and any reference anywhere (even in different environments!) to main.c refers back to that exact same object file. It makes no sense and I feel like I have to jump through hoops (using Object builders, etc.) just to get it to do something sane.

Referring directly to main.c when using either the shared library or program builders basically means you want any object file of that source. When you mean a specific object file, then you must specify that specific object file.

Basically, it's just a shortcut that simplifies things in 99% of the uses. This way you don't need to specify the object builder for every single source file, and managed each object file through to the library or program builder. In this case, you don't want to use that shortcut, and unfortunately the long-hand way is kind of obscure.

The other answer is that it's kind of bad practice to compile the exact same source with functionally different compiler options. But that's kind of a bad answer, since I know a lot of projects (both C and C++) do it.

I usually do this sort of thing (mostly when I want different preprocessor directives) by creating a C or C++ file for each use of the single source file, and including it from those. I never compile the main source directly, but instead the files that included it. That also keeps as much of the preprocessr usage out of the build system as possible, which I consider a good thing. The down side is that I'm including actual source files in other source files, which is a little unusual. But the up side is that it is clear what options are being specified from the source itself, and it also makes supporting multiple build systems easier.

So I may have gotten spoiled by Allegro. I had to pretty much reimplement its entire path builder API from scratch for Cell because it was very powerful but there was no way I was depending on Allegro for a command-line tool. On the upside, my custom path routines now have better canonization than Allegro, I can have it collapse upstream (../) hops which Allegro's canonizer won't do (it's not symlink-friendly) but is needed when working with, e.g. SPKs.

Paths are represented internally as an array of hops, which makes the whole thing platform-agnostic: Only the pathname string creation needs to be changed to use a different seperator (but almost all platforms accept / so this isn't even necessary in practice). It also makes working with paths safer since there is no risk of a buffer overflow--each hop is allocated independently using strdup().

Path building functions are one thing I always tend to miss when I'm not using .NET, so having them in C now is awesome.

Cell is coming along nicely, and should be a nice addition to minisphere 2.0. game.sgm is no longer a requirement for a Sphere project, instead you have a cell.js build script in the source directory, like this:

Now to really bring out the potential of this tool, it will need some image processing functions. Is Corona still active or is that a dead project at this point? I think I remember someone saying it was revived, but... If not, I'll probably just integrate libpng for image processing.

If anyone's wondering where I'm going with this, it's to support compiling spritesets and tilesets on-the-fly during the build process. Sphere formats are a pain to edit, even with a purpose-built GUI, and would be much easier to manage I think if you could create them from bare images. How this would work is you declare an asset in the Cellscript, like this:

And then Cell would build the .rss file at compile time from the input image. This would allow you to edit your sprites in your favorite image editor and let Cell deal with getting them into the proper format for the engine without a bunch of tedious copying and pasting into the RSS editor. ;D

Hm, I had forgotten Corona was C++. Like minisphere, Cell is written in C so I would need to write a wrapper to be able to use it. For now bare libpng will suffice.

Anyway, apparently the RTS tileset format doesn't support compression? There's a "compression" flag in the header, but the RTS doc says it's unsupported. As a result a tileset with just 256 32x32 tiles is already 1MB.

Since the flag is already there, I could add compression (either PNG or raw zlib) support easily enough (breaks backwards compat) but I'm not sure yet if it's worth the trouble--you get the zlib compression for free anyway via SPK packaging, which with Cell is ridiculously easy--just run cell -p mygame.spk.

Corona has a C interface, although it's 'hidden'. Corona's ABI is totally compiler agnostic--you could compile it with MingW and call it from MSVC, compile it with Solaris Studio and call it from tcc, etc. As a part of this, all functions have static versions, and all outward facing functions have no name C++ mangling.

So, here is what XNA does. XNA keeps all assets uncompressed even post pipeline (even if you fed it compressed formats like .png). The reason for this is because these games can be released in an archive format sorta like zip (or for Sphere, .spk) and so get benefited from compression. Further, when they decompress, there is no need to decompress a second time (e.g. from png to bmp). That way files can exist within a virtual file system and be streamed rather quickly into the game. This is how all great game engines work from Quake to Skyrim.

Sphere can be something like that. I was on a game developers forum and they laughed at me for having talked about releasing a game with hundreds of assets in subfolders (namely, every Sphere game not in a .spk format). BTW, spk's like other game engines shouldn't need to be compressed to the storage device - the assets should go straight from spk to RAM. But I think you may have that covered already in minisphere (;)).

So whatever processing occurs it's good to keep in mind what gets compressed or not, since it's the final compression - the .spk - which matters the most.

But yes, that's what spk_fopen() does - it decompresses the packed file into a malloc'd buffer and any subsequent file reads simply read from that buffer. Allowing write access (for transparency) was a bit trickier: I had to check the spk_fopen() mode string and if write access was requested, unpack the file to disk first then open that. The end result is that minisphere's SPK handling is actually more robust than 1.5's: many games that broke under the old engine when packaged work just fine in minisphere.

That makes sense though, keeping assets uncompressed on disk. This way too, if the SPK format gets an upgrade to use, say, LZMA compression it isn't held back by already-compressed assets being stored as-is.

The only downside I've had developing XNA games is the friggin' huge filesize on my storage device. But, that's considered standard in the industry (for all major fields whether you are a recording artist in a sound studio, a director shooting a film, or an animator or game developer). Almost nobody uses compressed formats professionally.

So apparently libpng v1.2 and v1.6 are mutually incompatible. That makes things difficult, as it seems most Linux distros only provide a package for libpng 1.2, meaning my Travis build is quite thoroughly broken right now. To get around this, I attempted to compile libpng 1.2 on Windows, but it seems that release uses an older zlib which is ALSO incompatible. Lovely. And I guess I'd have this same issue even if I switched to Corona, since it uses libpng...

No. Corona works with libpng older or newer than libpng 1.2. You just need to have compiled it for whichever libpng you have on that system.

Travis uses somewhat outdated Debian. Which is about the only place that still uses such an ancient version of libpng. My main complaint about Travis is that the system it represents is very out of date. Very few Linux users will have an environment like it.

Well, that's good to know at least. Still stupid that the PNG group thought it was a good idea to release a 1.5/1.6 and not keep it at least somewhat source-compatible with 1.2, though. The API is completely different. I know PNG predates semantic versioning, but even so, that's tacky.

That said, I removed the image processing for now as it was only being used to generate tilesets, but that's not useful as the resulting tileset has no obstruction data. I haven't come up with a solution for that yet.

No, I like the new API a lot, don't get me wrong on that. :) It's just that they should have versioned it at 2.0 to make it clearer that the upgrade wouldn't be seamless. Keeping the major version the same implies at least mostly-backward compatibility with code from the older version, which isn't the case at all. It certainly caught me by surprise!

Hm, I'll look into it. However, off topic, I found this:https://github.com/dimensio/libpng16-deb/blob/master/README.md

Ubuntu, which Travis uses, includes 1.2. The readme also says Debian is experimenting with adding 1.6, but there are apparently compatibility issues preventing it. No idea why but that explains why the Travis build fails at least.

The first pre-release of minisphere 2.0 is now available, minisphere 2.0b1! This includes a preview of the new Cell compiler. To get started with Cell, place this example script in any Sphere game directory as Cellscript.js:

Hopefully someday we can start marketing a nice solution to game hobbyists. I think Sphere has fallen in visibility lately and we can try to re-ignite what was there under Minisphere and my editor. Perhaps get a more advanced crowd to who'll appreciate debug tools and command line build scripts. ;)

That's actually my overarching goal with the recent additions (from around 1.5 on)--to make Sphere look like a serious tool for game development, beyond the "toy" that is Sphere 1.5. To accomplish that, I realized it needs to be more than just the engine; it doesn't matter how many awesome features I add to it, there needs to be some sort of toolchain to go with it.

If you think about it, being more than just a toy is what got Sphere on the map originally--it had JavaScript, a full programming language, while everyone else was using RPG Maker 2000 with its point and click "scripting".

Also, I remember talk about an overhauled map engine at some point? Definitely check out http://www.mapeditor.org/ - it's a fantastic cross-platform map editor I've been using since very recently which is just EXCELLENT and I think integration of its map format into minisphere would be *very* beneficial for Sphere and the community to have. And re-ignite some of its flames.

Heck, look at what already supports it (http://doc.mapeditor.org/reference/support-for-tmx-maps/). Add minisphere to that list and bam, visibility goes up. :)

That map editor looks awesome. I'll see about integrating it, even if I don't support it in the engine directly I could have Cell be able to compile it to an RMP if nothing else.

Speaking of which, thanks to a recent massive overhaul of Sphere Studio's plugin system, the minisphere 2.0 GDK will have much tighter integration with the editor. So you won't have to drop to the command line to get the full power of Cell! ;D

As for the overhauled map engine, I was considering doing one for minisphere 2.0 in JS. I keep putting it off to do other stuff though, like the Sphere Studio overhaul, because I know it will be a huge undertaking. Implementing the classic map engine was easily the most time-consuming part of minisphere's early development, and that was working off of the original Sphere 1.x source!

As for the overhauled map engine, I was considering doing one for minisphere 2.0 in JS. I keep putting it off to do other stuff though, like the Sphere Studio overhaul, because I know it will be a huge undertaking. Implementing the classic map engine was easily the most time-consuming part of minisphere's early development, and that was working off of the original Sphere 1.x source!

Always remember the most immediate advantage of making a piece of the engine in JS is how easily portable it will be to the web versions (and likely inevitable node.js version). Once a working proof of concept is made (can probably reuse casiotone's, Radnen's, and/or my existing JS animation code (http://www.spheredev.org/fmt/) for animating tiles), THEN we can worry about optimization and stuff. If you look at the source for mine you'll see I had almost finished map stuff, but I was stuck on figuring out an efficient animated rendering method and didn't go further.

Note: in my tile animation demo section the 'A' that marks animated tiles is HTML, not canvas, so don't worry about a parsing error there if you want to save the canvas to a file.

I found it was much, much faster and easier to write a map engine clone in JS. And I also found that, just knowing what characteristics it should have and implementing those, I came very close to creating an equivalent object-oriented API without really meaning to.

That was what prompted me to try and rewrite more of the API in JS. I found it was actually pretty easy for a lot of the API, and didn't incur much of a performance hit at all. Fortunately, SpiderMonkey is able to properly manage its own memory, so I could finally tie GPU resources to JS objects.

That was also what made me think about putting almost the entire API in script. Just expose a single ArrayBuffer that is the screen, and ArrayBuffer-like object you can post audio to, something equivalent in functionality to the RawFile object for filesystem and network access, and an object that represents input. Everything else can be done in script.

That ArrayBuffer-like audio object is answered by Audialis, which as of 2.0 will support 8, 16, 24, and 32 bit audio, the last one being float. Likewise RawFile is being deprecated in favor of the new FileStream object.

24 bit audio might be a bit awkward with ArrayBuffers though as there is no Int24Array. Thankfully there IS a Float32Array. :)

Thinking about the JS map engine some more, I'm beginning to think it might actually be outside the scope of the minisphere project itself. It would be a great thing to have certainly, I just think it would be healthier as a project if it was maintained independently, instead of shipping with the engine.

The classic map engine will be kept in the minisphere 2.0 core for backwards compatibility (and as a convenient starting point for newbies), but I'd say any map engine projects going forward would be better off in the long run as independent projects. Especially with Sphere Studio's plugin system being actually usable now, map engines don't have to be shackled to the RMP format anymore and thus there's no longer any need for the "one map engine to rule them all" model used thus far.

@DaVince Looked at that Tiled editor, it's pretty neat, but I'm not a big fan on the XML format for maps. It also seems to be more complex than necessary and would require changes to the engine itself to fully support (e.g. changeable render order for tiles... weird, and kind of pointless). And are there even any XML parsers for JS? I'm not familiar with any if there are.

Do you lose the full feature set if you do though? or would it be like saving an MS Word document in RTF, it keeps most of the formatting but you lose the more intricate stuff?

From what I could see, it makes a perfect copy of all the data in the map. I tried all the different layer types, tile rotation, objects, custom properties, basically all of the major features in the editor. See attached file.

I'm thinking I'm going release minisphere 2.0 as-is, with only basic file copy and SPK creation for Cell. I started out a bit more ambitious than this, I wanted it to have various builders for maps, spritesets, etc. but that will require a bit more effort than anticipated--there's no way to specify collision data with only images, for example. So implementing that will need more thought.

The only other improvement I might make for 2.0 is a new SGM format, probably JSON-based. The current format is starting to show its age, especially in light of the recent SphereFS enhancements and such.

Want to hear something awesome? Cell is completely compatible with Sphere 1.5. :D I added a Cellscript to "In the Steps of the Blackfoot" (if anyone remembers, that was my first minisphere compatibility target), then used Cell to make an SPK from it and Sphere 1.5 ran the SPK with no issues.

I wasn't sure if it would work because I've had issues in the past with SPK creation where minisphere will read the package just fine but Sphere 1.5 either locks up or crashes when given the same package. So it's good to know I finally got it right.

Progress report:2.0 release has been delayed somewhat due to unforeseen issues. I wanted to release it last week, but decided to implement a game.sgm replacement... and that uncovered a few shortcomings in the way the engine is currently set up.

Long story short: JS context handling is broken. minisphere uses a single Duktape context which is created at launch and whose pointer is stored in a global variable. This is normally fine--only one game can be run at a time. The issues show up when a startup game is used: calling GetGameList() creates new temporary sandboxes which share the global JS environment and clobber stuff. This in turn causes weird crashes when switching games that are difficult to pin down. Fixing this will require a bit of refactoring, not sure how much actual work is involved yet.

The way I implemented it in minisphere is actually pretty clean: ExecuteGame() is simply a longjmp back into main() which shuts down everything and restarts with the new game (Duktape uses longjmp itself so it tolerates such antics). The fix for this is easy in theory: Duktape contexts are completely independent of one another, so sandboxing is trivial. The main issue preventing a quick fix is that API functions are also registered globally.

Good news: I managed to fix the bug without a huge amount of refactoring. Which is good, because the Duktape context wasn't even the half of it: There are file-scoped static variables all over the place, etc. that would need to be sandboxed as well.

The game.sgm replacement I came up with is nifty: It's JSON-based, and all properties contained in it are exposed to script by calling GetGameManifest(). This is useful for embedding game-specific data directly in the manifest, for example debugging options, and in the future it would even be possible to store the debugger map directly in the .s2gm file (Cell currently writes it to a separate file, sourcemap.json, by analogy with MSVC's .pdb files).

Just fixed the bug this morning where minisphere can't load images with the wrong file extension. The latest Allegro release (5.1.12) includes a fix for this, but building it in Windows is a pain (its CMake script can never find all the dependencies, making it work is an exercise in frustration) so I added a workaround myself. I'm determined to get KR running out of the box, hehe. :P

I may have mentioned this above but const works now, thanks to a quick hack by the author to add it as an alias for var.

The only thing I really have left to do is give the code another quick lookover to make sure there are no inconsistencies with the new behavior and perhaps strengthen the sandbox somewhat (it currently allows relative paths to go out of the game directory when it probably shouldn't).

Pretty much, yeah. There are a handful of lesser-used APIs that I never bothered to implement such as Complex(), but otherwise nearly 100% of the Sphere API is there. I even managed to add all the new stuff for 2.0 without changing the semantics of the legacy functions. Of course that was only possible because Sphere doesn't have constructors. :)

Oh, and there are also a few regexes that don't work under minisphere because Duktape's parser is stricter to the ES standards than most engines. Not much I can do there.

It craps out with a "not callable" error because Duktape doesn't support .toSource(). Apparently that's a Spidermonkey-specific thing. Duktape doesn't track source code for functions at all, even calling .toString() on a function just gives you an empty function body.

The debugger is such an awesome thing to have by the way, normally with Sphere I would have to drill down into the project tree to find the file (annoying when there are multiple levels of subfolders), then scroll to the correct line, instead I just let the debugger open the file and highlight the line for me. :)

Last-minute debugger feature addition: You can double-click any callstack entry while stopped at a breakpoint to see the values of variables in that function. Unfortunately you can only Eval in the context of the topmost call, so you can only view primitive values in this case. :(

A few planned features got knocked off the checklist, but regardless this is still a very worthy upgrade. The only thing I didn't get to yet was writing an API reference for Cell, but seeing as that API consists of exactly four functions, it shouldn't be a big issue. I'll get to it eventually.

The debugger improvements are worth the upgrade alone--you can now view variables at any point in the call chain, not just from the currently executing function. Plus you get some neat goodies like 16-bit and float support for Audialis, better integration of ArrayBuffers, and of course, the new S2GM format.

Sure, you should be good as far as Allegro goes, I'm still using 5.1.11. minisphere and Cell both build with no issues under Linux using SCons, so you should be good. Unfortunately, single-step debugging is Windows-only for the moment because I haven't made a command-line debugger yet, so you need Sphere Studio for that.

The engine will then check for required extensions when loading the game, before any JS code is even executed. This is better than leaving the requirements check completely up to script, as RequireScript()'d scripts may actually cause a runtime error before the check can be done if they use any extended functionality.

Quick update (2.1.1): JS errors are now more informative thanks to recent enhancements to Duktape. Instead of a vague "invalid base value" or "not string", you now get "cannot read property 'foo' of undefined" or "number required, found string 'foobar'" and similar.

You need:Allegro 5.1.11+ (may have to build this yourself, https://github.com/liballeg/allegro5)libmngzlib

From the command line, switch to the minisphere source directory and run scons which will build minisphere and Cell in the bin/ subdirectory.

Gave a missing libmng error (pretty much the only library error left after all the previous work I did before), DLed libmng 2.0.3 from Sourceforge, one `./configure; make; sudo make install` later was able to scons minisphere!

Running my two tests worked ok, running Radnen's Cellar Rush gave a LoadSound() error - failed to load some ogg file. I've previously had trouble building Allegro on this Mac with extended sound capabilities (including anything libogg related), so this one's probably on me.

Other than Allegro-specific or me-specific things like the libogg issue, it builds on Mac OS X Mavericks! I'll take a look at Allegro stuff later.

This current building served two purposes: make sure current minisphere builds and runs on Mavericks, and set up a prep environment related to my game dev and my RFC about adding Python (http://forums.spheredev.org/index.php/topic,1320.0.html).

Here's the thing with Allegro: By default it dynamically loads audio codecs such as libogg at runtime, and gracefully degrades if they are missing (this is annoying). You can static link them if you disable the CMAKE flag WANT_ACODEC_DYNAMIC_LOAD, not sure how feasible that is on OS X though. Either way, additional dependencies needed for Allegro audio:

dumblibFLAClibogglibvorbislibvorbisfile

They really need to get rid of that "dynamic link by default" feature, it causes so many headaches.

-- Allowing GCC/Clang to use SSE instructions-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) S3TC locking disabled. You will not be able to load/save pre-compressed textures with OpenGL.-- Could NOT find OPENSL (missing: OPENSL_INCLUDE_DIR OPENSL_LIBRARY) -- Could NOT find FLAC (missing: FLAC_INCLUDE_DIR) WARNING: libFLAC not found or compile test failed, disabling support.-- Could NOT find DUMB (missing: DUMB_INCLUDE_DIR DUMB_LIBRARY) WARNING: libdumb not found or compile test failed, disabling support. <http://dumb.sourceforge.net/>-- Could NOT find OGG (missing: OGG_INCLUDE_DIR) WARNING: libvorbis not found or compile test failed, disabling support.-- Could NOT find OGG (missing: OGG_INCLUDE_DIR) -- Could NOT find OGG (missing: OGG_INCLUDE_DIR) WARNING: allegro_video wanted but no supported backend found-- Not building ex_video-- Configuring doneCMake Warning (dev): Policy CMP0042 is not set: MACOSX_RPATH is enabled by default. Run "cmake --help-policy CMP0042" for policy details. Use the cmake_policy command to set the policy and suppress this warning.

You think this is bad, you should have seen me try to build Allegro on Windows when I first upgraded to 5.1. Even with CMake it's a nightmare, sometimes it doesn't find libraries that are actually present, or they'll fail a compile test for no reason at all (which CMake then "remembers" and won't try again until you blow away the entire build cache and start over). This is why I'm still using Allegro 5.1.11 even though 5.1.12 has some new stuff that would actually be useful to have (such as cross-platform clipboard support).

Allegro is a great library, but their build process needs a lot of work.

CMake is just always a bit of a nightmare. This is a pretty normal experience with it, especially on Windows.

In large part this seems to be caused by CMake's braindead caching setup: When a variable is set, its value is stored in the CMakeCache and future accesses will always just read from the cache. There doesn't appear to be any kind of conditional logic where the cached value can be ignored when something related to it changes.

Ok, that's it. I'm done with Sphere 1.5/1.6. That was the secret. I wanted you to do that, but never said, and now that you did it, bye bye Sphere 1.5/1.6. :)

Hehe. I wanted to do this a while ago, but I was too lazy to research the clipboard APIs for the different platforms. As of Allegro 5.1.12, basic clipboard functions are built-in, so I took advantage of it.

2.1.3 doesn't include the feature, but it's in the git repository anyway (Windows build requires VC++2015). If I release a 2.1.4 I'll backport it, otherwise it'll be in v2.2 along with some sort of physics support. I haven't quite worked out a good API for that yet.

Okay, Radnen, you lucked out, I had to fix a map engine bug related to GrabImage() (actually a regression due to a careless recent change to the map update loop) so I released a hotfix. Said hotfix happens to include the error message copying, so now you can download minisphere 2.1.4 and ditch Sphere 1.x if you want. ;)

As for physics, the API is going to need some more thought before I forge ahead with it, so I'm postponing it to minisphere 3.0. Instead I think I'll dedicate minisphere 2.2 to improving Cell. What was released of it with minisphere 2.0 is little more than a prototype and I'd like to make it a more invaluable part of the Sphere toolchain.

Yeah, you need Allegro 5.1 "unstable" (i.e. the API is unstable, it's actually quite reliable). Not sure if that's available through homebrew; you may need to build Allegro yourself:http://github.com/liballeg/allegro5

Thanks, managed to build Allegro. Now having a problem with libmng - I can't get that to build on OS X at all. I have no plans to actually use MNG, is there any chance you could add an option to compile without MNG support?

You're the second person to request that, I'll see what I can do. For now you can probably disable it by:* Remove 'animation.c' from msphere_sources in the SConscript* Remove 'mng' from msphere_libs in the SConscript* Comment out the call to init_animation_api() in api.c

There's been talk of Allegro adding optional MNG support to the library; if that happens I can do away with my own libmng dependency. Oh, that reminds me, watch out with Allegro's audio support; if you didn't set WANT_ACODEC_DYNAMIC_LOAD=0 when using Allegro's CMake, then it attempts to dynamically load libvorbis, etc. at runtime and fails silently if it can't, so if minisphere fails to load any sound files--it's most likely not my fault! ;)

You're the second person to request that, I'll see what I can do. For now you can probably disable it by:* Remove 'animation.c' from msphere_sources in the SConscript* Remove 'mng' from msphere_libs in the SConscript* Comment out the call to init_animation_api() in api.c

There's been talk of Allegro adding optional MNG support to the library; if that happens I can do away with my own libmng dependency. Oh, that reminds me, watch out with Allegro's audio support; if you didn't set WANT_ACODEC_DYNAMIC_LOAD=0 when using Allegro's CMake, then it attempts to dynamically load libvorbis, etc. at runtime and fails silently if it can't, so if minisphere fails to load any sound files--it's most likely not my fault! ;)

minisphere 2.1.5 fixes corruption at the end of a WAV stream (note: this was an Allegro bug) and adds an option to the GDK plugin to Test Game in windowed mode. The default is still fullscreen, of course.

So I've been thinking on and off about the direction I want to go with in minisphere 3.0, but I've been wracking my brain because pretty much all of what I set out to implement has been implemented as of minisphere 2.1. I haven't even been able to muster a clear plan for a v2.2 (which will likely end up just being some Cell enhancements), let alone a major upgrade. Which really only leaves one more hurdle: plugins. The engine already has most of the framework in place for this (the extension system), most of the work would be coming up with an API.

I like DrDobbs magazine for the conceptual things it contains. Just relax, sit down in non-programming mode, and read it. Around page 3/4 it goes into code... maybe it gives you an idea on how to start the API.

Hey, so this is just my selfishness speaking, but how feasible would a software renderer mode be? :P I'm developing something while temporarily on quite a crappy computer (Supports up to OpenGL 1.3...) so I obviously stumbled against the issue of not being able to run minisphere.

Hm, in theory it's possible to initialize Allegro in D3D mode, which would raise compatibility. The downside is that shader support would be disabled, but it would allow the rest of the functionality (including base Galileo) to work. I'll see about making that change in minisphere 2.2.

I'm still using a variant on that in UltraSphere/Turbo. I guess why complicate things, I never found I needed anything more than this. With how minisphere handles extensions, you could also add a GetExtension/GetNumExtensions component.

I've read that Dr Dobb's article, and I'm not really a fan of how they do it.

I have to agree. I looked over it and the very OO method they provided just seemed overcomplicated for most purposes. That said, I did use a similar setup when I overhauled Sphere Studio's plugin API, but at least there it's justified since 1) There are a bunch of different plugin roles (debugger, editor, engine runner, and so on) but I needed to be able to have one plugin implement multiple roles while still having a unified interface, and 2) It's C#, so I don't have to worry about name mangling differences, etc. like I would with C++.

Having just started work on minisphere 3.0, a question occurs to me: Would anyone be opposed if, for the 3.0 Windows release, I provided only a 64-bit build? The x86 build seems pretty redundant nowadays, I personally haven't encountered a 32-bit version of Windows in years.

On older systems, there are many other game makers... go for gold. When the time comes, compile for 128-bit.Before you tag and go to 3, can you take a tiny look at Linux? My latest succesful build was Nov 29. And

-- Allowing GCC/Clang to use SSE instructionsS3TC locking disabled. You will not be able to load/save pre-compressed textures with OpenGL.-- Could NOT find OPENSL (missing: OPENSL_INCLUDE_DIR OPENSL_LIBRARY) -- Configuring done-- Generating done-- Build files have been written to: /home/fbnil/MiniSphere/allegro5/Build

But I do not remember requiring that last time. Do you mean editing AllegroFindFFMPEG.cmake there remove FFMPEG... and... yes... now it compiles, and I can make install. hmm... did not recall this. Same error in minisphere though. Will check tomorrow, last time, I had to purge the previous Allegro version before it started working (too late now, need Zzzz)

If Allegro cmake can't find FFMPEG it should just disable the video component (or at least that's how it's supposed to work). This is fine since minisphere doesn't use that part. You should be in the clear.

To everyone else: I'm in the process of writing a full install guide for minisphere. This should hopefully alleviate some of the issues seen in the past for people building minisphere on non-Windows platforms.

Actually does minisphere even run on WinXP? Defiant had issues a while back, I think I fixed it but I don't have an XP machine to test on.

Well, I could probably test this soon... Just need to shrink my Linux partition on this old PC and install XP on it. Depending on the last version that works, you could still offer that as the last 32-bit version download for those who really are stuck on 32-bit Windows. :)

For SSJ, to make it as efficient as possible to debug on the command-line, I think I want to go with 1- or 2-character commands, for example "s" to step, "st" for a stack trace, "v" to list local variables, and so on. No prefixing commands with a dot or ! as that just slows down command entry.

I'm not sure yet how to handle locating sources for a game. Cell can optionally include a source map if needed when building a game (this is very useful as it allows SPKs to be debugged!), but even that uses relative paths. In Sphere Studio it's trivial to just resolve the relative path against the current project, but SSJ will need a command-line option or something to provide the location of the sources.

What features would you want to see in the debugger? Keep in mind some things might not be possible until Duktape implements them in its debug API, but I'll make sure to note any requests regardless. :)

I don't know if anyone remembers the --explode switch you could pass to Cell to get an easter egg (specifically, a quote from the program's namesake), but I'm starting a tradition with SSJ where all the GDK tools will have this little secret.

I see you're using minisphere 1.7.4. I was going to suggest upgrading to 2.1.6, but I think I know the cause of the bug: Your machine might not support OpenGL shaders. minisphere currently requires shader support to run. In the latest builds I added a fallback for that, but I didn't backport the fix to 2.1 because I figured it wasn't a practical concern. Seems I was wrong. ;)

I'll try running minisphere in my XP VM to verify my theory.

edit: Hm. The last line printed out by minisphere 2.1.6 on my Hyper-V WinXP SP3 VM is:

Interesting oddity I found: Cell doesn't work properly under XP either. I tried compiling Spectacles with it, and was told "no Cellscript.js in input directory", which is patently false. So it seems this might be file system-related. I'll keep digging.

Good news everyone: I finally got Ubuntu 14.04 successfully installed on my laptop to dual boot with Win10. What this means is that I can actively support the engine code on both Windows and Linux now (or Ubuntu, at least). Now if only I had a Mac, we'd have the trifecta...

If I could get some official Ubuntu packages going that'd be great for exposure too, I think.

Yes, that would certainly help a lot. You have time until Allegro 5.x hits Ubuntu (at least, your unstable version with the code you need to get it compiled/running).Also: Documentation documentation documentation. From using it as node.js (sphere was a crappy node.js, but I could serve webpages)... hmm.. maybe not this one...to debugger (good work getting it working!) to using it like image magick (I have some turtle code I think lost it) read png, add text, write to jpg things. Read file, parse data, create graph...to well... a game making software.Bundle it with some small default examples (from pianola to slideshow, an rpg, a sidescroller, things like that)

I still need to get into the code to add the things I miss (like changing the spriteset directions labels to "swap" graphics) and test out if I finally can access the spriteset image to mix it (overlay different hair (processed through a color matrix) and such to generate spritesets on the fly).

If you personally invest money in a Mac, I highly recommend getting into iOS app dev at that point, since IMO that's the only thing a Mac can do properly that no other OS can come close to (basically the iOS equivalent of the C#+Visual Studio vs. Mono+MonoDevelop and/or maybe the wine vs. Windows debate).

I have to say I'm not liking Linux as a development environment. It has all kinds of neat tools like valgrind (note: minisphere, Cell and SSJ all leak like a sieve :P), and of course the package system makes it ridiculously quick and simple to install new stuff, but for everyday code maintenance I'd much rather have Visual Studio, bloat and all.

Doing everything from the terminal and using a text editor to edit source files feels like a massive downgrade after being spoiled by Intellisense. I know there are IDEs that work on Linux, but... eh. I think I'll just stick to Windows for primary development. ;)

It's less that I can't remember the API so much as I strive for utmost readability, leading to descriptive struct member names like ignore_all_persons. Imagine how much time it saves when Intellisense figures out, nine times out of ten, exactly which variable I want after typing only one character (and sometimes not even that!). Then just press Tab to accept. It's a tremendous time-saver. I could survive without it, but code readability would likely suffer for it, as I would be too tempted to abbreviate all my variable and function names.

I found Eclipse slow (java based) although some of my colleagues praise it so much its religous, Codeblocks very fast (runs on the OpenPandora) and complete (but not the stable release, that one is 2 years old, you really want the rc1 from a month ago). And Not sure what happened to Qt Creator, it seems like gone, but was very good a few years ago.

I am curious about http://anjuta.org/ so I'm going to give it a spin.Never tried this one, but it looks also like something you would want to try:https://www.kdevelop.org/sites/kdevelop.org/files/photos/Kdevelop_cpp_codetooltip.png

I have to say I'm not liking Linux as a development environment. It has all kinds of neat tools like valgrind (note: minisphere, Cell and SSJ all leak like a sieve :P), and of course the package system makes it ridiculously quick and simple to install new stuff, but for everyday code maintenance I'd much rather have Visual Studio, bloat and all.

Doing everything from the terminal and using a text editor to edit source files feels like a massive downgrade after being spoiled by Intellisense. I know there are IDEs that work on Linux, but... eh. I think I'll just stick to Windows for primary development. ;)

Use MonoDevelop. It's really good and had decent intellisense last I used it. Plus, apps you do happen to make on it are Mono and therefore cross-platform. I might just restart my Mono Sphere Editor one of these days...

I've been trying to get Sphere Studio to run under Mono, but no such luck. Before the huge refactoring I did a few months back, it used to throw an exception related to the Weifen Luo controls. Now it doesn't produce any output at all, and terminates immediately. Not sure what's causing it and I don't know how to get debugging information out of Mono.

Sphere Studio itself requires .NET 4.5. It's impossible to backport now since it uses async/await pretty extensively, especially in the debugger code. But that's not the issue I don't think--everything else seems to work fine under Wine (even things I didn't expect to work, like running Cell and redirecting it's stdout to the IDE), until you go to open a file. Then it freezes.

I think the problem is that the Weifen Luo controls abuse P/Invoke for calling into native win32 APIs, to support things like interprocess drag-and-drop. Wine's emulation of the necessary APIs must not be perfect and so it causes deadlocks or something.

The weird thing is that the start page shows up just fine. It's quite baffling.

Here's a sneak peek at SSJ, the new console debugger that will come with minisphere GDK 3.0. It has fancy colors and everything! ;D As a convenience, SSJ will launch minisphere for you, meaning all you have to do to start a fresh debugging session is run ssj <filename>. This is especially convenient on Linux, which previously required using two terminals, one to run msphere --debug <filename> and the other for the debugger.

Anyway, check out the screenshot, it's looking pretty slick so far I think.

I did find that out, although in my attempts at that the two programs would fight over the same terminal, unless of course you redirect the engine's stdout elsewhere (which is exactly what SSJ does). In any case this matches how GDB and similar debuggers work, where you pass the program to be debugged as an argument to the debugger.

Basically, in Windows if you do start whatever, it opens a new terminal (console) for the program, I couldn't find a way to do the same in Linux.

Traditionally, you would explicitly start another terminal (usually `xterm`, which a lot of distros symlink to be their DE's terminal rather than the real xterm), which works similarly to `start` in Windows. If you pass an argument, that is executed by the terminal, which will exit once that command returns.

# You can run 2 things like this:$ xterm -title "This is a terminal1" -r -selbg blue -e "/script/or/program/run" &$ xterm -title "This is a terminal2" -e "vi" &# The wait statement waits for all the child processes...$ wait# now do some cleanup...echo "cleaning up"...

SSJ commands implemented so far (names subject to change as development progresses):

"go" - Resumes execution."step" - Step over, same as "next" in GDB"in" - Step in"out" - Step out"trace" - Prints a numbered stack trace, 0 is the function currently executing, counts up from there"var" - Prints local variables for the current function. Doesn't yet show values."eval" - Runs arbitrary JS code in the current context, can also be used to examine variables ("eval someVar")"quit" - Detaches the debugger and terminates

No breakpoint support yet, and the Step commands don't show any source code for context, but these all work otherwise, so I'm off to a good start. Oh, and it also reports uncaught exceptions.

Right now, single letters aren't accepted as valid commands, but I do want to implement that. It gets tedious typing 'step' (or selecting it from history) over and over again. :)

For the most part I take inspiration from gdb for command naming, but a few of its naming decisions baffle me. For example in gdb `step` is actually Step In, while Step Over is mapped to `next`. This is weird to me, since it's been my experience that the vast majority of stepping done is Step Over. In most cases with well-placed breakpoints you don't need to step into functions unless the code is really tangled. (the reason this matters is that it's quite a bit faster to type 's'+enter than 'n'+enter)

I will most likely rename `trace` to `backtrace`. Even though the term is odd to me, it matches gdb and lldb naming and is an accepted term for a call stack listing. As for `print`, I was considering that initially, but hesitated: `eval` can execute arbitrary code with any number of side effects. Someone using a command called `print` may not expect that. That said, I'll probably do it anyway though for parity with gdb.

What's your opinion of the command line (see screenshot posted earlier)? gdb's prompt is just "(gdb)", likewise for lldb, whereas I include the source file and line number. I'm undecided on whether this is legitimately useful or just adds noise.

I think the debugger having its own prompt name makes more sense when you have control of stdin, since many programs (in Unix at least) provide line-editing like features.

`print` in lldb does perform JITing in expressions via llvm.

In general if it were me, I'd take more inspiration from gdb than lldb. The latter tends to be much more annoying to use, since it's extremely verbose. The reasoning is that it's more orthogonal and descriptive, but in reality it just makes everything more work.

Most of the unusual names in gdb were just to give each command a unique but initial letter synonym. If you always call stack traces 'backtraces', you will always remember they are `bt` or just `b`.

I implemented stack walking, yay! You can now enter `frame <x>` to switch to a different function in the stack. Future requests to print variables, run code, etc. will then use that scope.

This is actually coming together pretty quickly! I do still need to implement source code listing and most importantly, breakpoints, and that should put SSJ pretty close to feature parity with the Sphere Studio plugin. Heck, I might even be able to rewrite that plugin to use SSJ under the hood, to avoid having to maintain two debugger codebases. ;D

I managed to finally compile minisphere, but only after using http://download.gna.org/allegro/allegro-unstable/5.1.13/ (but I also removed all allegro libs from my debian, breaking allegro games, then make installed the new version)I noticed that --game is not an option anymore, and I couldn't see why in the git log's, so I assume it is a bug?

-game (single hyphen) should still be supported for legacy compatibility, however new-style --game is not, because I switched to the more Unix-y convention of:msphere [options] <path>

This was changed in version 2.0. I don't think it will accept an .sgm file on the command line though, due to a bug I haven't gotten around to fixing. As a workaround for now, just pass the name of the directory containing game.sgm.

mp3 is impossible without relicensing minisphere as GPL (no thank you), and MIDI... I don't even know where to start with that. For Windows I can probably just call into winmm, no idea for other platforms.

That's definitely true in my experience - .ogg still sounds decent even down to 48kbps in stereo (the lowest bitrate the encoder will give you in "constant quality" mode) - try that with an mp3 and it'll be so full of compression noise as to be unlistenable.

I just switched minisphere's UNIX build system from SCons to make. Not autotools, I don't have time for that. :P It's a hand-made makefile. The makefile allows minisphere and GDK tools to be installed in /usr/bin as well:

I just switched minisphere's UNIX build system from SCons to make. Not autotools, I don't have time for that. :P

The days when Autotools made sense are mostly gone. Supporting Unix no longer means supporting Linux, Irix, Solaris, HP-UA, AIX, etc., and ignoring the hoopla, most Linux distros are very similar. The only thing you really need to do is support prefixes.

The other main use of autotools was to smooth over different libc's, but again, those days are gone. Every system either uses glibc, bsd libc (which is very similar in API to glibc), or something that tries its best to look like glibc (like musl).

So since Oracle either stopped or will stop working on the applet system (though thanks to Oracle's crap security, it was pretty much dead in the water a while ago) JavaSphere is a no go there, and since doing JavaSphere from scratch would be effectively reinventing the wheel, do you think it would be at all possible to port miniSphere to Android? Looking around, it doesn't look like it should be too difficult to compile Allegro stuff for Android. I'm not familiar with Allegro (I've mostly just used SDL in the past), but I'll see what I can do. Keyboard stuff might be a bit tricky, if impossible, but mouse stuff could possibly be converted to swiping and touching. So while there might be a lot of Sphere games that either won't work at all, or will have to be heavily modified for Android, I still think it could be pretty cool.

Allegro has a lot of stuff built in that I would likely have to implement myself or go looking for third-party add-on libraries to do in SDL, and it's ridiculously simple to compile static (the official Windows releases are statically linked to Allegro). Also, SDL as far as I know is LGPL, making static linking more of an iffy proposition due to minisphere's BSD license. Allegro is zlib licensed. Oh, and I like the Allegro API, very C-like. :)

Allegro can be compiled on Android, and actually I wanted to do an Android build of the engine at some point in the future, but getting the build environment set up seemed like a daunting task, so I keep putting it on the back burner. Feel free to try it yourself and let me know the results!

If that's the case, it might be easier to just use SDL or something. I'll look into working with one of the other cross-platform engines, or just making my own and using some code from them as reference. But I'm already working on a non-Sphere related project, so that may or may not happen. (shameless (http://github.com/eggbertx/gochan) plug (http://gochan.org))Heck, since it's developed by Google anyway, can is compatible with Linux, OS X, Windows, Android, and iOS and it can link other non-Go libraries like SDL and GTK, I wonder how feasable a Sphere engine written in Go (http://golang.org) would be...

Do keep in mind that when I said it seemed daunting, I was developing exclusively on Windows at the time--a platform which is not really well-suited to cross-platform development. :P Now that i have access to Linux, I might try it again at some point in the future.

That's fine. I haven't used it a whole lot since building it a few days ago in Linux, but it seems to run pretty well. This was more of a random idea, since Radnen suggested I look into porting JavaSphere to Android.

Allegro has a lot of stuff built in that I would likely have to implement myself or go looking for third-party add-on libraries to do in SDL, and it's ridiculously simple to compile static (the official Windows releases are statically linked to Allegro). Also, SDL as far as I know is LGPL, making static linking more of an iffy proposition due to minisphere's BSD license. Allegro is zlib licensed. Oh, and I like the Allegro API, very C-like. :)

SDL2 is zlib licensed.

SDL2 is also extremely similar to SDL1 in an API sense (to the point that a few very common functions now have dummy arguments to match the API of their SDL1 counterparts). I personally prefer SDL2's API, and if you were going to call it from Java I think it would be a much better choice since its API is very well suited to being used from an object-oriented environment. SDL2 also has full support for Android, and has a variety of features to either query the actual touch system or to just emulate a keyboard and mouse with it.

If cross-platfom is a goal, SDL1 and even SDL2 utterly annihilate Allegro, though :P

Not sure about Allegro 4, but v5 supports Android back to API level 12, iOS, and of course the big three (Windows, OSX, Linux). Possibly BSD as well, not sure about that though. Allegro 4 is very much a legacy platform (being designed originally for MS-DOS games and ported elsewhere over the years), v5 was rewritten from the ground up but it gets a bad rap because people assume it's just an incremental evolution of the classic Allegro.

SDL probably does support more platforms, but for something like Sphere, the 5 listed above should cover the majority of users. Honestly though most of why minisphere is still using Allegro is inertia - it was the first thing I tried after SFML, and had everything I needed--and still does--and now that I have the whole Sphere API built on top of it (note: the Allegro 5 API is VERY similar in structure to Sphere 1.x) it would be a massive undertaking to port it to a new backend.

Speaking of porting, I backported minisphere to be able to compile against Allegro 5.0, which is what's pulled by default via apt-get and homebrew since 5.1 is "unstable". This should make it easier for people to compile the engine now. :)

Allegro 5 sort of supports FreeBSD (no sound), and doesn't support OpenBSD at all. They say they do, but the OpenBSD people say they don't (and Allegro doesn't compile in OpenBSD 5.7+, I know from experience). Either way, they don't support the OpenBSD audio system for sure.

The other targets that are important to me are Solaris (particularly on UltraSparc) and Haiku. SDL2 supports both, although their raw Surface video backend is pretty bugged on Haiku (the Render backend and OpenGL support has no issues, though). It also has audio on BSDs. But I don't use SDL2 for audio anyway, I usually use OpenAL or OpenBSD's native sndio when on OpenBSD or Linux (which is easily the best audio backend I've found so far).

You're right, though, these are pretty obscure targets. Allegro could probably be made to support FreeBSD with PulseAudio enabled, but the BSD people hate the PulseAudio people and the PulseAudio people hate the BSD people, so I don't suspect that's a good long term plan.

So I finally got Travis to actually use clang to build minisphere (turns out SCons doesn't honor the pre-existing environment, it was simple now that I have a makefile), and said compiler now seems to hate me, mostly because I like to do this:

It's just so succinct and elegant that I got into the habit of doing it everywhere. I can easily shut up the warnings of course, by adding another set of parentheses, but that triggers my OCD and makes the statement look uglier. :-\

I should try adding -Wall -pedantic to that command line and see if I can get clang even angrier at me. :P

Anyway, I think I'm getting close to releasing the first 3.0 beta, but I have to get SSJ to be able to locate source code properly first, and also implement breakpoints. It's kind of useless without those. ;)

I think minisphere on Windows XP is a lost cause. I set up Windows XP x64 edition in a VirtualBox VM yesterday and tried to get minisphere going on it, but failed miserably. I think it might just be that the MSVC 2015 C runtime doesn't like XP - everything was fine until something tried to access the file system. Cell will report that there's no cellscript in the current directory, minisphere errors out if a game is passed on the command line, the "select a game" dialog doesn't show up at all, etc.

So yeah, I'm just going to cross XP off the list of supported platforms. Anyone know if minisphere runs on Vista or should I just say the minimum requirement is Win7 and call it a day?

In any case, I decided not to drop the 32-bit builds after all. There are still quite a few 32-bit Windows installs in the wild, particularly netbooks tend to be preinstalled with a 32-bit OS to counterbalance the low RAM. Since both the 32- and 64-bit binaries are built from the same source, it's not a big deal to maintain two sets of binaries. Speaking of which, starting with minisphere 3.0 the entire toolchain will be built for 64-bit. In minisphere 2.x, Cell was 32-bit even in a 64-bit minisphere installation.

XP is more than 15 years old. If someone is disappointed with Minisphere not supporting it, I would be more disappointed they are still using XP.Literally even Wine is better supported, more compatible, more stable, and more secure at this point.

So I finally got Travis to actually use clang to build minisphere (turns out SCons doesn't honor the pre-existing environment, it was simple now that I have a makefile)

It's easy once you know how, but I agree that SCons should really accept hints from $CC, $CXX, etc. When I started fiddling with Emscripten I had to learn how to accept environment settings, but it really should be the default to do so.

It's just so succinct and elegant that I got into the habit of doing it everywhere. I can easily shut up the warnings of course, by adding another set of parentheses, but that triggers my OCD and makes the statement look uglier. :-\

I sort of understand why they do this. It's because using both equality and assignment has screwy precedence order...

It also is intended to show you that in such cases variable decaration will not be hoisted to the next block. But I wish they would just leave these warnings on conditionals with both assignment and equality.

I suppose the Allegro 5.1 PPA is mandatory for this one, since it gave me "Dependency not satisfiable: liballegro-acodec5.1" in Ubuntu's package manager.

Installed fine after adding that. The minisphere desktop entry also appeared in my Xfce menu. It opened the standard "open file" dialog; can't help but feel that showing the launcher game with sample games would be better though. (Maybe with a simple game that explains/demonstrates what this whole thing is? That could be a future step, I suppose... :P )

It's actually supposed to show the startup game, guess that's a packaging bug. Thanks for testing!

As for Allegro 5.1, minisphere will actually compile against Allegro 5.0 now, at the cost of disabling some features--the ones I know are shaders, error copy-to-clipboard, and vertex buffers (improves Galileo performance). But apparently debuild just sees that Allegro 5.1 is installed and declares that as the dependency. I'll see if I can fix that before release.

By the way if you drop to command line, can you successfully execute cell and ssj? Also check if you have man pages for minisphere, spherun, cell and ssj.

I also noticed that my dev copy of Sir Boingers likes to lock up and crash minisphere when navigating over the High Scores option. And also when in the pause menu for half a second or so. Not sure what's up with that; haven't tested if it only happens with the precompiled version or also when I compile it myself. In any case, I can't even navigate down enough to enable the sound and music...

That second one is a bug in SSJ, it's trying to load the source map which isn't present unless you compile with Cell using the -d switch. It's supposed to gracefully degrade, but apparently something fouled up there. ;)

In minisphere 2.1, compiling with cell -d will generate a debug map which maps the name of a script in the compiled package to its location in the source tree. This aids the debugger (Sphere Studio for 2.1, SSJ for 3.0) in locating the original scripts, even if the Cellscript relocates them.

For Cell 3.0 I'm going to add a new option, --ssj2, which augments the debug info with the full original source code for all scripts. Not only does this allow easy debugging of SPK packages even if the original source tree changes (or is moved), but it will also let you release betas compiled with --ssj2 that others can run through the debugger when errors occur to get meaningful info. :D

After almost 2 months of development, the first beta of minisphere 3.0 is available. Make sure to test drive SSJ and let me know of any issues. It still needs polishing, but should be functional enough to use for actual debugging. :P

I recommend uninstalling previous versions of minisphere before trying the beta as the engine executables were renamed, so the old files may cause conflicts/confusion. Note also that Sphere Studio is no longer included in the download--that will have to be installed separately now for anyone that wants it. The GDK plugin is included, though, and will be picked up by Sphere Studio 1.2.

If you choose to add minisphere to the PATH, the command to run a game on the command-line is:spherun <gamepath>

If you omit the path, it will list available command-line options.

edit: By the way, minisphere is available on Ubuntu 14.04 now, through PPA:

This probably won't work on later versions of Ubuntu, e.g. 15.10 due to Ubuntu's braindead PPA packaging system (you can't upload multiple packages with the same version number, even if they are built for a different Ubuntu version). So I'll be posting .deb packages sometime in the near future.

edit 2: Alright, the .deb packages are now available for direct download for those who can't get it through APT.

This probably won't work on later versions of Ubuntu, e.g. 15.10 due to Ubuntu's braindead PPA packaging system (you can't upload multiple packages with the same version number, even if they are built for a different Ubuntu version)

I suppose this is why they keep appending -1, -2, etc. to the end of the version number... You might want to do that for the 15.10 repo, since that's probably the other Ubuntu version a lot of people (including me :P ) will be running.

Heads up, DaVince: I just realized why I originally made the switch to Allegro 5.1. There are some pretty nasty bugs in 5.0, as I was just reminded by my cousin beta testing it. Notably, sometimes playing sounds will completely lock up the engine, from which the only way out is to kill the process. It's a hard deadlock due to a race condition in Allegro's streaming audio code, nothing minisphere can do to work around it. :(

If worse comes to worst I'll have to statically link Allegro for the final Linux release. This will likely disqualify it from official Debian/Ubuntu packaging, but it'd just be a stopgap measure until a new stable Allegro release comes out.

I hope they release Allegro 5.2 soon... I'm not really up for trying to port the whole thing to SDL right now. :P Although it might be an interesting experiment to do in my spare time, I'd like to try to get 3.0 out the door first. :P

Yeah, I remember those bugs too. Thing is, the engine hasn't crashed where it would before, so I figured things have gotten at least a *little* better with Allegro 5.0 somehow. Still, I can imagine the earliest minisphere would be able to be included in any official repo is Ubuntu 16.04 or so. On Ubuntu and related distros, anyway.

minisphere 3.0b2 for Windows is up, with a vastly improved SSJ debugger. :D I recommend testing it out on real Sphere games - by my guess, minisphere 3.0 Final is getting pretty close so testing would be much appreciated.

Both seems to be working great, for as far as I've tested them! (Only tested SSJ as far as Print/DebugPrint and backtracing a game that crashes on it (an old special Kefka's Revenge winter demo I have yet to upload anywhere).)

The crash happened in "undefined:0", but at least the backtrace ensured it was clear it was in the map engine and exactly what line in the scripts started that map engine with which map. That is really useful. Thanks a ton for making this! :)

Edit: should say, though, if this could somehow report which line/script in the map file is doing that, that would be cool, because... the map it errored out on has like fifty entities.

The crash happened in "undefined:0", but at least the backtrace ensured it was clear it was in the map engine and exactly what line in the scripts started that map engine with which map. That is really useful. Thanks a ton for making this! :)

Edit: should say, though, if this could somehow report which line/script in the map file is doing that, that would be cool, because... the map it errored out on has like fifty entities.

I just realized, if it says "undefined:0" that means the error was thrown by a Sphere API (e.g. Abort()), not directly by the script. That's something I need to fix before the final release: It should automatically select the next stack frame up if the error occurs in an API function (the API is throwing it on behalf of the game anyway). For now if it drops you into "undefined:0" just enter the command "up" to switch to the function that actually caused the error.

And hey, no problem - A symbolic debugger is something I always wished Sphere had and the lack of one always held it back as serious game development tool for me. Finally having it at my disposal is awesome--even more awesome because I wrote it. ;D

I just realized, if it says "undefined:0" that means the error was thrown by a Sphere API (e.g. Abort()), not directly by the script. That's something I need to fix before the final release: It should automatically select the next stack frame up if the error occurs in an API function (the API is throwing it on behalf of the game anyway). For now if it drops you into "undefined:0" just enter the command "up" to switch to the function that actually caused the error.

Dammit, I think I'm going to have to bite the bullet in minisphere 3.0 and allow API functions to accept 0/1 in place of true/false. Quite a few Sphere games seem to do that but minisphere doesn't like it because it's not actually a JS boolean value. I suspect that's the cause of your error.

The reason it doesn't show the map file name is because at the time the script is queued (using QueuePersonScript) only the person name is known. I could probably fix that by tracking which map transient persons are created for.

Hm, on second look it actually looks like error is that the game passed a string for the second argument to SetPersonFrame() which expects a number in that slot. Since this is based on Kekfa's Revenge code I shouldn't really be surprised. :P

Next (pre)release of minisphere I want to add the ability to send source to the debugger directly from the running game so that:

SSJ doesn't need a local matching copy of the source, eventually enabling easy remote debugging. This is unsupported at present because the requirement for local source makes it unwieldy. If the source doesn't match, your line numbers will be off which is very confusing!

Embedded map scripts without a physical script file can still be debugged with source code present. So this way if an error occurs with an NPC script you get to see the line of code that caused it.

SSJ could see the source for system scripts, e.g. miniRT. Right now the debugger doesn't necessarily know where the engine is so it can't easily load them. Handing off source loading duty to minisphere would eliminate the issue entirely (since the engine has to know where all the code is by definition).

My goal is to have minisphere 3.0 go gold on the first anniversary of the minisphere 1.0 release, March 28. So that gives me about a month. Looks like 2016 will be the year of the Sphere debugger! :)

@DaVinceI implemented source download in SSJ (after solving a nasty segfault mentioned in the Programming board that ruined my night...), and using it, proceeded to track down the cause of your KR crashes:

I didn't fix the KR bug if that's what you mean - I mostly just wanted to track down the cause since I wasn't able to do this even with the Sphere Studio debugger. Since the classic map engine is still supported in minisphere, it was kind of dumb that you couldn't see map code in the debugger. Now you can!

I didn't fix the KR bug if that's what you mean - I mostly just wanted to track down the cause since I wasn't able to do this even with the Sphere Studio debugger. Since the classic map engine is still supported in minisphere, it was kind of dumb that you couldn't see map code in the debugger. Now you can!

Ah, okay! That makes a LOT more sense. In any case, this just makes it more powerful!

Just posted another beta, minisphere 3.0b3. SSJ has a brand-new feature: It pulls source code for the game being debugged directly from minisphere. This means you can debug games, even those packaged as SPKs, without having access to the original source tree: So long as the scripts weren't minified or otherwise mangled before being compressed, you can now debug any Sphere game past, present and future.

I also enhanced the output of SSJ's "examine" command to make it more useful this release: It now shows property attributes for all properties and produces a nice listing like Unix ls -l:

That's "ewc" for "Enumerable, Writable, Configurable". The last slot which is clear here is "a" for Accessor (a property with a getter/setter). All properties are listed, even non-enumerable ones. This is in contrast to eval which only lists enumerable properties. If you do examine global be prepared for an absolutely massive listing!

Cell is most likely going to get an overhaul before the official release (March 28), the codebase is not very modular making any changes difficult, and writing a Cellscript isn't particularly intuitive even with the manpage.

SSJ probably won't change any further, I'm very satisfied with how it turned out. :D

minisphere itself hasn't gotten many changes at all, the 2.1 codebase was already quite mature. The only major change I made was to support source code download by the debugger. Other than that it's just minor bug fixes.

Hm, on second thought I think I'll hold off on that Cell overhaul until v3.1. Development time would be better spent improving the Sphere Studio debugger UI, which has kind of fallen behind compared to SSJ's feature set, particularly w.r.t. variable and object inspection.

As the minisphere 3.0 release is only 3 weeks away, I decided to do a code freeze. minisphere 3.0rc1 has been posted, and if no showstopping bugs are found, that build will be officially released as minisphere 3.0.0 on March 28. I took down the links for 2.1.6 to encourage testing the new version. As with all major minisphere releases, the previous one will remain available in the Spherical download repository.

Sphere Studio is no longer bundled: For Windows users, it is highly recommended to download Sphere Studio 1.2.1 as a companion to minisphere 3.0.

To the Spherical regulars:I know you guys don't have much free time, but if some testing could be squeezed in on the RC before the 28th it would be much appreciated. I will keep an eye out for bugs myself in the meantime.

Thanks, NEO. By the way you don't need to build Allegro manually after all: It turns out Allegro 5.1 is available through homebrew, you just have to use the --devel switch:https://github.com/fatcerberus/minisphere/blob/master/INSTALL.md#mac-os-x

Testing it out! It seems VERY stable; hasn't crashed once, even with the deb build that uses allegro 5.0. It's also fast, so far.Now just coding random stuff (see attached file :P) and coming across the following:

I used TypeScript for a bit and it seemed to work fine. Classes worked properly and stuff. :)

LoadSound("it file").play(true) didn't work, but I think I remember this being an Allegro 5.0 specific problem, not a 5.1 one. Similarly, I think music keeps looping even if I tell it not to (there are several tunes in my test game and it's supposed to pick a random new one after finishing one song, but it always sticks to the same one tune it started out with).

surface.filledCircle(), and probably the other circle functions too, only accept integers. It errors out if I give it any radius that is a floating point value. It also doesn't seem to antialias them even when I pass true to the antialias argument.

Is there any way for the screenshot function to take a screenshot at the game's native size rather than the window size? I personally always thought that Sphere screenshotting at the native size was a strength, because it makes for really easy quick screen capping.

Finally... I still haven't played around with any of the new functions yet, other than trying TypeScript for a little bit. This is because this thread is huge and I don't know where I could find a list of the new functions specifically!

You'll have to look through the changelog to see what's new. That should be much more manageable than trying to sift through a nearly 70-page thread! :P Also check minisphere-api.txt, I make it a point to add all new APIs to that file. It's missing some Sphere 1.x stuff mostly related to the map engine, but it's comprehensive otherwise.

Thanks for the testing, especially trying out TypeScript, I didn't expect that. :)

No antialiasing on circles is due to Allegro limitations, it's a known issue that I don't have any fix for at present. Floating point radii causing an error is unexpected though, I'll have to look into that. As for the screenshots: This is implemented by taking a snapshot of the backbuffer. For low resolutions, the backbuffer is actually enlarged and all rendering is run through a transformation matrix. So getting an actual-size screenshots is actually pretty difficult. At one point I tried to have it scale down the screenshots before saving, but that caused loss of quality, so I decided to leave it as-is.

I'll look into the music issues, I think I touched the Audialis code during 3.0 development at some point and may have fouled something up.

LoadSound("it file").play(true) didn't work, but I think I remember this being an Allegro 5.0 specific problem, not a 5.1 one.

This is not a bug, per se, and actually nothing to do with Allegro. It's probably by sheer accident that it even works in Sphere 1.5. What happens is: You're loading a sound, calling .play() on it and then immediately losing your reference to the sound object. The garbage collector then finds it, sees it's unreachable, and finalizes it. I'm guessing the old SpiderMonkey in Sphere 1.5 had a pretty lazy garbage collector and didn't free objects immediately, so that little trick ends up working. Duktape primarily uses reference counting, so the second you lose the last reference, the refcount hits zero and the object is freed.

Working around it is possible: I could probably have the engine temporary bump the refcount of the sound while it's playing so that it doesn't get freed unless it stops (or the engine is closed). That shouldn't be too difficult. Sounds aren't intrinsically linked to the lifetime of the JS Sound object--they have their own independent refcount and everything. That was done to allow assets to be passed around internally without causing segfaults galore when their JS objects go out of scope... those were just loads of fun to debug during early engine development. :P

Actually? Don't fix that. In hindsight, what you said about throwing the reference away, it might actually be good for the engine to fail at accomplishing this so people will be forced to do it the 'right' way instead. :)

There's also a drop-in replacement for Math.random, called RNG.random, along with a bunch of others (search for "RNG" in the API doc). My favorite is RNG.normal - it gives you a random number from a normal distribution with a range of about 6 standard deviations. I use it in Specs to calculate when bosses change phases. I was going to use it for damage calculation too, but then I figured the critical hits from that would be brutally unfair and decided against it. :P

Actually? Don't fix that. In hindsight, what you said about throwing the reference away, it might actually be good for the engine to fail at accomplishing this so people will be forced to do it the 'right' way instead. :)

I fixed it anyway. While it's probably bad to use that for playing looping music (since you can then never stop it), it's useful to be able to throw away references to sound effects and still have them finish--say you have a function that loads and plays a sound then returns: the sound object goes out of scope but you still want it to play through. Without the fix you'd have to keep the reference somewhere globally accessible, which adds extra complexity (and prevents it from being GC'd ever).

...Okay, I don't understand why, but suddenly it IS accepting the value. I don't know what changed that made it work, but, well, if I encounter the specific error message again I'll let you know right away.

Also, thanks for the RNG tip! That seems a lot better. I'll use it right away. Seems to work great! :)

Speaking of the API doc - where does the deb drop this file, anyway? It doesn't seem to be in /usr/share/doc/minisphere/...

Gentlemen. I performed a fresh install of minisphere 3.0rc3 and Sphere Studio 1.2.1, but I get an error when trying to create a new project when it tries to find a directory that doesn't seem to exist "C:\Program Files\minisphere\assets\template"

(http://i.imgur.com/w0XqinQ.png)

Is this due to something I'm doing wrong? Hope it's not wrong of me to post this on this topic.

Thanks for any assistance you can provide. I'll probably continue to fkc around with settings.

That might be a packaging bug on my part. If so, my bad. I'll fix it and post 3.0rc4, but in the meantime you can unzip this file into C:\Program Files\minisphere to hopefully make it work:https://drive.google.com/open?id=0BxPKLRqQOUSNalNkdml5R1YxdXc

Never feel bad about reporting bugs - I'm always willing to fix them and this is the reason it's a release candidate and not the final release yet. :)

@DaVince: I also recommend looking into using the S2GM format if you're going to commit to minisphere - Unlike normal game.sgm you can put arbitrary properties into it and access them using GetGameManifest(). Useful for keeping debug settings and such in a central location. 8)

That might be a packaging bug on my part. If so, my bad. I'll fix it and post 3.0rc4, but in the meantime you can unzip this file into C:\Program Files\minisphere to hopefully make it work:https://drive.google.com/open?id=0BxPKLRqQOUSNalNkdml5R1YxdXc

Never feel bad about reporting bugs - I'm always willing to fix them and this is the reason it's a release candidate and not the final release yet. :)

Created project without it yelling at me, so... so far so good :) Thanks Lord English!!

Edit:Trying to test project to see if it runs (I just left main.js to what it defaults to just to make sure it runs) and I receive the following lovely message in the Build Log:

@DaVince: I also recommend looking into using the S2GM format if you're going to commit to minisphere - Unlike normal game.sgm you can put arbitrary properties into it and access them using GetGameManifest(). Useful for keeping debug settings and such in a central location. 8)

Me using SGM or S2GM is actually just directly related to which editor I use since I just let it do the work. So I'm sure this will change in the future... For now, I'm good. :P

Ah, I guess you're still using the 1.5 editor. I'll take another look at getting Sphere Studio to run on Linux once 3.0.0 is officially out the door. That's really the definitive experience for minisphere development and it sucks that you have to miss out on it!

I uploaded 3.0rc4. It installs the API docs in /usr/share/doc/minisphere now. It turns out I never added those to the makefile because I didn't know the proper place to install them, so thanks for the tip on that. :)

I'm also hoping this is the last RC. Thanks to my OCD I'm up to rc4 already, even Microsoft doesn't put out this many release candidates. (That doesn't excuse you from testing duty mind you! ;) )

I've been using some new functions and object prototypes (new Font, new Color etc) and their methods and properties and it's all been working great so far.

One thing I did notice that's a thing to fix in a new minor version is that when I made a 1280x720 game it stretched in fullscreen without any regard to the aspect ratio on this 1280x1024 monitor. Result is the screenshot. (By the way, what's with the randomized filename for the screenshot? Game-name-timestamp-01.png would seem a lot more intuitive to me...)

The way minisphere's fullscreen scaling works (remember what I said about enlarged backbuffer and transformation matrices above?), it's actually a bit difficult to do letterboxing without ending up with weird artifacts where stuff gets drawn outside the screen, so I got lazy and just stretched it. I do want to fix it eventually, but the 3.0 release is already quite big enough and I'm still busy fixing little bugs I find (SSJ's "help" command crashes in 3.0rc4, for instance), so yeah, that might have to wait till v3.1 or something.

As for the randomized screenshots, that was again due to laziness--I didn't feel like formatting a timestamp at the time so I just used RNG.string(), hehe. I'll fix it before release.

Okay, I can get the aspect ratio thing. That sounds pretty troublesome! (Maybe an easy solution is to force drawing two black rectangles in the appropriate areas? In any case, future feature!)

I've started actually developing a full game now, and it will specifically target and use minisphere functions whenever appropriate. I'm sure I'll be using the debugger too. I probably won't encounter many problems while this RC is happening, but at the very least there'll probably be feedback I can give you at a later stage. :)

Edit: tried creating an s2gm file according to the API documentation, but I'm getting an error when trying to run the game:

You only need the extensions you actually use, the engine will check them on startup to see if they're supported (minisphere-api.txt has the full list). As for API version, that should be 2.0. That refers to Sphere 2.0, not the specific engine. I'll add a note in the documentation clarifying that.

The error message is wrong though (it should be something like unsupported engine), I'll look into that.

I see. Even setting that back to 2.0 makes it return the same error message, though. I'm not sure why. Also, it can't hurt to have the full list of extensions in there, right? I think I'll be using pretty much all of them anyway. (Except for maybe legacy-api, but that depends on what that specific extension includes.)

I'd include legacy-api just to be safe. It's basically a catch-all for any functions directly taken from the Sphere 1.x API that weren't reassigned to a Sphere 2.0 extension, so I don't really have a concrete list of what it covers. :P One thing for future work would be to standardize exactly what constitutes Sphere 2.0 and go from there. Ah well, something for another day.

Okay, that's a documentation bug and is on me. :-[ There are actually several things wrong with the example: JSON requires property names to be quoted, double quotes used throughout, and doesn't allow a trailing comma after the last array entry or property. Here's a properly-formatted file:

That made it work, thanks! :) Man, I didn't know JSON parsing was so much stricter, I thought it was pretty much just a JS object...

On a related note, the deb package associates sgm files with minisphere (at least, I *think* so... if I didn't do this before by myself). But not the s2gm. That opens with a text editor by default, and is recognized as a regular text file (so even associating it with minisphere will make *all* text files associate to minisphere).

That's weird... the debs are built using pbuilder-dist which just runs "make" and "make install" in a chroot and then packages the installed binaries. I didn't add any file association logic to it. Somehow the package manager must know that .sgm files should be associated with minisphere, but I have no idea how. ???

And yeah, JSON is ridiculously strict. I could have just eval'd the manifest but that leaves open the possibility of making malicious (but ultimately harmless of course) S2GMs that enter infinite loops or other such shenanigans. Since it's just metadata, I figured parsing it as pure JSON was better.

That's weird... the debs are built using pbuilder-dist which just runs "make" and "make install" in a chroot and then packages the installed binaries. I didn't add any file association logic to it. Somehow the package manager must know that .sgm files should be associated with minisphere, but I have no idea how.

Never mind me, then -- I might have associated the filetype myself at some point. It works perfectly and is definitely something to add by default if you ask me. :)

By the way, true to form, I decided to tackle the letterboxing issue now. minisphere's window scaling/resizing logic was in need of some refactoring anyway. main.c being the oldest file in the codebase, it's quite a mess of spaghetti code compared to the rest of the engine and could definitely use some cleanup sooner rather than later.

minisphere 3.0rc5 is now available, with fixes for several bugs found in 3.0rc4 by DaVince, and one fairly large change that really shouldn't have been done during code freeze but oh well: I added letterboxing support. Linux deb packages also now automatically associate Sphere file types (.sgm, .s2gm, .spk) with minisphere.

Just posted 3.0rc6, the final release candidate. miniRT has been overhauled and is now provided in module form, loadable using require('miniRT/threads'); etc. Full API documentation for miniRT is finally included as well, so hopefully that'll make the library more discoverable. It's definitely worth looking into if you don't want to reinvent the wheel--it includes a lot of useful stuff like my threading library, a version of Scenario, and a text console with built-in command parser (you just have to provide the command names and implementations!).

This will be the final 3.0 release candidate. I don't see any further changes being needed and the engine has been bug-free in my own use, but if anything else comes up I'll just make the fixes to the final release without doing more RCs. If I don't draw the line here, my perfectionism is going to be the death of me. :P

What's your graphics card? Is it an Intel iGPU? I have this too on my laptop (Core i3-5500U), but it affects all OpenGL games, not just minisphere--I think it's a driver issue with the newer Intel chips. So there's not a lot I can do short of putting Allegro in D3D mode (which disables shaders).

I've been using this version and have not ran into any serious issues. I think I got it to crash once, but I haven't been able to reproduce it... I'll run stress tests later in the week and get back to you.

minisphere 3.0 is finally out! ;D It's worth noting that this is minisphere's birthday - version 1.0, the first version to be almost fully compatible with Sphere 1.x, was released a year ago on this day, March 28. Such a momentous occasion warrants a momentous release, and minisphere 3.0 delivers! New in this release: The SSJ command-line debugger, TypeScript support, a fully documented miniRT, many, many undocumented bug fixes, and official support for Ubuntu Linux!

I decided at the last minute to bundle Sphere Studio in the (Windows) release after all. And a note to users of 3.0rc6: Download 3.0.0. As I suspected would happen, I had to make a few last-minute bug fixes before the release.

Anyway, go download minisphere 3.0.0 and have fun! See the OP for a list of breaking changes.

edit: I forgot to mention, minisphere is also available on Ubuntu via PPA:

https://launchpad.net/~fatcerberus/+archive/ubuntu/minisphere

To install minisphere from PPA, open Terminal and run the following commands:

If you use spherun instead of minisphere it will run windowed by default since that's used for debugging where fullscreen is generally undesirable. This enables the debugger and other development features so there may be a slight performance hit, but it shouldn't be significant. Do note however that spherun is designed for command-line use and therefore requires a game path--it won't run the startup game automatically. What I can do for 3.0.1 is have the engine save the window/fullscreen state from the last run, perhaps per-game (spherun would still default to windowed). That wouldn't be too difficult to do.