Skip to content

Commit 296672b

Browse files
committed
Add cross-platform bgfx + GLFW graphics sample.
Introduce docs/how/cmake_bgfx as a mixed TypeScript/C++ graphics sample using the TSLANG CMake language, GLFW, and FetchContent bgfx.cmake. Control flow matches cmake_winapp and cmake_vulkan: C++ owns the event loop (GLFW polling); TypeScript constructs AppWindow and handles onMessage for frame rendering and input. Targets Windows, Linux (X11), and macOS via GLFW native window handles.
1 parent 61a0c8c commit 296672b

15 files changed

Lines changed: 819 additions & 0 deletions

docs/how/cmake_bgfx/CMakeLists.txt

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
4+
5+
project(cmake_bgfx CXX)
6+
7+
set(CMAKE_CXX_STANDARD 20)
8+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
9+
set(CMAKE_CXX_EXTENSIONS OFF)
10+
11+
set(TSLANG_ROOT "" CACHE PATH "TypeScriptCompiler __build folder (contains tslang/, llvm/, gc/)")
12+
13+
include(LocateTSLang)
14+
locate_tslang_compiler()
15+
set(CMAKE_TSLANG_COMPILER "${CMAKE_TSLANG_COMPILER}" CACHE FILEPATH "TSLANG compiler" FORCE)
16+
17+
include(FetchContent)
18+
19+
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
20+
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
21+
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
22+
set(GLFW_BUILD_WAYLAND OFF CACHE BOOL "" FORCE)
23+
24+
FetchContent_Declare(
25+
glfw
26+
GIT_REPOSITORY https://github.com/glfw/glfw.git
27+
GIT_TAG 3.4
28+
GIT_SHALLOW TRUE)
29+
30+
set(BGFX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
31+
set(BGFX_BUILD_TOOLS OFF CACHE BOOL "" FORCE)
32+
set(BGFX_INSTALL OFF CACHE BOOL "" FORCE)
33+
34+
FetchContent_Declare(
35+
bgfx
36+
GIT_REPOSITORY https://github.com/bkaradzic/bgfx.cmake.git
37+
GIT_TAG v1.150.9365-558
38+
GIT_SHALLOW TRUE)
39+
40+
FetchContent_MakeAvailable(glfw bgfx)
41+
42+
enable_language(TSLANG)
43+
44+
setup_tslang_link_paths()
45+
46+
if(CMAKE_BUILD_TYPE STREQUAL "Release")
47+
set(CMAKE_TSLANG_FLAGS "--opt --opt_level=3")
48+
else()
49+
set(CMAKE_TSLANG_FLAGS "--di --opt_level=0")
50+
endif()
51+
52+
if(WIN32)
53+
else()
54+
set(CMAKE_TSLANG_FLAGS "${CMAKE_TSLANG_FLAGS} -relocation-model=pic")
55+
endif()
56+
57+
add_executable(${PROJECT_NAME}
58+
src/main.ts
59+
src/application.ts
60+
src/appwindow.ts
61+
native/bgfx_bridge.cpp
62+
native/main_entry.cpp)
63+
64+
target_include_directories(${PROJECT_NAME} PRIVATE native)
65+
66+
set(TSLANG_LINK_LIBS
67+
TypeScriptDefaultLib
68+
TypeScriptAsyncRuntime
69+
gc
70+
LLVMSupport)
71+
72+
if(WIN32)
73+
list(APPEND TSLANG_LINK_LIBS ntdll)
74+
else()
75+
find_library(TSLANG_TINFO_LIB NAMES tinfo)
76+
list(APPEND TSLANG_LINK_LIBS LLVMDemangle stdc++ m pthread dl rt)
77+
if(TSLANG_TINFO_LIB)
78+
list(APPEND TSLANG_LINK_LIBS ${TSLANG_TINFO_LIB})
79+
else()
80+
list(APPEND TSLANG_LINK_LIBS tinfo)
81+
endif()
82+
endif()
83+
84+
target_link_libraries(${PROJECT_NAME}
85+
PRIVATE
86+
glfw
87+
bgfx
88+
bx
89+
bimg
90+
${TSLANG_LINK_LIBS})
91+
92+
if(UNIX AND NOT APPLE)
93+
find_package(X11 REQUIRED)
94+
target_link_libraries(${PROJECT_NAME} PRIVATE X11::X11)
95+
endif()
96+
97+
add_custom_target(run
98+
COMMAND "$<TARGET_FILE:${PROJECT_NAME}>"
99+
DEPENDS ${PROJECT_NAME}
100+
USES_TERMINAL
101+
COMMENT "Running ${PROJECT_NAME}")
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"version": 3,
3+
"cmakeMinimumRequired": {
4+
"major": 3,
5+
"minor": 20,
6+
"patch": 0
7+
},
8+
"configurePresets": [
9+
{
10+
"name": "default",
11+
"displayName": "Default (Ninja)",
12+
"description": "TSLANG custom language requires the Ninja generator.",
13+
"generator": "Ninja",
14+
"binaryDir": "${sourceDir}/build",
15+
"cacheVariables": {
16+
"CMAKE_BUILD_TYPE": "Release",
17+
"TSLANG_ROOT": "${sourceDir}/../../../__build"
18+
}
19+
},
20+
{
21+
"name": "debug",
22+
"displayName": "Debug (Ninja)",
23+
"generator": "Ninja",
24+
"binaryDir": "${sourceDir}/build-debug",
25+
"cacheVariables": {
26+
"CMAKE_BUILD_TYPE": "Debug",
27+
"TSLANG_ROOT": "${sourceDir}/../../../__build"
28+
}
29+
}
30+
],
31+
"buildPresets": [
32+
{
33+
"name": "default",
34+
"configurePreset": "default"
35+
},
36+
{
37+
"name": "debug",
38+
"configurePreset": "debug"
39+
}
40+
]
41+
}

