Skip to content

Latest commit

 

History

1,425 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LAK

Please make sure you have read the basic setup guide before building anything!

License

This library is dual licensed under the Unlicense and MIT license. See LICENSE and UNLICENSE. Attribution would be nice but is not required.

If you are intending to use this as a subproject or distribute binaries, ensure you have also checked the licenses of the subprojects used by this library. Many subproject dependencies can be turned on or off with meson settings.

Philosophy

  • Reserving address space should not increase physical memory usage on a hosted system.
  • Prefer dense allocation over sparse allocation.
  • Recursion is evil.
  • Runtime performance is more important than compile time performance.
  • Abuse the type system whenever and wherever possible.
  • Types should be either primarily data (POD/C-structs) or primarily functionality (containers, traits), but not both (OOP).
  • virtual is usually a sign of systematic design failure.
  • Design APIs to be granular.

Basic setup

Building requires meson and a C++ compiler (msvc, clang, gcc, etc).

Enable or disable features by modifying meson_options.txt or with -D[feature]=[setting] command line options during setup (setup.bat msvc "-Dfeature=setting", ./setup.sh gcc -Dfeature=setting, etc, etc).

Running setup.sh/setup.bat/win_setup.sh multiple times will wipe the build directory, make sure you've specified all the options you need up front.

Windows

Native (msvc) via command prompt (always use *.bat scripts, wrap settings in "" quotes):

setup.bat msvc "-Dfeature1=settings1" "-Dfeature2=settings2"
compile.bat <target>

Native (msvc) via WSL (always use win_*.sh scripts):

./win_setup.sh msvc -Dfeature1=settings1 -Dfeature2=settings2
./win_compile.sh <target>

MacOS

Install LLVM (at least llvm@20 recommended) with homebrew

./setup.sh homebrew-clang <feature settings>
./compile.sh <target>

Linux

gcc

./setup.sh gcc <feature settings>
./compile.sh <target>

clang

./setup.sh clang <feature settings>
./compile.sh <target>

NixOS

nix-shell
./setup.sh auto <feature settings>
./compile.sh <target>

Tools

These are command line tools mostly designed to only depend on std:: or a very minimal subset of the core of lak::, in some cases so they can be used as pre-processors for later build stages.

Run with no arguments to get help text.

asc2csv

Converts .asc point cloud files to .csvs.

Setup the build directory then

compile.bat asc2csv
build\tools\asc2csv\asc2csv

or

./compile.sh asc2csv
./build/tools/asc2csv/asc2csv

ebnf2cpp

Reads in a semi-custom EBNF grammar description language and uses it to generate lak::dsl:: headers.

Setup the build directory then

compile.bat ebnf2cpp
build\tools\ebnf2cpp\ebnf2cpp

or

./compile.sh ebnf2cpp
./build/tools/ebnf2cpp/ebnf2cpp

There is a generator in meson that can be used to use ebnf2cpp at compile time:

ebnf2cpp = subproject('lak').get_variable('ebnf2cpp')
my_lib = static_library(
	'my_lib',
	[
		'my_lib.cpp',
		# Accessed with #include "my_grammar.ebnf.hpp"
		ebnf2cpp.process('my_grammar.ebnf', extra_args: [
			'MY_LIB_EBNF_HPP', 'my_lib_parse']),
	],
)

lisk-repl

Setup the build directory then

compile.bat lisk-repl
build\tools\lisk-repl\lisk-repl

or

./compile.sh lisk-repl
./build/tools/lisk-repl/lisk-repl
lisk> (begin (define func (lambda (x n) (begin (if (zero? n) x (tail (func (* x 2) (- n 1))))))) (println (func 2 10)))
2048
lisk$ nil
lisk>

mdc2png

Demosaics/desqueezes/upscales Minolta RD-175 .MDC raw files and saves the results as a .png.

Required feature settings:

  • -Dlak_enable_stb=true
  • -Dlak_enable_stb_image_write=true

Setup the build directory then

compile.bat mdc2png
build\tools\mdc2png\mdc2png C:\path\to\.MDC D:\path\to\.png

or

./compile.sh mdc2png
./build/tools/mdc2png/mdc2png /path/to/.MDC /path/to/.png

mdc2png.png

Examples

basic_program

Demo of various features available with <lak/basic_program.inl>

Required feature settings:

  • -Dlak_enable_windowing=true
  • -Dlak_enable_imgui=true
  • -Dlak_renderer=
    • softrender
    • opengl
    • cobalt (-Dcobalt_renderer= to change which Cobalt renderers to use)
    • any or all of the above ("-Dlak_renderer=softrender,opengl,cobalt" (including quotes))

Setup the build directory then

compile.bat basic_program
build\examples\basic_program\basic_program

or

./compile.sh basic_program
./build/examples/basic_program/basic_program

basic_program.png

ball-game

Roll a ball around a maze of blocks and collect all the coins. Controlled with the arrow keys. Don't fall off!

Required feature settings:

  • -Dlak_enable_windowing=true
  • -Dlak_enable_imgui=true
  • -Dlak_renderer=opengl

Setup the build directory then

