Glymmer (Glyph Menu) 0.3
Graphic user interface made of glyphs and using controller style input.
Glymmer (Glyph Menu)

Glymmer (Glyph Menu)

Author: Eric Pietrocupo

Artifacts

The following artifacts are available for download or reading:

Introduction

This project is a glyph based user interface displayed in graphic mode which should be mostly used in video games, but it could be used for other projects. It use regular ascii characters to create window outline and display choices to the user. The output is still in graphic mode even if the interface are character based. This also allows to skin the dialogs for different thematic purpose.

The project will be coded in plain C for portability and simplicity. Unicode will not be supported as I do not want to draw 65 thousands characters. The latest ISO/IEC 8859-15 will be used instead. It should support all european language. Considering Japanese can write using romaji, I don't think there will be any issues supporting other languages with this alphabet.

There is multiple glyphs sets, the characters, the frame and the game icons. This allow skinning the user interface the way you like it.

Features

Almost all user interface are event based, it requires the program to react to use input which changes the flow of the program. Glymmer is a non-event based user interface that get things done by asking the user a series of questions. It relies on the fact that video games have little data entry but have a lot of operations to manipulate that data. You don't want the user to easily modify the game's data as it would be cheating. So there is no need to have input forms to add and modify data. Instead, it's only a series of choice that the user must make based on information displayed to them.

Glymmer takes advantage of this and gain the following benefits:

  • No need to handle events, the user choose where he wants to go once, then he is on a track.
  • No need to define listener, the program flow remains normal, you ask a question and wait for an answer. So the game loop is not at a single place.
  • No need to handle notifications.
  • No need for many widgets to create a window, everything is built by drawing text.
  • No need for custom crowded windows, you reuse many different dialogs to achieve what you want, but there is little need for custom code.
  • No need to manage layout inside a dialog. You will need to manage the layout of multiple dialogs on the screen.
  • No need of object oriented programming, Entity Component System and data oriented programming will be used internally almost transparently to the user.
  • The interface is suitable for keyboard and joystick only.

The disadvantages:

  • Players are most of the time on track. They generally make a choice using a menu, then answer a series of questions to perform the operation.
  • The same window structure will be reused over and over. Which could be boring after some time.
  • Designed for video games, so little data to insert but lof of commands to execute. Could be problematic in other type of applications.
  • It require an SQLite database for most of the operations. The library is limited without SQLite.
  • No mouse support

Dependencies

The following libraries are required:

  • Raylib: Video game library.
  • Sqlite: Database library for query dialogs.
  • Cunit: (optional) Unit test library, not required to run the game.
  • cmake: Software builder
  • ninja: Software builder

Dependencies are apparently more painful to handle with the C language, especially when supporting multiple platforms. After 100+ hours of work with chat GPT, claude AI and google AI, we came up with a compromise that should make all parties happy: ME the programmer, YOU the user and IT the gitlab runner. Take note that build process are complex (more than they should) and not flawless, I cannot guaranty it will work on all computers, I am sorry if it does not works.

Also take a look at my stock ticker project. Its an example of game that uses this library, so it can contain useful code to setup the build system correctly.

Gitlab: Stock Ticker

Installing dependencies on linux

Library dependencies and building tools can be installed with the following command except for raylib that must proceed other wise (this is for debian 11 command line):

sudo apt-get update && sudo apt-get install -y \
build-essential \
pkg-config \
cmake \
ninja-build

you also remove the backslashes and put everything on a single line. SQLite will be downloaded from source, the package is in case of fallback. If you want to build unit tests, add those packages:

libcunit1 libcunit1-dev

Some distribution have a raylib development package, if you can install it from package fine, else you will have to build it yourself. In linux, there is a script to download, compile and install raylib and other dependencies into your build folders, you can launch it this way:

sh/get_depedencies.sh linux

Installing dependencies on windows

This is more tricky and I do not have a windows computer to test it. So you basically need:

  • gcc, g++: MinGW compiler (see note below)
  • ninja: Build tools
  • cmake: Build tools
  • curl: Allow downloading from URL
  • tar: File decompression
  • PowerShell: To run commands

In theory you can use a different compiler than mingw, the scripts should be working, cmake should find any compiler you have available ... in theory. Many of those softwares are installed by default stating from windows 10. I also have a batch scripts to do the job, I could not test them, so they were generated and validated by chatGPT, use at your own risk. You can install dependencies by typing:

sh\get_dependencies.bat

If everything goes according to plan, raylib and sqlite3 should be downloaded and built. I hope everything goes well. If you have issues with raylib, look at raylibs web site documentation to indicate how to install the library.

https://github.com/raysan5/raylib/wiki/Working-on-Windows

Installing dependencies for cross-compiling for windows.

You can use the following command to install the depedencies for cross compiling(Again, from a debian distro):

