BlitzMax on iOS

BlitzMax Forums/Brucey's Modules/BlitzMax on iOS

Brucey(Posted 2015) [#1]
Hot-on-the-heels of getting DX9 working in bmx-ng, I thought I'd have a bash at iOS.

Getting code to compile correctly turned out to be the easier part of the mission.

As far as can see there are three possible targets for iOS : armv7, arm64 and x86 (simulator).
Apparently armv7 will work on all devices since the iPhone4...
But for now I've been concentrating on the simulator, as it doesn't require me to pay for a dev license to test it.

Dynamically building the xcode project has been a trickier part to get right, involving a bit of trial and error and looking at other's project files for inspiration. We're pretty much there now though, and it is happily populating things in the right place.
There are lots of possibilities for customisation though, which can be looked into at a later date (like folders of stuff you want auto-packaged into the bundle, etc)

The biggest hurdle so far has been SDL.GL2SDLMax2D, which has refused to render *any* graphics whatsoever, and since there's so much going on in there, it's hard to work out where it actually isn't working. :-(

However, I knocked together a small test program which renders a coloured rectangle on the screen, and it is working as expected ! :-)
Which proves that, in theory at least, iOS is definitely a viable target.

SDL.GL2SDLMax2D is already known to work on the Pi and Android so it's a bit of a puzzle why it's not rendering anything on iOS...

If anyone has any wild or crazy ideas, I'm more than happy to listen to them.


