handmade.network » Forums » Work-in-Progress » Pixie Game System
mmozeiko
Mārtiņš Možeiko
1693 posts
1 project
#14165 Pixie Game System
4 months, 3 weeks ago Edited by Mārtiņš Možeiko on Jan. 30, 2018, 6:52 p.m.

You can always use Objective-C functionality just from C with <objc/runtime.h> header. Its similar how in Android/Java you can interact with Java objects through jni.h header.

Here's an older but still good example how to write complete app for iOS in just C: https://stackoverflow.com/a/10290255
You pretty much can do same stuff for OpenGL. Here's some example (no idea how well it works) for OpenGL on OSX: https://github.com/jimon/osx_app_in_plain_c
forkingpaths
Martin Fouilleul
45 posts
1 project

Sound Engineer / Programmer

#14166 Pixie Game System
4 months, 3 weeks ago Edited by Martin Fouilleul on Jan. 30, 2018, 7:01 p.m.

Hello !

Regarding your mouse input problem, how do you get the events inside your custom event loop ? Do you use a derived NSWindow with an NSTrackingArea ?

It seems super strange to me that you have different results with XCode and from the command line... Usually either your project builds or it don't but it's strange to have different results. XCode is merely a front-end to clang++ and although apple seems to care about making your life more difficult if you don't want to use it, it is still totally doable. I hate XCode so I build everything from the command line or with make.

Until recently I used XCode as a debugger only, but something broke with the last update and I didn't have time to investigate which project option config has silently changed, so for now i'm back to command line debugging, too (which is less cool).

Martin
wilberton
Andy Gill
18 posts
#14167 Pixie Game System
4 months, 3 weeks ago

Thanks for those links. Calling the objective c functions using objc_msgSend is fine (if a little verbose) - it's more the fact that you can't include the Cocoa headers that's the trouble. Duplicating the enums and structs from the headers just seems wrong to me, even if the likely-hood of them changing is low. I'm sure it's technically possible to do it all from C, I just don't know if the resulting ugliness/maintainability of the code is worth it.

As for the mouse input, I derive from NSWindow and set acceptsMouseMoveEvents to true - so no NSTrackingArea. This works fine building from XCode. There are other things that function differently when I compile from the command line, I'm hoping they're all related to one underlying cause but I don't know for sure yet. For example, when you start the application it doesn't have focus, and the main menu doesn't appear. The list of arguments that XCode passes to clang is pretty long, but I just need to go through them one by one and see if I can figure out what's causing the command line version to be different.
Mattias Gustavsson
@Mattias_G
36 posts

Amateur (ex-pro) game dev, making retro styled games and small public domain C/C++ libs.

#14168 Pixie Game System
4 months, 3 weeks ago

Yeah, it was definitely ugly, and involved inlining some definitions, but it is totally worth it to get something which builds cleanly. Having to add an extra app.m file totally breaks the whole "single header so no build system hassle" thing for me, so I'd much rather deal with a bit of duplicate definitions and occasional maintenance :) Here's the test code I was messing about with, not sure which article/sample/blog post I got the info from: https://pastebin.com/WAbPR1YK and as I said, it is barely a start.
It does build by doing: clang main.c -o./test -framework AppKit
wilberton
Andy Gill
18 posts
#14169 Pixie Game System
4 months, 3 weeks ago

Ok, that's pretty similar to what I had (except the dynamic loading OpenGL - that's nice!)

I agree a single header is nicest, now I have something mostly working I can look at migrating the Objective C functions over to use objc_sendMsg instead one by one, if you're happy with that style.

I got to the bottom of the command line compiling differences. It seems to be something to do with packaging it as a mac app. At first I thought it needed the Info.plist file, but it turns out that's not necessary, all it requires is the right directory structure.

1
2
3
4
5
6
>clang main.c -o myexe 
>./myexe  // doesn't work correctly
>mkdir Contents
>mkdir Contents/MacOS
>mv myexe Contents/MacOS/
>./Contents/MacOS/myexe  // runs correctly!


If you rename either the Contents or MacOS directories, it won't run properly. To be a proper bundle it should have 3rd parent directory called something like AppName.app, but that doesn't seem necessary to make it run at least.
Obviously Xcode does all this for you, but it makes compiling from the command line somewhat confusing as I've never experienced parent directory names influencing how an executable functions before!
forkingpaths
Martin Fouilleul
45 posts
1 project

Sound Engineer / Programmer

#14171 Pixie Game System
4 months, 3 weeks ago

Hello !

how do you build you railtracker example ? On my machine it seems that somehow clang doesn't want to include time.h so I get :

1
2
3
4
5
6
7
./app.h:3421:5: warning: implicit declaration of function 'clock_gettime' is invalid in C99
      [-Wimplicit-function-declaration]
    clock_gettime(CLOCK_MONOTONIC, &ts);
    ^
./app.h:3421:19: error: use of undeclared identifier 'CLOCK_MONOTONIC'
    clock_gettime(CLOCK_MONOTONIC, &ts);
                              ^


And I get a bunch of error from app.m because the NSWindowStyleMask and NSEventMask constants seems to be unrecognized.

I try to build the app to see if the command line version works on my machine. Making an app bundle should only be necessary if you want to double click on the app to run it and be able to reference resources from within the app, using bundle-relative paths.



Martin
wilberton
Andy Gill
18 posts
#14172 Pixie Game System
4 months, 3 weeks ago