sudo apt-get update && sudo apt-get install -y \
build-essential \
pkg-config \
mingw-w64 \
g++-mingw-w64-x86-64-posix \
mingw-w64-tools \
pkg-config-mingw-w64-x86-64 \
mingw-w64-sqlite3 \
cmake \
ninja-build

Cross compilation library are generally not available so they must be downloaded and built. I have a script that should be used to prepare for an installation:

sh/get_dependencies.sh windows

All those dependencies are built from source. So it always takes a certain amount of time to do download and build those dependencies.

Building the Software

The build process is also using scripts. At this point, we assume that all the dependencies are installed and working. Note that building software is never bullet proof, you can run in many issues. The problem is that people comes from different platforms with different resources, so its hard to anticipate all the possibilities when I don't have multiple computers with different platforms in front of me. If the dependencies were built so far without failure, the rest is very likely to build correctly.

To build the linux version you can run this script

sh/build.sh linux

Cross compiling windows on linux

Normally cross compilation is designed to be used by the gitlab continuous integration script, but you can do it yourself if you want. There is also a script to do the job only for crosswin:

sh/build.sh windows

Building from windows

ChatGPT made some batch files for a windows build, again use at your own risks. You can run it using:

sh\build.bat

Installing the software on windows and linux.

To install the library, you will need to have admin access in linux using sudo, I do not think its necessary in windows. You can use the following command to install it on your system, the binaries will be in the rool directory, since you are impatient to try it out ... right!?

sudo cmake --install build-linux

OR

sudo cmake --install build-window

