PhysicsFS/PhysFS++ Tutorial

This is a follow-up from a promise that I made in my tutorial video on designing an asset manager using SFML. That video can be found here.

This tutorial is centred around PhysFS++, a C++ wrapper for PhysicsFS. For the sake of the tutorial, it’s assumed that the reader is familiar with PhysicsFS and what it’s capable of. Described here is a workflow for simple use of the library. Anything more discrete is beyond the scope and will have to be ascertained by the reader on their own accord.

Lastly of note, PhysFS++ encapsulates PhysicsFS calls in a PhysFS namespace. The functions are global within this namespace and there are only a few classes that are provided. PhysFS++ further encapsulates key PhysicsFS constructs, notably those corresponding to archived files, into said classes that are derivatives of STL stream classes (a huge boon).

Like some other libraries, PhysicsFS requires explicit initialisation before it can be used. This is facilitated by a function named init. It takes one argument of type const char* and is semantically directed at a terminal invocation argument triaged through the much loved argv. However, this can be an empty string especially if you’re not expecting to handle terminal invocations. Thus, a very general call to init can be performed as such:

PhysFS::init (nullptr);

Right of the bat we have to mention a caveat here. From PhysFS++, there’s no way to assert the initialisation process of PhysicsFS. This is counter-intuitive to the upstream library which relies on the tried-and-true zero on failure, non-zero on success return values as sanity checks. Furthermore, while PhysFS++ implements C++ exceptions, the init function doesn’t throw any at all. Ostensibly, what one is left with is an unchecked call to init. Because one needs to compile PhysFS++ from the source, it is possible to modify the code, as I have done, to add a check to this call.

Once init has successfully completed, the next step is to mount an archive file into the virtual filesystem created by init. This is performed with the mount function. mount expects three arguments: the archive file on disk, a string specifying a mount point in the virtual filesystem, and a boolean which appends the mount point to the search path. One should place the archive file in the working directory for the binary file of their executable so PhysFS++ can see it. The second argument can be an empty string which would force root mounting, and the third can be true. Thus, for our example, if we assume we have an archive file named funphotos.zip on our disk in the binary’s working directory, we can issue a call to mount as such:

PhysFS::mount (“funphotos.zip”, “”, 1);

Unfortunately, as was the case with init, mount wraps an upstream function that adheres to the zero-or-nonzero return value paradigm that is outright dropped by PhysFS++ with no exception catering otherwise. Thus, if mount fails to mount the archive for whatever reason, it’ll be a little difficult to ascertain why; plan accordingly.

Assuming mount has returned properly, one can start to work with the files that are contained in the archive. At this point, you should begin working in the mentality of filesystem calls. It’s possible to have archive files with complex directory layouts which would require one to perform recursive searches. That being said, everything should be considered a file – even a directory. An analysis of the PhysicsFS and PhysFS++ APIs will provide for you the full breadth of your available capabilities so for the sake of brevity, only a select number of those will be touched here.

Enumeration of files in a directory can be performed with the enumerateFiles function. It takes as an argument a string which indicates the directory to use as a root for the enumeration. As a return it provides the caller with a vector of strings indicating the name of the file. For ease of use, a call to this to enumerate the files in root can be performed as such:

auto rootfiles = PhysFs::enumerateFiles (“/”);

To actually work with a file in the filesystem, one needs to use the PHYSFS_file ADT. This upstream ADT is encapsulated by one of three classes: PhysFS::ifstream, PhysFS::ostream, or PhysFS::fstream. Each of these is fantastic in that they encapsulate a PHYSFS_file ADT in a standard stream which means that one can now perform established stream operations on the file itself. Each class has its own use: fstream for reading files, ostream for writing to files, and ifstream for bidirectional file handling. In any case, any of these classes can be instantiated with a string argument that contains a fully qualified pathname to a file in the virtual filesystem that one wants to work with. For example, given that our virtual filesystem has a file named goofycats.png located at the path /textures/cats, we could instantiate a read file as such:

PhysFS::fstream gc (“/textures/cats/goofycats.png”);

Again, the underlying upstream call to open the file goes unchecked.

What you do from here is largely subjective relative to your program’s context. Say, for example (and this is actually pretty specific to my own use case), that you have a series of files of various formats in an archive that are being used in a video game program. The multimedia library you’re using should have ADTs that represent types of assets such as textures, fonts, etc. One could do some work to transpose the raw data of these streams into the aforementioned ADTs for use in the multimedia library. The following snippet of code, borrowed from one of my own projects, illustrates this. A PhysFS::fstream instance named f is created with a certain file. Following up is a char array named d is instantiated with the size of f. The read function of f is called to transpose the bytes from f into d. Then, d is used to instantiate an instance of sf::Music from SFML contained in a std::unordered_map:

code

