add wasm support

This commit is contained in:
Rokas Puzonas 2023-07-20 03:10:09 +03:00
parent 4173d1f369
commit 63627d9c7a
8 changed files with 247 additions and 107 deletions

4
.gitignore vendored
View File

@ -1,3 +1 @@
include
lib
bin
build

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "depends/raylib"]
path = depends/raylib
url = https://github.com/raysan5/raylib
[submodule "depends/emsdk"]
path = depends/emsdk
url = git@github.com:emscripten-core/emsdk.git

172
Makefile
View File

@ -1,102 +1,134 @@
# Copyright (c) 2020 Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr)
#
# This code is released under an unmodified zlib license.
# For conditions of distribution and use, please see:
# https://opensource.org/licenses/Zlib
# ------------------------ Config -----------------------
# Define custom functions
rwildcard = $(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
platformpth = $(subst /,$(PATHSEP),$1)
# PLATFORM can be 'web' or 'desktop'
PLATFORM ?= desktop
# Set global macros
buildDir := bin
executable := app
target := $(buildDir)/$(executable)
sources := $(call rwildcard,src/,*.cpp)
objects := $(patsubst src/%, $(buildDir)/%, $(patsubst %.cpp, %.o, $(sources)))
depends := $(patsubst %.o, %.d, $(objects))
compileFlags := -std=c++17 -I include
linkFlags = -L lib/$(platform) -l raylib
SHELL := /bin/zsh
TOP_BUILD_DIR := build
EXECUTABLE := app
WEB_SHELL := src/shell.html
SUBMODULES_PATH := depends
COMPILER_FLAGS := -std=c++17
LINKER_FLAGS := -lraylib
SOURCES := $(wildcard src/*.cpp)
# ----------------- Prepare variables for targets ------------------
EXT :=
EMSDK_PATH := $(SUBMODULES_PATH)/emsdk
RAYLIB_PLATFORM := PLATFORM_DESKTOP
# Check for Windows
ifeq ($(OS), Windows_NT)
# Set Windows macros
platform := Windows
CXX ?= g++
linkFlags += -Wl,--allow-multiple-definition -pthread -lopengl32 -lgdi32 -lwinmm -mwindows -static -static-libgcc -static-libstdc++
libGenDir := src
THEN := &&
PATHSEP := \$(BLANK)
MKDIR := -mkdir -p
RM := -del /q
COPY = -robocopy "$(call platformpth,$1)" "$(call platformpth,$2)" $3
else
# Check for MacOS/Linux
UNAMEOS := $(shell uname)
ifeq ($(UNAMEOS), Linux)
# Set Linux macros
platform := Linux
CXX ?= g++
linkFlags += -l GL -l m -l pthread -l dl -l rt -l X11
endif
ifeq ($(UNAMEOS), Darwin)
# Set macOS macros
platform := macOS
CXX ?= clang++
linkFlags += -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL
libGenDir := src
endif
COPY = -robocopy "$1" "$2" $3
EXT = .exe
MOVE := move
# Set UNIX macros
OS_NAME := windows
LINKER_FLAGS += -Wl,--allow-multiple-definition -pthread -lopengl32
LINKER_FLAGS += -lgdi32 -lwinmm -mwindows -static -static-libgcc -static-libstdc++
else
CXX ?= g++
THEN := ;
PATHSEP := /
MKDIR := mkdir -p
RM := rm -rf
COPY = cp $1$(PATHSEP)$3 $2
COPY = cp $1/$3 $2
MOVE := mv
OS_NAME := linux
LINKER_FLAGS += -lGL -lm -lpthread -ldl -lrt -lX11
endif
# Lists phony targets for Makefile
.PHONY: all setup submodules execute clean
BUILD_NAME := $(OS_NAME)-$(PLATFORM)
BUILD_DIR := $(TOP_BUILD_DIR)/$(BUILD_NAME)
RAYLIB_RELEASE_PATH := $(TOP_BUILD_DIR)/raylib-$(BUILD_NAME)
# Default target, compiles, executes and cleans
all: $(target) execute clean
OBJECTS := $(patsubst src/%, $(BUILD_DIR)/%, $(patsubst %.cpp, %.o, $(SOURCES)))
OBJECT_DEPENDS := $(patsubst %.o, %.d, $(OBJECTS))
LIB_DEPENDENCIES :=
ifeq ($(PLATFORM), web)
export EMSDK_QUIET=1
RAYLIB_PLATFORM := PLATFORM_WEB
CXX := source $(SUBMODULES_PATH)/emsdk/emsdk_env.sh $(THEN) emcc
EXT = .html
EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten
COMPILER_FLAGS += -I$(EMSCRIPTEN_PATH)/cache/sysroot/include
LINKER_FLAGS += -s USE_GLFW=3
LINKER_FLAGS += -s FORCE_FILESYSTEM=1
LINKER_FLAGS += $(RAYLIB_RELEASE_PATH)/libraylib.a
LINKER_FLAGS += --shell-file $(WEB_SHELL)
LIB_DEPENDENCIES += emsdk
endif
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib-cpp/include
COMPILER_FLAGS += -I$(SUBMODULES_PATH)/raylib/src
LINKER_FLAGS += -L$(RAYLIB_RELEASE_PATH)
MAIN_TARGET := $(BUILD_DIR)/$(EXECUTABLE)$(EXT)
# ------------------------ Targets -----------------------
# Add all rules from dependency files
-include $(OBJECT_DEPENDS)
.DEFAULT_GOAL := all
# Lists phony targets for Makefile
.PHONY: all setup submodules run clean emsdk
# Default target, compiles, runss and cleans
all: clean $(MAIN_TARGET) run
# Sets up the project for compiling, generates includes and libs
setup: include lib
setup: lib
# Pull and update the the build submodules
submodules:
git submodule update --init --recursive
# Copy the relevant header files into includes
include: submodules
$(MKDIR) $(call platformpth, ./include)
$(call COPY,depends/raylib/src,./include,raylib.h)
$(call COPY,depends/raylib/src,./include,raymath.h)
$(call COPY,depends/raylib-cpp/include,./include,*.hpp)
# Build the raylib static library file and copy it into lib
lib: submodules
cd depends/raylib/src $(THEN) "$(MAKE)" PLATFORM=PLATFORM_DESKTOP
$(MKDIR) $(call platformpth, lib/$(platform))
$(call COPY,depends/raylib/src/$(libGenDir),lib/$(platform),libraylib.a)
lib: submodules $(LIB_DEPENDENCIES)
$(MKDIR) $(RAYLIB_RELEASE_PATH)
cd $(SUBMODULES_PATH)/raylib/src $(THEN) \
"$(MAKE)" \
PLATFORM=$(RAYLIB_PLATFORM) \
EMSDK_PATH=$(EMSDK_PATH) \
RAYLIB_RELEASE_PATH=../../../$(RAYLIB_RELEASE_PATH) -B
# Install and activate emscripten
emsdk: submodules
cd $(SUBMODULES_PATH)/emsdk $(THEN) ./emsdk install latest
cd $(SUBMODULES_PATH)/emsdk $(THEN) ./emsdk activate latest
# source $(SUBMODULES_PATH)/emsdk/emsdk_env.sh
# Link the program and create the executable
$(target): $(objects)
$(CXX) $(objects) -o $(target) $(linkFlags)
# Add all rules from dependency files
-include $(depends)
$(MAIN_TARGET): $(OBJECTS)
$(CXX) $(OBJECTS) -o $(MAIN_TARGET) $(LINKER_FLAGS) -D$(RAYLIB_PLATFORM)
ifeq ($(PLATFORM), web)
$(MOVE) $(MAIN_TARGET) $(BUILD_DIR)/index.html
endif
# Compile objects to the build directory
$(buildDir)/%.o: src/%.cpp Makefile
$(MKDIR) $(call platformpth, $(@D))
$(CXX) -MMD -MP -c $(compileFlags) $< -o $@ $(CXXFLAGS)
$(BUILD_DIR)/%.o: src/%.cpp Makefile
$(MKDIR) $(BUILD_DIR)
# \
$(CXX) -MMD -MP -c $(COMPILER_FLAGS) $< -o $@ $(CXXFLAGS) -D$(RAYLIB_PLATFORM)
# Run the executable
execute:
$(target) $(ARGS)
run:
ifeq ($(PLATFORM), web)
python -m http.server 8080 -d $(BUILD_DIR)
else
$(MAIN_TARGET) $(ARGS)
endif
# Clean up all relevant files
clean:
$(RM) $(call platformpth, $(buildDir)/*)
$(RM) $(BUILD_DIR)

View File

@ -28,12 +28,24 @@ $ make setup
$ make
```
For web:
```console
$ make setup PLATFORM=web
$ make PLATFORM=web
```
#### Windows
```console
> mingw32-make setup
> mingw32-make
```
For web:
```console
> mingw32-make setup PLATFORM=web
> mingw32-make PLATFORM=web
```
The first command will clone in the lastest C++ bindings and targeted version of raylib, copy across any relevant header files into `/includes`, and build a static library file from them, placing it in `/lib`. The second command then compiles, runs and cleans up your project using the source code in `/src/main.cpp`.
*If a window pops up, congratulations, you've successfully built the project and you can now start programming your game!*
@ -51,13 +63,13 @@ By using the following Make commands instead of the default target, we can skip
#### macOS & Linux
```console
$ make bin/app; make execute
$ make build/app; make run
```
#### Windows
```console
> mingw32-make bin/app && mingw32-make execute
> mingw32-make build/app && mingw32-make run
```
Using this method can save you a huge amount of time compiling *(in reality, just a few seconds)* each time you make a small change to your code! If you want to know more about how it works, you should have a read through [the docs entry explaining the Makefile](docs/MakefileExplanation.md).
@ -114,18 +126,7 @@ $ make CXX=g++
> mingw32-make CXX=g++
```
## Contributing
### How do I contribute?
It's pretty simple actually:
1. Fork it from [here](https://github.com/CapsCollective/raylib-cpp-starter/fork)
2. Create your feature branch (`git checkout -b cool-new-feature`)
3. Commit your changes (`git commit -m "Added some feature"`)
4. Push to the branch (`git push origin cool-new-feature`)
5. Create a new pull request for it!
### Contributors
## Contributors
- [J-Mo63](https://github.com/J-Mo63) Jonathan Moallem - co-creator, maintainer
- [Raelr](https://github.com/Raelr) Aryeh Zinn - co-creator, maintainer
- [mTvare6](https://github.com/mTvare6) mTvare6 - contributor

2
compile_flags.txt Normal file
View File

@ -0,0 +1,2 @@
-Idepends/raylib-cpp/include/
-Idepends/raylib/src/

1
depends/emsdk Submodule

@ -0,0 +1 @@
Subproject commit b6df670bdb7cc696804495306e99a604f6641b38

View File

@ -1,29 +1,36 @@
#include <raylib-cpp.hpp>
#ifdef PLATFORM_WEB
#include <emscripten/emscripten.h>
#endif
void UpdateDrawFrame() {
// Update
// Draw
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);
EndDrawing();
}
int main() {
// Initialization
int screenWidth = 800;
int screenHeight = 450;
int screen_width = 800;
int screen_height = 450;
raylib::Color textColor(LIGHTGRAY);
raylib::Window w(screenWidth, screenHeight, "Raylib C++ Starter Kit Example");
raylib::Window window(screen_width, screen_height, "Raylib C++ Starter Kit");
#ifdef PLATFORM_WEB
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
#else
SetTargetFPS(60);
// Main game loop
while (!w.ShouldClose()) // Detect window close button or ESC key
{
// Update
// TODO: Update your variables here
// Draw
BeginDrawing();
ClearBackground(RAYWHITE);
textColor.DrawText("Congrats! You created your first window!", 190, 200, 20);
EndDrawing();
while (!window.ShouldClose()) {
UpdateDrawFrame();
}
#endif
window.Close();
return 0;
}
}

96
src/shell.html Normal file
View File

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>raylib web game</title>
<meta name="title" content="raylib web game">
<meta name="description" content="New raylib web videogame, developed using raylib videogames library">
<meta name="keywords" content="raylib, games, html5, programming, C, C++, library, learn, videogames">
<meta name="viewport" content="width=device-width">
<!-- Open Graph metatags for sharing -->
<meta property="og:title" content="raylib web game">
<meta property="og:image:type" content="image/png">
<meta property="og:image" content="https://www.raylib.com/common/img/raylib_logo.png">
<meta property="og:site_name" content="raylib.com">
<meta property="og:url" content="https://www.raylib.com/games.html">
<meta property="og:description" content="New raylib web videogame, developed using raylib videogames library">
<!-- Twitter metatags for sharing -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@raysan5">
<meta name="twitter:title" content="raylib web game">
<meta name="twitter:image" content="https://www.raylib.com/common/raylib_logo.png">
<meta name="twitter:url" content="https://www.raylib.com/games.html">
<meta name="twitter:description" content="New raylib web game, developed using raylib videogames library">
<!-- Favicon -->
<link rel="shortcut icon" href="https://www.raylib.com/favicon.ico">
<style>
body {
width: 100vw;
height: 100vh;
margin: 0px;
background-color: rgb(245, 245, 245);
}
canvas.emscripten {
position: relative;
left: 50%;
top: 50%;
border: 3px solid #000000;
transform: translate(-50%, -50%);
background-color: black;
}
</style>
<script type='text/javascript' src="https://cdn.jsdelivr.net/gh/eligrey/FileSaver.js/dist/FileSaver.min.js"> </script>
<script type='text/javascript'>
function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code
{
var isSafari = false; // Not supported, navigator.userAgent access is being restricted
//var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
var data = FS.readFile(memoryFSname);
var blob;
if (isSafari) blob = new Blob([data.buffer], { type: "application/octet-stream" });
else blob = new Blob([data.buffer], { type: "application/octet-binary" });
// NOTE: SaveAsDialog is a browser setting. For example, in Google Chrome,
// in Settings/Advanced/Downloads section you have a setting:
// 'Ask where to save each file before downloading' - which you can set true/false.
// If you enable this setting it would always ask you and bring the SaveAsDialog
saveAs(blob, localFSname);
}
</script>
</head>
<body>
<canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas>
<p id="output" />
<script>
var Module = {
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
canvas: (function() {
var canvas = document.getElementById('canvas');
return canvas;
})()
};
</script>
{{{ SCRIPT }}}
</body>
</html>