FabriceW(Posted 2015) [#2]
Since XCode 7 beta you no longer need an apple dev membership to test on the device. http://bouk.co/blog/sideload-iphone/


Brucey(Posted 2015) [#3]
Interesting! Thanks ;-)


Brucey(Posted 2015) [#4]
It's all a bit like some mysterious magic stuff... when everything just seems to work...

(running on iOS simulator, *with sound*!)

One has to be somewhat impressed with Skid's freeaudio module, which so far has played on every platform without issue. Go Skid! :-D


LT(Posted 2015) [#5]
That's pretty awesome...


MikeHart(Posted 2015) [#6]
Wow!


Cocopino(Posted 2015) [#7]
Magical indeed :)
But I guess user input will be a lot more difficult than just getting MouseHit(), MouseX() etc?


Brucey(Posted 2015) [#8]
But I guess user input will be a lot more difficult than just getting MouseHit(), MouseX() etc?

Depends if you want to support multi-touch or not? Otherwise, MouseX() and co reflect the "first" touch input.

For the breakout sample, when your finger touches the screen and move the bat across it, you are effectively holding down the mouse button while you move - think, click-and-drag.

So yes, you may need to adapt your mouse input stuff, but it's not so hard. You can catch the initial "down" when the user touches the screen and do something then if you like. Unlike moving your mouse cursor around the screen, the cursor will appear to "jump" around from place to place as the user touches different parts of the screen.

I added some new events for BlitzMax to help with multi-touch stuff (on top of the mouse handling which already works) :
Const EVENT_TOUCHMASK=$40000
Const EVENT_TOUCHDOWN=$40001
Const EVENT_TOUCHUP=$40002
Const EVENT_TOUCHMOVE=$40003

Rather than a button number in the event you will get a touch id, which you can use to track multiple fingers at the same time.


Cocopino(Posted 2015) [#9]
I can only synopsize some of the earlier comments:
Wow, that's pretty awesome!


xlsior(Posted 2015) [#10]
Very interesting!


Panno(Posted 2015) [#11]
Great !


Brucey(Posted 2015) [#12]
Thanks to the generosity of some members of the community, I can now work directly with iOS hardware, rather than just the simulator... (donations generally go directly towards improving the tools and environment I have at my disposal for creating all this stuff I churn out. ;-)



Nice to see my virtual joystick stuff actually seems to work! :-D

SuperStrict

Framework sdl.gl2sdlmax2d

Import sdl.virtualjoystick


Local joy:TRenderedJoystick = TRenderedJoystick(New TRenderedJoystick.Create("VJ", 100, 680, 50, 20))
joy.AddButton(900, 680, 30)
joy.AddButton(970, 620, 30)


Graphics 1024, 768, 0

SetBlend alphablend

SetClsColor 255, 255, 255
SetColor 0, 0, 0

While Not KeyDown(key_escape)

	Cls
	
	' draw joystick
	joy.Render()
	
	' get some stats
	SetColor 0, 0, 0
	
	Local x:Float = JoyX()
	DrawText "JoyX : " + x, 100, 300
	DrawLine 150, 330, 150, 360, False
	DrawRect 150, 330, x * 50, 30
	
	Local y:Float = JoyY()
	DrawText "JoyY : " + y, 300, 300
	DrawLine 260, 310, 290, 310, False
	DrawRect 260, 310, 30, y * 50
	
	If JoyDown(0) Then
		DrawText "Button 0 : DOWN", 100, 380
	Else
		DrawText "Button 0 : UP", 100, 380
	End If

	If JoyDown(1) Then
		DrawText "Button 1 : DOWN", 100, 400
	Else
		DrawText "Button 1 : UP", 100, 400
	End If

	Flip
Wend


Type TRenderedJoystick Extends TVirtualJoystick

	Method Render()
		If touchId <> -1 Then
			SetColor 200, 200, 100
		Else
			SetColor 100, 200, 100
		End If
		DrawOval centerX - radius, centerY - radius, radius * 2, radius * 2
		
		SetColor 100, 100, 200
		DrawOval xPos - knobRadius, yPos - knobRadius, knobRadius * 2, knobRadius * 2
		
		For Local i:Int = 0 Until buttons.length
			Local button:TVirtualButton = buttons[i]
			If JoyDown(i) Then
				SetColor 255, 100, 100
			Else
				SetColor 100, 100, 100 + i * 50
			End If
			DrawOval button.centerX - button.radius, button.centerY - button.radius, button.radius * 2, button.radius * 2 
		Next
	End Method

End Type



degac(Posted 2015) [#13]
Brucey, I must admit I feel 'joy'seeing the simple&dear&old BlitzMax syntax of the source code and the result running on an 'alien' device like iOS.
In MX this feeling is still missing...


markcw(Posted 2015) [#14]
Is the iOS simulator available on Mac?

Nice video demo - I thought it was better with no sound though - sort of distracting.

I didn't know you could do "Typename( New Typename.Create(arg) )". How is that better than a Create function?

Anyway great progress! It's all looking very cool.


Brucey(Posted 2015) [#15]
Is the iOS simulator available on Mac?

Yes. I was developing against that until recently (x86/x64 targets).
However, building for the devices themselves raised different issues that I was unaware of until now.

How is that better than a Create function?

This way I am creating an instance of my subclass and initialising it. The Create method itself is part of the superclass.
A create function would define a particular Type to create an instance of. This way, I am free to subclass and instantiate as I please, which is much more flexible.
Of course, you could also do the following if you aren't using any subclass-specific functionality :
Local joy:TVirtualJoystick = New TRenderedJoystick.Create("VJ", 100, 680, 50, 20)



Brucey(Posted 2015) [#16]
Anyhoo, here's Digesteroids running on the iPad Mini with the virtual joystick for input ...



As you can probably see, there's some potential for getting BlitzMax games on iOS ;-)


Hotshot2005(Posted 2015) [#17]
Very Nice and keep good work up :-)


LT(Posted 2015) [#18]
Awesome! What's next? BMax on XBone and PS4!? :D


degac(Posted 2015) [#19]
@brucey: it's doable a patron page(or like) for supporting BMX.NG or there could be a potential conflict with BRL?


*(Posted 2015) [#20]
TBH I cant see a patron page conflicting with BRL as its not their code its Bruceys, also Mark has abandoned this forum ages ago so I dont see it as a issue anymore.


Hotshot2005(Posted 2015) [#21]
Why not have doable a patron page for Brucey

Win to win situation for Brucey :-)


Brucey(Posted 2015) [#22]
What's next? BMax on XBone and PS4!?

Of those, more likely PS4, but unlikely just the same (although PS4 is running on top of BSD which isn't too far away from Linux) :-p

I will probably add support for nacl (Chrome OS/Chrome browser) at some point since SDL already supports it.

iOS is coming along. Did some work on lib and framework importing today, which made BASS useable, so I made a little app streaming internet radio on the iPad.

Very cool how you can build and run your app for desktop, then re-compile for iOS and it *just works* :-)
It's something I've always enjoyed with BlitzMax - the ability to switch platform and see your app running the same. And is more-or-less what I demand of NG - that you shouldn't need to change much (platform specific caveats aside), if anything, to run your stuff on the "new" platforms.


LT(Posted 2015) [#23]
I was (mostly) kidding, but I'm surprised PS4 is more likely.

Out of curiosity, is it possible to make a stand-alone NG compiler? One that requires no other installs (MinGW, SDL, etc.)?


xlsior(Posted 2015) [#24]
Out of curiosity, is it possible to make a stand-alone NG compiler? One that requires no other installs (MinGW, SDL, etc.)?


MinGW is only necessary to (re)compile modules, so if you have a compiled version of the mods and don't intent to add any others then you shouldn't need MinGW I'd think.


Brucey(Posted 2015) [#25]
I'm surprised PS4 is more likely.

PS4 builds with Clang/LLVM, as does Apple's OSX and iOS.


is it possible to make a stand-alone NG compiler? One that requires no other installs (MinGW, SDL, etc.)?

Yes, one could probably drop a copy of MinGW into BlitzMax/MinGW32, and add some of the other modules to it for some kind of basic Windows distribution.


LT(Posted 2015) [#26]
one could probably drop a copy of MinGW into BlitzMax/MinGW32
Ah, cool. Wasn't sure if that was a legal distribution method. What about other platforms? Would that be Clang/LLVM instead?


Brucey(Posted 2015) [#27]
Wasn't sure if that was a legal distribution method.

BlitzMax already ships with MinGW components.

What about other platforms? Would that be Clang/LLVM instead?

No. Unless you go to the trouble of creating your own custom distro of clang/gcc then it's easier just to use the compiler tools available on the system (XCode on Mac, GCC (or perhaps clang/llvm) on Linux.


LT(Posted 2015) [#28]
BlitzMax already ships with MinGW components
Oh? I couldn't see anything obvious (no MinGW directory), but I'll take your word for it.

How difficult would it be to add true first class functions to Blitz?


Brucey(Posted 2015) [#29]
How difficult would it be to add true first class functions to Blitz?

I've no idea. Ask Yasha :-)


LT(Posted 2015) [#30]
I've no idea. Ask Yasha
Bah!


Brucey(Posted 2015) [#31]
It's all rather exciting as the various parts come together :-)

Wake/sleep handling is now working.
The on-screen keyboard interacts well with BlitzMax's key stuff.
Fixed some 64-bit lua issues over the weekend, so it's running well now on iOS - I've been using Derron's TVTower game (https://github.com/GWRon/TVTower) as a testbed since it's huge, complex, has lua support, etc. The code only requires a couple of minor tweaks to run on iOS (graphics driver, logging), but it's now running very stable. Of course, the UI/interaction will need some work to be more touch friendly, but that is to be expected really. I was surprised it runs at a solid 60fps, considering how inefficient Max2D generally is.

One really nice thing XCode gives you is a fantastic depth of profiling information. You can snapshot the app any time and it will flood you with warnings (and detailed explanations) about the code, highlighting the lines of code, and ways you might want to change it to make it better...


LT(Posted 2015) [#32]
Well, this IS interesting. I'm hoping that this will make porting my game engine to the major platforms...less painful, anyway. All along, I've assumed that I'd have to translate everything to C or C++, but I would love to be wrong about that!

I'm using LuaJIT for scripting and have recently learned how to get better performance - Yasha's right when he sings its praises. So I'd have to get Zeke's module working. Is there a page somewhere that has a list of things to watch out for (for those of us used to standard BMX)? Did I read something earlier about Byte Ptr not working with 64-bit? I use them often...


Brucey(Posted 2015) [#33]
(a modified) LuaJIT appears to work fine in 64-bit BlitzMax.

I'll add it to the bmx-ng repo at some point.


LT(Posted 2015) [#34]
(a modified) LuaJIT appears to work fine
Modified in what way?


Brucey(Posted 2015) [#35]
I meant the module, rather than luajit itself :-)


LT(Posted 2015) [#36]
I know, that was what I meant. What has to change in standard BMX code in order to use it with NG?


Brucey(Posted 2015) [#37]
Oh :-)

Anything that refers to size_t in the API should be Long for 64-bit platforms. Also, externed Types should be wrapped instead.

Otherwise, it should work as normal.


Lugi, on the otherhand, would probably require a major rewrite - as it accesses BlitzMax Objects at a very low level, and I've rewritten the object internals for NG to use a different GC.
(A modified) MaxLua does work though (see paragraph 2 above) :-)


LT(Posted 2015) [#38]
Hmm, okay. I am not using Lugi, but I am using BBObject and the like for exposing objects. I suppose I'd have to know how the new GC works.

My current garbage collection function for exposed Lua userdata:
int __gc_object( lua_State *state ) {
    BBObject **obj = (BBObject**)lua_touserdata( state, 1 );
    BBRELEASE(*obj);
    *obj = NULL;
    return 0;
}

I've minimized the C code required and there are no instances of size_t (and no externed types), but I am using int - am I right to assume that doesn't matter?


Brucey(Posted 2015) [#39]
There's no need for your Null set there, unless you are specifically checking for it somewhere else?

Ints are fine, as long as you aren't using them for pointers.

For specific 64-bit changes, look for ?ptr64 here : https://github.com/bmx-ng/zeke.mod


LT(Posted 2015) [#40]
unless you are specifically checking for it somewhere else?
BBRELEASE works for BlitzMax GC, but Lua's GC also needs to release it. It's a metatable function.

Thanks for the link; I'll definitely want to look into this stuff soon. Just wish I had all the hardware for testing...


Brucey(Posted 2015) [#41]
Lua's GC also needs to release it.

I thought that was why this function would be called? - because Lua was GC'ing anyway.


LT(Posted 2015) [#42]
Perhaps you're right; don't think it's hurting anything, either. I've put a comment by it to check into when I run through gc testing again. :)


LT(Posted 2015) [#43]
Should the modified LuaJIT be working with original BlitzMax? Since the link you posted had a later version of LuaJIT (and one that might actually solve an issue I'm having), I decided to give it a try. The module built just fine, but when I tried to make an executable, I got some undefined references.

C:/BlitzMax/mod/zeke.mod/luajit.mod/lib/win32/libluajit_x86.a(lib_os.o):lib_os.c:(.text+0x10e): undefined reference to `_difftime32'
C:/BlitzMax/mod/zeke.mod/luajit.mod/lib/win32/libluajit_x86.a(lib_os.o):lib_os.c:(.text+0x548): undefined reference to `_time32'
C:/BlitzMax/mod/zeke.mod/luajit.mod/lib/win32/libluajit_x86.a(lib_os.o):lib_os.c:(.text+0x600): undefined reference to `_localtime32'
C:/BlitzMax/mod/zeke.mod/luajit.mod/lib/win32/libluajit_x86.a(lib_os.o):lib_os.c:(.text+0x8ab): undefined reference to `_gmtime32'
C:/BlitzMax/mod/zeke.mod/luajit.mod/lib/win32/libluajit_x86.a(lib_os.o):lib_os.c:(.text+0x8e8): undefined reference to `_time32'

What should I do about this? I'm using TDM 4.7 - could that be the problem?

EDIT: Tried updating TDM to 5.1 and still not working.

EDIT2: I'm guessing that the .a just needs to be recompiled.


Brucey(Posted 2015) [#44]
It's built with TDM 5.1 64-bit.

Yes, a recompile with a different version would probably sort it.


LT(Posted 2015) [#45]
Well, I guess I don't know how to do that. Thought "gcc -o Makefile luajit.c" from the terminal would do it... :(

EDIT: "mingw32-make", by itself, generates a .dll and .exe, but no static libs. Keep finding sources that say it should be spitting out .a libs. :/


Brucey(Posted 2015) [#46]
Just edit the makefile.

Look for the line :
BUILDMODE= mixed

And change it to static.

Or comment out that line and uncomment the following one...


LT(Posted 2015) [#47]
Hmm, guess I read that wrong. I thought "mixed" meant it would create both. I did as you suggested and got another error message related to making the exe...however...it DID build the static lib.

Unfortunately, the undefined references from above are still there. :(


Brucey(Posted 2015) [#48]
As far as I am aware, if you build everything with the 32-bit TDM, you shouldn't have an issue as it won't suffix those functions with 32.


LT(Posted 2015) [#49]
EDIT: Wtf moment...rescinded!

EDIT 2: Compiling problem resolved, but I think I'm getting too old for this...

EDIT 3: Finding lots of instances of size_t in luajit.mod - what has been "modified?"


Brucey(Posted 2015) [#50]
what has been "modified?"

See post #39 above.


LT(Posted 2015) [#51]
I did see that post, but it was unclear to me what you meant. I thought there were changes in the luajit C source.

Anyhoo, the luajit ffi stuff is not 100% working and now I'm trying to track down why...


Brucey(Posted 2015) [#52]
Nah, there are no changes to the library itself.

The examples were working fine, so I assumed it was okay.


LT(Posted 2015) [#53]
I've learned somewhat recently that FFI (not used in the examples, I think) allows you to directly call C functions and they get inlined with the JIT. It's very fast and better, in theory, than using the C API. In the process of switching over, I ran into an issue that I thought updating to the most recent version of LuaJIT (I was still using 2.0.1) would fix - but the issue is still there. I have to assume I'm still doing something wrong...

EDIT: Think I've just confirmed the ffi part is not fully functional, but I'll post an update tomorrow.


LT(Posted 2015) [#54]
Okay, I'm almost sure that ffi in the module is not working - at least not for cdata and ctype. LuaJIT allows you to create cdata objects and work with them directly and attach metamethods to them, just like userdata. Unfortunately, I've discovered that the ctypes are not recognized and that means the __index and __newindex metamethods are not getting called properly.

Just in case you're curious, here's an example Lua script...
local ffi = require( "ffi" )

ffi.cdef[[
struct foo { int a, b; };
]]

local tt = ffi.new( "foo", 5, 8 )

print( " ----- " )
print( tt.a )
print( type( tt ) )
print( ffi.typeof( tt ) )
print( " ----- " )
I am expecting the result to be...

> -----
> 5
> cdata
> foo <-- or maybe "struct foo"
> -----

Instead, the lines above and below "cdata" are blank.

Sorry for diverging from the thread topic. The truth is that JIT is turned off on iOS (and consoles). It may not be the best option for all platforms, but I'm not aware of a better one. It's too bad because except for these caveats, LuaJIT is pretty awesome.


Brucey(Posted 2015) [#55]
What happens when you declare your struct like this? :
typedef struct { int a, b; } foo;



LT(Posted 2015) [#56]
Same thing... I've tried many combinations and have been following working examples from the LuaJIT forums.

I don't know how the mod could be responsible for this - I don't see any connection. This is a simple example, of course. What I was trying to do was use BBArray directly and was pleasantly surprised when the __len meta method worked. Then, of course, I was deflated when the __index meta method did not. :/

The type is not getting recognized, so that explains it, but it would be nice to find a solution.


Brucey(Posted 2015) [#57]
Oh, that's interesting. When I tried it with the above def I got this on OS X :
 ----- 
5
cdata
ctype<struct 95>
 ----- 


... and the same result on Windows 7.


LT(Posted 2015) [#58]
Ugh. Okay, I'll look elsewhere... Thanks for looking into it, though.

EDIT: I'm embarrassed to say this was just my replacement "print" function. Not related to my original problem at all.


Brucey(Posted 2015) [#59]
So your problem is this?
What I was trying to do was use BBArray directly...


In case you hadn't noticed, the BBArray struct does not actually define the whole of the contents of your array. 'scales' is a variable size, and the data comes somewhere after that.

Unfortunately, I don't understand much of the innards of lua (like what are all these double-underscore variables), to be of too much help.


LT(Posted 2015) [#60]
That's okay. I appreciate what you have done and just by testing it (and exposing my blunder), you steered me away from spending too much time looking in the wrong place.

So your problem is this?
Sort of. There's a bit more to it.

--

All of this is already working using the C API and userdata, but I wanted best possible performance and that's where ffi came in. However, ffi is incompatible with the stack and you need the stack to make userdata. Another option is just to push every single object as userdata, but I'd prefer to avoid that.

Certain objects (table, userdata, and cdata) can have metatables/methods attached to them with double-underscore-prefixed keys that are accessors.
x = foo.bar ..... triggers __index, if it exists
foo.bar = x ..... triggers __newindex, ..
#a .............. triggers __len, ..
a + b ........... triggers __add, ..
etc.
The BBArray was another test case. This works right now, with the correct typedefs in ffi.cdef...
local arrayMT = {
  __len = function( self )
    return self.scales[0]
  end
}

local arrayType = ffi.metatype( "BBArray", arrayMT )

The __index metamethod wasn't triggering properly, but I have made some steps in the right direction and am no longer convinced the mod is the issue.


LT(Posted 2015) [#61]
Got it sorted now, thanks for your help (and sorry for the noise)!


byo(Posted 2015) [#62]
Wow, simply amazing!


Grisu(Posted 2015) [#63]
Brucey, you rock!