compile.bat ball-game
build\examples\ball-game\ball-game

or

./compile.sh ball-game
./build/examples/ball-game/ball-game

ball-game.png

Can load custom maps by dropping a .pnm image file into the game window.

  • Red channel = ground blocks
  • Green channel = collectable coins
  • Blue channel = lights (max 32)

See examples/ball-game/assets/map.ppm for the example map.

hello-cobalt

Demo of the Cobalt Renderer integration. Will attempt to open a window for every enabled renderer simultaneously.

Required feature settings:

  • -Dlak_enable_windowing=true
  • -Dlak_enable_imgui=true
  • -Dlak_renderer=cobalt
  • -Dcobalt_renderer= (optional: all system-available renderers enabled by default)
    • OpenGL3 (Windows, MacOS, Linux)
    • OpenGL4 (Windows, Linux)
    • Vulkan (Windows, MacOS, Linux)
    • Direct3D11 (Windows)
    • Direct3D12 (Windows)
    • any or all of the above ("-Dcobalt_renderer=OpenGL3,OpenGL4,Vulkan,Direct3D11,Direct3D12" (including quotes))

Setup the build directory then

compile.bat hello-cobalt
build\examples\hello-cobalt\hello-cobalt

or

./compile.sh hello-cobalt
./build/examples/hello-cobalt/hello-cobalt

hello-cobalt.png

mdc-view

Inspector for Minolta RD-175 .MDC raw files.

Required feature settings:

  • -Dlak_enable_windowing=true
  • -Dlak_enable_imgui=true
  • -Dlak_enable_stb=true
  • -Dlak_enable_stb_image_write=true

Setup the build directory then

compile.bat mdc-view
build\examples\mdc-view\mdc-view

or

./compile.sh mdc-view
./build/examples/mdc-view/mdc-view

mdc-view.png

nbt-view

Inspector for .nbt files.

Required feature settings:

  • -Dlak_enable_windowing=true
  • -Dlak_enable_imgui=true

Setup the build directory then

compile.bat nbt-view
build\examples\nbt-view\nbt-view

or

./compile.sh nbt-view
./build/examples/nbt-view/nbt-view

nbt-view.png

Advanced setup

To specify compilers manually:

set CC=<C compiler>
set CXX=<C++ compiler>
set CC_FOR_BUILD=<C compiler>
set CXX_FOR_BUILD=<C++ compiler>
setup.bat auto
compile.bat <target>
export CC=<C compiler>
export CXX=<C++ compiler>
export CC_FOR_BUILD=<C compiler>
export CXX_FOR_BUILD=<C++ compiler>
./setup.sh auto
./compile.sh <target>
export CC_FOR_BUILD=<build C compiler>
export CXX_FOR_BUILD=<build C++ compiler>
./setup.sh auto --cross-file=<host system cross file>
./compile.sh <target>

MacOS example:

export CC=$(brew --prefix llvm@20)/bin/clang
export CXX=$(brew --prefix llvm@20)/bin/clang++
export CC_FOR_BUILD=$(brew --prefix llvm@20)/bin/clang
export CXX_FOR_BUILD=$(brew --prefix llvm@20)/bin/clang++
./setup.sh auto
./compile.sh <target>

Use llvm@<version> for a specific version of of LLVM. llvm@20 or higher is recommended.

Cross compiling

Pre-configured cross compilation options take the form:

./setup.sh <host system option> <build system option>

(Host system means the system the <target> executables will run on, build system means the system that will compile them. Some parts of lak:: require building pre-processing tools, which means a compiler to build executables for the build machine must also be specificed)

Emscripten

Specifying wasm32 or wasm64 will automatically select pre-configured cross files for use with Emscripten

./setup.sh wasm32 <build system option>
./compile.sh <target>
./setup.sh wasm64 <build system option>
./compile.sh <target>

Build with tests

./setup.bat msvc --buildtype=debug -Dlak_enable_tests=true
./compile.bat lak_test
./build/lak_test --testall

Build with libgphoto2

Windows

Requires msys64

./setup.bat msvc -Dlak_enable_libgphoto2=true -Dlibgphoto2_msys_prefix=C:/msys64
./compile.bat install-msys-libgphoto2-dependencies
./compile.bat <target>

Other

Requires libgphoto2 dependencies to be preinstalled.

./setup.sh gcc -Dlak_enable_libgphoto2=true
./compile.sh <target>

Build with llvm

To use LLVM on Windows, MSVC must be installed with the MFC and ATL components

./setup.bat msvc -Dlak_enable_llvm=true
./compile.bat <target>

Using lak::

An example of an extremely simple program that opens a fullscreen Dear ImGui window (backend renderer determined by settings in meson_options.txt):

basic_program.png

// default window name and ID for root Dear ImGui window
#define APP_NAME "basic_program"

// handle Dear ImGui context creation, event processing and rendering
#define LAK_BASIC_PROGRAM_IMGUI_IMPL

// create a full screen Dear ImGui window surrounding calls to window loop
#define LAK_BASIC_PROGRAM_IMGUI_WINDOW_IMPL