This covers most the basic and general needs of users of PhysicsFS. Should you require anything else from it, you’d do well to read up on the Doxygen file of PhysicsFS or the source for PhysFS++. Lastly, when one is done with the library, you’ll need to call a deinitialization function called deinit:

PhysFS::deinit ();
Advertisements

Configuring Apache Cordova with JetBrains WebStorm

Stepping back into the mobile arena after a bit of an absence, I decided to take a bit of advice from a gentleman who sat in on my 2014 Ohio Linux Fest lecture “Android Development on Linux” (generously, and anonymously, curated on the Internet Archive) and look not just at Android but at cross platform. For the longest time, this has always been a topic of considerable consternation. One has to think, upon reflection of the history of technology, that we’ve experienced in some ways a regression to the days when cross platform littered the landscape and was, in certain respects, paralyzing. Fortunately for myself and others, we weren’t the only ones who recognized this. Some have taken action to help ensure that we do have a shim solution for these cases, and this is where Cordova enters the fray. Being derived from PhoneGap and adopted by Apache, Cordova attempts to bring to mobile developers the ability to write a program using web languages such as HTML, CSS, and JavaScript and deploy it to multiple platforms including but not limited to Android, iOS, and Windows Phone.

As I mentioned before, the focus this time around is on cross platform development. I had a little taste of PhoneGap a few years ago and it never really stuck but there seems to be a little community acquiescence toward Cordova. Not to say that I’m following the grain too much here because there is a genuine personal interest in the framework on my part, but I want to be able to help people as well.

Now, the development environment that I use is detailed here. As you should be aware, you may want to keep this in mind proceeding forward.

  • OS: Linux
    • Distribution: Ubuntu 15.10
    • Only the default upstream repositories are used in dpkg
  • Arch: 64
  • IDE: JetBrains WebStorm (I have a license for this; the unlicensed version only works for thirty days).

As the title indicates, this tutorial is specific to configuring WebStorm to be used with Cordova. As such, there will be a lot of WebStorm-specific information here that, if you were using an alternative IDE, may not be applicable. You’ll want to follow your IDE’s integration instructions or deduce it on your own at that rate.

Prerequisite – NodeJS/NPM

I’m going to be frank here – there is very little that I know about NodeJS other than what it is, that it’s been the subject of quite a lot of hype in the web development community since its conception, and that it is a requirement on behalf of Cordova. While there is still quite a bit of homework that needs to be done on my part, I have been able to successfully install and configure it so that it works for the purposes of Cordova. This will be the topic that is covered here.

Node can either be installed by downloading it in a pre-compiled package from the Node website or through your distribution’s default repositories. If you elect to download from the Node website, you’ll need to be responsible for manual maintenance of the package and for extracting it to a location that you have access to via your permissions or ACLs (if your file system supports them). The method I used was installing was the former since updates are automatic and installation is performed in the appropriate directories. This can be done with the following command

sudo apt-get install nodejs

Once this command completes, you’ll have Node installed on your computer. To test this, you’ll want to start a Node interpreter by issuing the command nodejs at your terminal. If you’re brought to a new prompt lacking the traditional user and host name information, Node is all set to go. You’ll need to press Ctrl+C twice to end the program and return to your traditional prompt.

NPM, a pseudo package manager for JavaScript libraries, is required since this is the preferred method for installing Cordova. It will also help with obtaining Cordova plugins and other JavaScript libraries that you might want to use later on for development. It can be installed in the same was as Node was with the distribution’s package manager.

sudo apt-get install npm

To test the installation, you can simply issue npm at the terminal. If you get back a page of text indicating the usage syntax, NPM has been installed successfully.

Installing Cordova

When you’re using WebStorm, it’s apparently possible to install Cordova entirely through the IDE once you have configured it to locate both Node and NPM. These steps, however, are a little convoluted to follow, especially with all of the potential pitfalls you’re going to encounter, so we’re going to avoid this entirely and install Cordova with NPM on the terminal.

NPM has two install modes: local and global. A local installation will create a node_modules directory in the working directory where the command was issued at and install the module there. The global installation places all of the modules in a consolidated directory and makes that available to the system through environment variables; Cordova is best installed in global mode (recommended by the official install documentation). The installation can be performed with a single NPM command

sudo npm install -g cordova

The installation, when in the global scope, will need to be run as root hence the use of sudo.

Caveats… Already

To test Cordova, you’d do it in the same way that you would with both Node and NPM. However when you type cordova into the terminal and press enter, you will most likely, but certainly not always, get in response an error that may look like this:

/usr/bin/env: node: not found

The issue here is that Cordova is looking for the Node binary with a specific identifier, node. However when Node is installed through the package manager, the identifier of the binary is nodejs. Despite there being several tutorials on the Internet offering advice such as aliasing nodejs as node in your .bashrc file, the solution that needs implemented here is to create a symlink in /usr/bin named node that links back to nodejs. So what your directory tree looks like then is similar to this