What version of MacOS/XCode do you have? I think clock_gettime only got added in 10.12.
When I was using sample code I got warnings about the enum values beings deprecated for a bunch of things, so I think they must have renamed a whole load recently.
mmozeiko
Mārtiņš Možeiko
1693 posts
1 project
#14173 Pixie Game System
4 months, 3 weeks ago

Typically on macOS you want to use mach_absolute_time and mach_timebase_info functions instead of clock_gettime.
wilberton
Andy Gill
18 posts
#14174 Pixie Game System
4 months, 3 weeks ago

Fair enough, I've switched that over.

I've started converting everything to plain C, it's actually less nasty than I feared. The CoreGraphics header can be included so at least we don't need to redefine things like CGRect.
Hopefully it shouldn't be too much more work and then it'll all be in a single header again.
wilberton
Andy Gill
18 posts
#14183 Pixie Game System
4 months, 3 weeks ago

Ok, it's all back in one header.

I've also removed clock_gettime, and the NSEventMask constants are all redefined in the header, so it should build cleanly now, even on older os versions.

For some reason, this also fixes some of the weirdness when compiling from the command line. Everything works fine now, except the main menu doesn't open. Again, that works correctly if you place the exe in a folder called Contents/MacOS/

There's still some missing functions vs the windows build, and resizing the window on the fly doesn't work properly yet, but it's not a bad start.

If anyone wants to take a look I've checked my copy in here: https://github.com/wilberton/RailTracker
Mattias Gustavsson
@Mattias_G
36 posts

Amateur (ex-pro) game dev, making retro styled games and small public domain C/C++ libs.

#14197 Pixie Game System
4 months, 3 weeks ago

That is looking very good now :) I definitely want to merge that in to my version. I'll probably add dynamic loading for OpenGL though, and I have changed a couple of API calls from the version you based yours on, but I can fix that up. Great work! The missing functions can be added over time, I'm sure.
wilberton
Andy Gill
18 posts
#14200 Pixie Game System
4 months, 2 weeks ago

Cool, if you want me to make any changes let me know. I've just fixed window resizing so it properly centres the view again.
There are a few other things that could probably be tidied up - for example the functions for converting window coordinates are almost identical to the Windows versions, so they could usefully be refactored to avoid duplicating that code.

Incidentally I just did a little investigation into how hard an iOS version would be, but unfortunately I hit a snag pretty much straight away. iOS doesn't let you control the event loop, you just get callbacks when it's time to render, or when events occur. Without completely changing the interface to similarly abstract the game loop away into separate callbacks (init, frame_update, quit_requested etc), I don't see an easy way to fit the current api onto iOS.
It would be so cool to have a single header that could compile across all major platforms, so it might be worth considering. Any thoughts?
forkingpaths
Martin Fouilleul
45 posts
1 project

Sound Engineer / Programmer

#14201 Pixie Game System
4 months, 2 weeks ago

If you want to preserve the same interface, maybe your ios callbacks could fill a queue with events, and you can still have a main loop that polls this queue instead of directly polling iOS ?

Martin
wilberton
Andy Gill
18 posts
#14202 Pixie Game System
4 months, 2 weeks ago

Yes, the events can still be buffered, that's fine. The problem is the actual game loop. At the moment the code looks something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
main()
{
  init();
  while(running) {
    handle_events();
    frame_update();
    swap_buffers();
  }
  shutdown();
}


whereas on iOS your main function always looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
main()
{
   return UIApplicationMain(myDelegate);
}

// in my delegate
void app_started()
{
 // do init stuff here
}

void render()
{
 // automatically called at 60hz, or whatever your target frame rate is
}

void app_moving_to_background()
{
  // etc
}


So there's literally nowhere to put a while(running) type of loop. Because at the moment that while loop is in the client code, not the app.h library, we can't hide that difference on iOS. The simplest interface I can think of to handle this would be to make everything into an event, and replace the current app_proc callback (which currently houses the main loop) with a single event handler:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
app_handle_event(Event* event)
{
  switch(event->type)
  {
    case EventType_AppStarted:
      // do init here
    case EventType_FrameUpdate:
      // do main frame update here.
      // input could still be buffered and retrieved here, or it could come in as events too
    case EventType_AudioSamplesRequired:
      // fill audio buffer
    case EventType_AppClosing:
      // do shutdown here
    // etc etc
  }
}


However, that's a pretty big api change from how it is now, so maybe it's not worth it.
I always wondered why glfw don't have an iOS port, and perhaps this is part of the reason - their current api simply can't be implemented on iOS.
Mattias Gustavsson
@Mattias_G
36 posts

Amateur (ex-pro) game dev, making retro styled games and small public domain C/C++ libs.

#14204 Pixie Game System
4 months, 2 weeks ago

I think it is possible to make an iOS version without changing the interface, but with one caveat - the call to app_run will not return.

The way to do it would be by letting app_run start the iOS app normally, same as the standard main would, and then spin up a second thread which calls app_proc. Since the app_proc main loop will have to call "app_yield" once per iteration, app_yield can wait until the main thread flags an event. So in the main thread event loop, we can wait for the second thread to call app_yield, and in app_yield we can wait for the event loop to be executed, thereby keeping them both in sync, and giving the app_proc the illusion of controlling its own game loop.

I think maybe this explanation was not the best - let me know if something is unclear :p

Btw, the version with the updates is here: https://github.com/mattiasgustavsson/libs/blob/master/app.h (but I haven't worked your macos changes into it yet, will try to do that next week).