docs/how/cmake_bgfx/README.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# bgfx + GLFW TypeScript sample
2+
3+
Cross-platform graphics sample for the TypeScript native compiler (`tslang`). Application logic is written in TypeScript; GLFW windowing and bgfx rendering live in a thin C++ bridge exposed through `.d.ts` FFI declarations.
4+
5+
Control flow matches [`cmake_vulkan`](../cmake_vulkan/) and [`cmake_winapp`](../cmake_winapp/): **C++ owns the event loop**, TypeScript creates the window and reacts via an `onMessage` callback.
6+
7+
## What it does
8+
9+
- Opens an 800x600 GLFW window (no client API — bgfx owns rendering)
10+
- Initializes bgfx with the native window handle (Win32, X11, or Cocoa)
11+
- C++ `run_loop()` polls GLFW and dispatches `Messages.Frame` each iteration
12+
- TypeScript `onMessage` calls `run_bgfx_frame()` on Frame (like `run_vulkan()` on Paint)
13+
- Renders an animated clear color and on-screen debug text: "Hello from tslang"
14+
- Quits on Escape or window close
15+
16+
## Prerequisites
17+
18+
1. **Built `tslang`** — follow the main [README](../../../README.md) to build the compiler and install the default library (`tslang --install-default-lib`).
19+
2. **CMake 3.20+** and **Ninja** (required for the custom `TSLANG` CMake language).
20+
3. **C++20** toolchain (GCC, Clang, or MSVC).
21+
4. **Graphics drivers** — bgfx auto-selects an available backend (OpenGL, Vulkan, DirectX on Windows).
22+
23+
### Linux packages (Fedora example)
24+
25+
```bash
26+
sudo dnf install cmake ninja-build gcc-c++ ncurses-devel \
27+
libX11-devel libXcursor-devel libXi-devel libXrandr-devel \
28+
libXinerama-devel libXxf86vm-devel mesa-libGL-devel
29+
```
30+
31+
### Windows
32+
33+
- Visual Studio 2022+ with C++ workload, CMake, and Ninja.
34+
- Ensure `tslang.exe` is on `PATH` or pass `-DTSLANG_ROOT=...` pointing at the folder that contains `bin/tslang.exe`.
35+
36+
## Layout
37+
38+
```
39+
cmake_bgfx/
40+
├── CMakeLists.txt # FetchContent GLFW + bgfx, mixed TS/C++ target
41+
├── CMakePresets.json
42+
├── cmake/ # TSLANG custom language modules
43+
├── src/
44+
│ ├── main.ts # entry point (Main)
45+
│ ├── application.ts # constructs AppWindow only
46+
│ ├── appwindow.ts # onMessage handler (Frame / KeyDown / Close / Destroy)
47+
│ └── bgfx_glfw.d.ts # FFI declarations
48+
└── native/
49+
├── bgfx_bridge.cpp # extern "C" GLFW + bgfx glue + run_loop()
50+
└── main_entry.cpp # main() -> Main() -> run_loop()
51+
```
52+
53+
## Build and run
54+
55+
### Linux
56+
57+
```bash
58+
cd docs/how/cmake_bgfx
59+
60+
cmake --preset default
61+
# or explicitly:
62+
# cmake --preset default -DTSLANG_ROOT=/path/to/TypeScriptCompiler/__build
63+
64+
cmake --build --preset default
65+
cmake --build --target run
66+
```
67+
68+
Binary: `build/cmake_bgfx`
69+
70+
If CMake reports `tslang compiler not found`, build the compiler from the repo root first:
71+
72+
```bash
73+
./prepare_3rdParty_release.sh
74+
cd tslang && ./config_tslang_release.sh && ./build_tslang_release.sh
75+
./bin/tslang --install-default-lib
76+
```
77+
78+
Then re-run `cmake --preset default` from `docs/how/cmake_bgfx`.
79+
80+
### Windows
81+
82+
```bat
83+
cd docs\how\cmake_bgfx
84+
85+
cmake --preset default -DTSLANG_ROOT=C:\path\to\TypeScriptCompiler\__build
86+
cmake --build --preset default
87+
cmake --build --target run
88+
```
89+
90+
Binary: `build\cmake_bgfx.exe`
91+
92+
### macOS
93+
94+
Same CMake flow as Linux. Requires Xcode command-line tools and a working OpenGL/Metal backend for bgfx.
95+
96+
### Debug build
97+
98+
```bash
99+
cmake --preset debug
100+
cmake --build --preset debug
101+
```
102+
103+
## How it works
104+
105+
1. **`main_entry.cpp`** calls TypeScript `Main()`, then C++ `run_loop()`.
106+
2. **`Main()`** constructs `AppWindow`, which registers `onMessage` and calls `create_bgfx`.
107+
3. **`run_loop()`** polls GLFW, dispatches `Messages.Frame` each tick, then `Messages.Destroy` on exit.
108+
4. **CMake `TSLANG` language** compiles `.ts` sources to object files with `tslang --emit=obj`.
109+
5. **`bgfx_bridge.cpp`** implements the flat `extern "C"` API declared in `bgfx_glfw.d.ts`.
110+
6. **FetchContent** downloads GLFW 3.4 and [bgfx.cmake](https://github.com/bkaradzic/bgfx.cmake) on first configure.
111+
112+
## Platform notes
113+
114+
| Platform | Window backend | Notes |
115+
|----------|----------------|-------|
116+
| Windows | Win32 (`glfwGetWin32Window`) | bgfx D3D11/D3D12/OpenGL/Vulkan |
117+
| Linux | X11 (`glfwGetX11Display` / `glfwGetX11Window`) | Wayland disabled (`GLFW_BUILD_WAYLAND=OFF`) |
118+
| macOS | Cocoa (`glfwGetCocoaWindow`) | OpenGL/Metal via bgfx |
119+
120+
## Related samples
121+
122+
- [`cmake_winapp`](../cmake_winapp/) — Win32 window only (C++ message loop)
123+
- [`cmake_vulkan`](../cmake_vulkan/) — Win32 + Vulkan cube (same onMessage pattern)
124+
- [`cmake_tslang`](../cmake_tslang/) — mixed C++/TypeScript with custom CMake language
125+
- [`c-cpp-header-import.md`](../../c-cpp-header-import.md) — FFI / native binding design
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
include(${CMAKE_CURRENT_LIST_DIR}/LocateTSLang.cmake)
2+
3+
if(NOT CMAKE_TSLANG_COMPILER OR NOT EXISTS "${CMAKE_TSLANG_COMPILER}")
4+
locate_tslang_compiler()
5+
set(CMAKE_TSLANG_COMPILER "${CMAKE_TSLANG_COMPILER}" CACHE FILEPATH "TSLANG compiler" FORCE)
6+
endif()
7+
8+
cmake_path(GET CMAKE_TSLANG_COMPILER PARENT_PATH CMAKE_TSLANG_DIR)
9+
10+
mark_as_advanced(CMAKE_TSLANG_COMPILER)
11+
mark_as_advanced(CMAKE_TSLANG_DIR)
12+
13+
set(CMAKE_TSLANG_SOURCE_FILE_EXTENSIONS ts)
14+
if(NOT WIN32)
15+
set(CMAKE_TSLANG_OUTPUT_EXTENSION .o)
16+
else()
17+
set(CMAKE_TSLANG_OUTPUT_EXTENSION .obj)
18+
endif()
19+
set(CMAKE_TSLANG_COMPILER_ENV_VAR "TSLANG")
20+
21+
configure_file(
22+
${CMAKE_CURRENT_LIST_DIR}/CMakeTSLANGCompiler.cmake.in
23+
${CMAKE_PLATFORM_INFO_DIR}/CMakeTSLANGCompiler.cmake @ONLY)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
set(CMAKE_TSLANG_COMPILER "@CMAKE_TSLANG_COMPILER@")
2+
set(CMAKE_TSLANG_DIR "@CMAKE_TSLANG_DIR@")
3+
set(CMAKE_TSLANG_SOURCE_FILE_EXTENSIONS @CMAKE_TSLANG_SOURCE_FILE_EXTENSIONS@)
4+
set(CMAKE_TSLANG_OUTPUT_EXTENSION @CMAKE_TSLANG_OUTPUT_EXTENSION@)
5+
set(CMAKE_TSLANG_COMPILER_LOADED 1)
6+
set(CMAKE_TSLANG_COMPILER_WORKS TRUE)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# bx propagates -msse4.2 via PUBLIC compile options on GCC/Clang. tslang does
2+
# not accept those flags, so filter them through a small wrapper on Unix.
3+
get_filename_component(_TSLANG_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
4+
set(_TSLANG_COMPILE_TEMPLATE
5+
"<CMAKE_TSLANG_COMPILER> <FLAGS> --default-lib-path=${CMAKE_TSLANG_DIR} --emit=obj --export=none -o=<OBJECT> <SOURCE>")
6+
if(NOT CMAKE_TSLANG_COMPILE_OBJECT)
7+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
8+
set(CMAKE_TSLANG_COMPILE_OBJECT
9+
"${_TSLANG_CMAKE_DIR}/tslang_compile.sh ${_TSLANG_COMPILE_TEMPLATE}")
10+
else()
11+
set(CMAKE_TSLANG_COMPILE_OBJECT "${_TSLANG_COMPILE_TEMPLATE}")
12+
endif()
13+
endif()
14+
15+
if(NOT CMAKE_TSLANG_LINK_EXECUTABLE)
16+
set(CMAKE_TSLANG_LINK_EXECUTABLE
17+
"<CMAKE_CXX_COMPILER> <FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
18+
endif()
19+
20+
set(CMAKE_TSLANG_INFORMATION_LOADED 1)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
set(CMAKE_TSLANG_COMPILER_WORKS TRUE)

0 commit comments

Comments
 (0)