cordova-node-usrbin-dirstructure

If the highlighting gets in the way, what you should be paying attention to here is that the bottom highlighted line shows the actual Node binary, nodejs, and the top line shows the node symlink which points straight to the nodejs binary. They’re both in the same directory but Cordova is looking specifically for the node file. I’m unsure if this can be configured in Cordova in some way so if someone knows, please share how to do this. Either way, once this symlink exists in /usr/bin, you should be able to then issue cordova from the terminal and get syntax help printed out to the terminal. If this happens, Cordova can see Node and is ready to go.

Prerequisite – Platform SDKs

As great as Cordova may be, it needs the platform SDKs in order to build for each one specifically. Obviously, while capable of bridging the gap between platforms, you still need the platforms themselves to actually accomplish anything. The good thing is that the Cordova wiki hosts a plethora of information relative to acquiring the corresponding SDKs. Being on a Linux system, you can install without a serious amount of labor the Android, BlackBerry and Ubuntu SDKs. For the sake of this tutorial, we’re only going to be focusing on the Android SDK. If there is further interest in setting up any of the other SDKs, I’ll create them later.

Downloading and installing the Android SDK should be a relatively straightforward process at this stage. I’m going to assume that you either know how to do this or can follow the instructions outlined on the Cordova wiki. Post installation, you’ll want to ensure that you have added an environment variable called ANDROID_HOME and included it in your PATH environment variable that points to the root directory of the SDK; again assuming that you know how to set persistent environment variables on your Linux computer..

As a secondary caveat, if you’re starting WebStorm from a desktop link or a link in the Unity Launcher, there is a bit of a catch in that the invocation context will be such that the program won’t notice the user-modified PATH variable that contains the ANDROID_HOME variable. What this means is that the IDE won’t be able to see the location of the Android SDK (I’m assuming that this would be the case for other SDKs as well). The way to fix this is to modify the EXEC field in the file to preface the issuing command with bash -ic.

cordova-node-wsdesktopstart-mod

Keep in mind that traditional desktop icons are found in ~/.local/share/applications while Unity Launcher icons are located in /usr/share/applications.

So long as all of these conditions are met, you should be able then to start WebStorm and create a Cordova project. Let’s step through that process next.

WebStorm – Creating a Cordova Project

webstorm-cordova-launch001

As you can tell, I’ve been at this for quite some time.

The first thing you’ll want to do is click on Configure at the bottom-right and then select Settings which will be the first item in the subsequent menu.

webstorm-cordova-launch002

First you’ll want to examine to ensure that WebStorm knows the location of Node. It’s highly unlikely that it has automatically determined its location so you may have to set it. Keeping in mind the location of the Node binary that was installed through your system’s package manager, you’ll want to get this fully qualified path name, along with the binary, into the Node interpreter field. Code Assistance may not be enabled for you by default. Frankly I’m unsure what this feature is but I have it enabled because… reasons.

webstorm-cordova-launch003

Next you’ll want to instruct WebStorm as to where to find the Cordova binary. Again, there’s a very high chance that it’s not automatically detected by your installation so you’ll have to manually specify. As we did with specifying the Node installation directory, you’ll need to do that here in the first field labeled PhoneGap/Cordova executable. Note that WebStorm still retains the PhoneGap label for all things Cordova even though Cordova has absorbed PhoneGap. Once the installation directory has been specified and WebStorm sees the Cordova binary, the PhoneGap/Cordova version field should automatically populate. The third field, PhoneGap/Cordova working directory shouldn’t be filled out at this point; ignore my entry here. This field is specific to your current project. This also explains the error that you’re seeing at the bottom of the window in the screen shot.

Once those are set, you can click OK and go back to the WebStorm Greeting Window. Here, you can click on Create New Project.

webstorm-cordova-launch004

Once the New Project dialog appears, you’ll select PhoneGap/Cordova App on the left side and then fill out the Location field. The PhoneGap/Cordova field is simply the location of the Cordova binary; we set this previously in the global settings. Click Create and WebStorm should take care of the work to generate the files necessary for your project.

webstorm-cordova-launch005

Now so long as the steps above were followed to the letter, you shouldn’t have any errors, other than something simply blowing up, that get thrown from WebStorm. Now you can start working on your program.

Deployment

webstorm-cordova-launch006

Testing your Cordova program can be done by creating multiple Run Configurations. Each of these would be distinguished by the value in the Name field. The value in the Command field will determine if Cordova will attempt to delegate to the emulator for the target platform, and the value in the Platform field will determine which platform is being targeted with this Run Configuration. I prefer to test on actual hardware, unless I’m constrained by the lack of, so for Android deployments I’ll deploy strictly to the device.

This should be enough to get you started. You can always read more on the Cordova Wiki to get a primer on the Cordova specifics. Otherwise you can start hacking away using HTML, CSS, and JavaScript