Use the command according the the platform you compiled to. Else you have to copy files manually in the "build-..." directories. It should copy the .so library, the tools and the include files into the local directories (/usr/local/lib, /usr/local/bin, /usr/local/include.

The demo program demo and the examples will be copied at the root of the project for easy demonstration. Makes sure you have the glyph assets ready at the same place.

Installing crosscompilation

There is no reason to crosscompile install, so running the command above will make no sense. The files are simply designed to be packaged during continuous integration. You can still find the files in the directory structure under build-windows/src, dll should be under lib/, the .exe demo under demo/, and examples under example/.

Running the unit tests

Once the library is built and installed. You can build the unit tests with:

sh/build_test.sh

This script to build the unit test. Then you can run them by typing:

build-linux/src/test/unitest

I only configured the unit test for linux, since its only supposed to be used by continuous integration.

Downloading the glyphs assets

In order to run the demo and examples, you will need the glyph assets. That is the whole point of the library, use image glyphs to display user interface and information. If you do not have the glyphs in hands, no worries, I got some scripts to do the job. Glyphs are either characters used to build dialog frame, display test, or display game icons in text. Glyphs should be available already built on my website, look for the asset archive:

http://lariennalibrary.com/ArtifactDepot/glymmer/glyph/

else you can download and build them yourself. The idea is that each individual image is fusionned together in a single image. The glyphs should have been fusionned into sprite atlas already on my website. You can download them manually on the link above or use the following script:

sh/download_assets.sh

in windows you can use

sh\download_assets.bat

You should now have different png files at the root of the project. Here are some example glyph sets, name followed by size, those glyphs are 10x15 pixels.

IcGenericGameIcon1015.png
FrGreenGold1015.png
FrBrushedMetal1015.png
FrRenaissance1015.png
FrWindows1015.png
LtWizardry1015.png

The font name prefix indicates the purpose of the glyph:

  • Ic: Icon Glyphs
  • Fr: Window frame glyphs
  • Lt: Letter Glyphs

Building your own glyph assets

If you want to create your own glyphs or modify those that I made, you can you can download all the glyphs available using this script:

sh/download_glyph.sh

Each character will be an individual file. You need to use gpack installed (a tool previous built) to assemble those characters into the same file. You can use the following script to do that:

sh/build_glyph.sh

Demo and examples

The demonstration application used for functionnal testing. I allows exploring the various features of the library. It does not do anything in particular. Makes sure the glyphs are in the same folder. You can launch it by typing in linux:

demo

Example programs are also available for learning and testing purpose:

ex01text
ex02list
ex03database

you can run them all with the script

sh/run_examples.sh

Using the library

First you need to copy lib/libglymmer.so or lib/libglymmer.dll into your library path to make sure it finds it when compiling your program. Also copy the include/ files into your include path. You need some options to make sure it can find the library at the same place as the binaries. See below.

To use the library in your projects, simply add -lglymmer to your linker command line or the glymmer library to your build tools.

Raylib demands much more libraries, so far I am using this list in code::blocks. raylib GL m pthread dl rt X11

While sqlite3 requires sqlite3

In case of doubt, look at my stock ticker game as an example of project.

Using the library with Cmake

If you have a cmake project, here are some guide lines how to plug my llibrary into your project. I will require to use the config mode instead of the module mode. The files should be created when building the library.

I first add some options to make sure everything gets built dynamically in the root CMakeLists.txt:

set(BUILD_SHARED_LIBS ON)
set(RAYLIB_STATIC_LIB OFF CACHE BOOL "Use static Raylib" FORCE)

Your project will require the following packages in that order:

find_package(raylib CONFIG REQUIRED)
find_package(SQLite3 CONFIG REQUIRED)
find_package(Glymmer CONFIG REQUIRED)

In your source code CMakelists.txt, you will need to include the library:

target_link_libraries(stockticker PRIVATE
Glymmer::glymmer
raylib
SQLite3::sqlite3
m
)

You can use the lines below to for the program to look in the same folder for the libraries. Install rpath is responsible for that. It just makes distribution easier.

set_target_properties(demo PROPERTIES
BUILD_RPATH "\$ORIGIN"
INSTALL_RPATH "\$ORIGIN"
)

Now raylib is very picky if you are crosscompiling, or even normally compiling, it could be using the wrong dependencies, or could take 2 different copie of the raylib. If you endup in such a situation, you need to change the configuration that raylib is definning because it is buggy. To do so, in your main Cmakelists.txt file, add the following lines of code after find_package(raylib CONFIG REQUIRED):

# Raylib's installed config may have host build paths baked in.
# Strip any flags that aren't the actual import library we found.
if(TARGET raylib)
get_target_property(_rl_libs raylib INTERFACE_LINK_LIBRARIES)
message(STATUS "raylib INTERFACE_LINK_LIBRARIES before fix: ${_rl_libs}")
if(_rl_libs)
# Remove anything that is a bare -lraylib or an absolute host path to raylib
list(FILTER _rl_libs EXCLUDE REGEX ".*lraylib.*")
list(FILTER _rl_libs EXCLUDE REGEX ".*/usr/local/.*raylib.*")
set_target_properties(raylib PROPERTIES INTERFACE_LINK_LIBRARIES "${_rl_libs}")
message(STATUS "raylib INTERFACE_LINK_LIBRARIES after fix: ${_rl_libs}")
endif()
endif()

You can reuse my shell script if you want to help yourself building your project. This is not a bullet proof process, other adjustments might need to be done. Watch out for raylib, there is always problems.

Using the library with Meson

I successfully configured a meson project, but it could be quite complicated to make it run. It only worked once, now it does not woirks anymore. Still, I'll try to explain the necessary steps to make it work, again, not a bullet proof process, and raylib always cause issues.

In the meson.build, you need need to configure raylib and glymmer to use cmake to build the project. Else it will try to search for a meson project. Here is my dependency configuration, you will add them to your project afterwards.

cmake = import('cmake')
#Raylib dependency
raylib_opts = cmake.subproject_options()
raylib_opts.add_cmake_defines({
'BUILD_SHARED_LIBS': 'ON',
'BUILD_EXAMPLES': 'OFF'
})
raylib_proj = cmake.subproject('raylib', options: raylib_opts)
raylib_dep = raylib_proj.dependency('raylib')
#Other common dependencies
sqlite3_dep = dependency('sqlite3', fallback: ['sqlite3', 'sqlite3_dep'])
threads_dep = dependency('threads')
#Glymmer dependency
glymmer_opts = cmake.subproject_options()
glymmer_opts.add_cmake_defines({
'BUILD_SHARED_LIBS': 'ON'
})
glymmer_proj = cmake.subproject('glymmer', options: glymmer_opts)
glymmer_dep = glymmer_proj.dependency('glymmer')

If you are crosscompiling and I think building for windows, you need additional dependencies:

extra_deps = []
if host_machine.system() == 'windows'
extra_deps += [
cc.find_library('winmm'),
cc.find_library('gdi32'),
cc.find_library('opengl32'),
cc.find_library('shell32')
]
endif

If you want to make sure the libraries are found in the same folder as the binary executable, add the following property to the executable command:

executable(meson.project_name(),
...
...
install_rpath: '$ORIGIN'
)

While I was writting this document, crosscompiling was not yet working with Meson, so keep your ecpectations low. You also need a crosscompilation file, I am still in the process of trying to make it work.

Now the dependencies can download themselves automatically. To do so, a subprojects/ folder with wrap files are necessary. Here are a copy of my wrap files, the sqlite3.wrap can be downloaded from the database.:

raylib.wrap

[wrap-git]
directory = raylib
url = https://github.com/raysan5/raylib.git
revision = 5.5
depth = 1
buildsystem = cmake
[provide]
raylib = raylib_dep

glymmer.wrap

[wrap-git]
directory = glymmer
url = https://gitlab.com/larienna/glymmer.git
revision = master
depth = 1
buildsystem = cmake
[provide]
dependency_names = glymmer_dep

I hope that it works.

Build Documentation

The documentation is made with doxygen, you simply need to type

doxygen Doxyfile

to generate the documentation. The web site entry point will be located in :

doc/html/index.html

Conclusion

Thank you for taking the time to read this. I hope everything works well for you. I hope you try making some games or other software of your own.