// can be included in other source/header files if access to these functions is
// needed from elsewhere (ensure config defines are set first)
// #include <lak/basic_program.hpp>

#include <lak/basic_program.inl> // include .inl file only once (typically your
                                 // main.cpp or equivalent)

#include <lak/optional.hpp>

#include <lak/imgui/texture.hpp>

#include <filesystem>

// refer to basic_program.inl for an example of how to implement main yourself
// and avoid the dynamic dispatch of LAK_BASIC_PROGRAM(window_api)
struct my_window : virtual public LAK_BASIC_PROGRAM(window_api)
{
	my_window() : LAK_BASIC_PROGRAM(window_api)() {}

	// store any member variables needed by this window here so they can be
	// accessed during init/handle_event/loop

	lak::optional<std::filesystem::path> dropfile;

	// unique_com_ptr wrapper of ImTextureRef which will automatically handle
	// destroying the texture
	lak::ImUniqueTexture checker;

	virtual void init() override final
	{
		// called once window has been set up

		window().set_title(L"something other than " APP_NAME);

		lak::image<lak::vec3u8_t> checker_img;
		checker_img.resize(lak::vec2s_t{30U, 30U});
		for (size_t y = 0U; y < checker_img.size().y; ++y)
			for (size_t x = 0U; x < checker_img.size().x; ++x)
				checker_img[{x, y}].r = checker_img[{x, y}].g = checker_img[{x, y}].b =
				  (((x + y) & 1U) * 255U);
		checker.emplace(checker_img); // see also: lak::CreateTexture() and
		                              // lak::DestroyTexture()
	}

	virtual ~my_window()
	{
		// handle end-of-window-lifetime cleanup here
	}

	virtual void handle_event(lak::event &event) override final
	{
		// called whenever the window receives an event
		switch (event.type)
		{
			case lak::event_type::close_window:
				destroy(); // window is added to the destroy queue (flushed at end of
				           // the current frame)
				break;
			case lak::event_type::dropfile:
				dropfile = event.dropfile().path;
				break;
		}
	}

	virtual void loop(uint64_t counter_delta) override final
	{
		// called once every frame

		ImGui::Text("Frame time: %01.2fms",
		            ((float)counter_delta * 1000U) / lak::performance_frequency());

		lak::window &wnd = window();
		ImGui::Text("Window size: %lu x %lu", wnd.size().x, wnd.size().y);
		ImGui::Text("Drawable size: %lu x %lu",
		            wnd.drawable_size().x,
		            wnd.drawable_size().y);

		if_let_some (auto &path, dropfile)
			ImGui::Text("Dropped file: %s", path.generic_string().c_str());

		ImGui::Image(checker, ImVec2(200, 200));
	}
};

// lak::error_code<int> -> lak::result<lak::monostate, int>
lak::error_code<int> LAK_BASIC_PROGRAM(program_preinit)(lak::span<char *> args)
{
	// called at program startup

	// return lak::ok_t{}: continue onto program_init
	// return lak::err_t{int}: quit program with that exit code
	return lak::ok_t{};
}

lak::weak_ptr<LAK_BASIC_PROGRAM(window_instance<my_window>)> my_window_ptr;

lak::error_code<int> LAK_BASIC_PROGRAM(program_init)()
{
	// called after program_preinit and once all platform initialisation is
	// complete. you can start creating windows now

	auto map_str_err = [](lak::u8string err) -> int
	{
		ERROR(err);
		return EXIT_FAILURE;
	};

	// try macros can be used thanks to the result type return value
	RES_TRY_ASSIGN(
	  my_window_ptr =,
	  LAK_BASIC_PROGRAM(create_window<my_window>)().map_err(map_str_err));
	// by not specifying a specific graphics settings struct, create_window will
	// attempt to find the first working graphics backend (settings for each are
	// pulled from the global LAK_BASIC_PROGRAM(window_*_settings) structs).

	DEBUG_EXPR(my_window_ptr.get()->window().graphics());

	// return lak::ok_t{}: continue onto program_loop
	// return lak::err_t{int}: quit program with that exit code
	return lak::ok_t{};
}

void LAK_BASIC_PROGRAM(program_handle_event)(lak::event &event)
{
	// handle non-window events
}

bool LAK_BASIC_PROGRAM(program_loop)(uint64_t counter_delta)
{
	// called once per frame

	// return true: continue program execution
	// return false: stop main program loop, continues to program_quit
	return !LAK_BASIC_PROGRAM(window_instances)().empty();
}

int LAK_BASIC_PROGRAM(program_quit)()
{
	// called after program_loop has returned false and after basic_program's
	// window bank has been cleared (if you are holding onto any window
	// pointers, clear them here)

	my_window_ptr.reset(); // this was only a weak pointer, so the window should
	                       // have already been destroyed, but this will still
	                       // deallocate the memory now

	// return value used as program exit code
	return EXIT_SUCCESS;
}

lak:: has been developed with a granular API, so if you find this (basic_program) style of application framework too restricting, you might look at the source of basic_program.hpp/basic_program.inl for examples of how you might implement a lower level program yourself.

About

Application development framework

Resources

Stars

12 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages