Skip to content

Commit

Permalink
Initial C++ engine and Typescript web package
Browse files Browse the repository at this point in the history
Web package is based on Typescript, React and Vite. Engine is compiled
to WASM.

Initial page has two tabs:

  * Home, the game page, with a 2D canvas
  * Blank, a blank page with a retro red background
  • Loading branch information
juztamau5 committed Mar 13, 2024
1 parent 737d3f7 commit 6fe7b71
Show file tree
Hide file tree
Showing 32 changed files with 3,944 additions and 0 deletions.
109 changes: 109 additions & 0 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
################################################################################
#
# Copyright (C) 2023-2024 retro.ai
# This file is part of retro3 - https://github.com/retroai/retro3
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# See the file LICENSE.txt for more information.
#
################################################################################

name: Node.js CI

on: [push, pull_request]

jobs:
build-and-deploy:
# The type of runner that the job will run on
runs-on: ${{ matrix.os }}

defaults:
run:
# Set the working directory to frontend folder
working-directory: src/frontend

strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-20.04
node-version: 20
- os: ubuntu-22.04
node-version: 21

steps:
- name: Checkout 🛎️
uses: actions/checkout@v4

- name: Cache vite build files
id: cache-vite
uses: actions/cache@v4
with:
path: |
src/frontend/dist
key: cache-vite-${{ matrix.os }}-${{ matrix.node-version }}-${{ hashFiles('src/frontend/**') }}

- name: Cache pnpm modules
id: cache-modules
uses: actions/cache@v4
with:
path: |
src/frontend/node_modules
key: cache-modules-${{ matrix.os }}-${{ matrix.node-version }}-${{ hashFiles('src/frontend/pnpm-lock.yaml') }}

- name: Cache emsdk
id: cache-emsdk
uses: actions/cache@v4
with:
path: |
tools/emsdk
key: cache-emsdk-${{ hashFiles('tools/download-emscripten.sh') }}

- name: Cache WASM libraries
id: cache-wasm
uses: actions/cache@v4
with:
path: |
src/frontend/public/wasm
src/frontend/src/wasm
key: cache-wasm-${{ matrix.os }}-${{ matrix.node-version }}-${{ hashFiles('src/engine/**', 'tools/build-wasm.sh', 'tools/download-emscripten.sh') }}

- name: Install emsdk
if: steps.cache-emsdk.outputs.cache-hit != 'true'
run: |
./download-emscripten.sh
working-directory: tools

- name: Build wasm libraries
if: steps.cache-wasm.outputs.cache-hit != 'true'
run: |
./build-wasm.sh
working-directory: tools

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install pnpm
run: |
npm install -g pnpm
- name: pnpm install
if: steps.cache-modules.outputs.cache-hit != 'true'
run: |
pnpm install
- name: pnpm audit-ci
run: |
pnpm audit-ci
- name: pnpm lint
if: steps.cache-vite.outputs.cache-hit != 'true'
run: |
pnpm lint
- name: pnpm build
if: steps.cache-vite.outputs.cache-hit != 'true'
run: |
pnpm build
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ The following subfolders compose the repo architecture:

* `src/backend/` - The Cartesi Machine logic
* `src/frontend/` - The website and frontend logic
* `src/engine/` - The main emulator engine
* `src/learning/` - The Python code for AI agents
* `tools/` - Tooling for dependencies

Expand Down
78 changes: 78 additions & 0 deletions src/engine/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
################################################################################
#
# Copyright (C) 2024 retro.ai
# This file is part of retro3 - https://github.com/retroai/retro3
#
# SPDX-License-Identifier: AGPL-3.0-or-later
# See the file LICENSE.txt for more information.
#
################################################################################

################################################################################
# Project settings
################################################################################

project(retro_engine LANGUAGES CXX)
cmake_minimum_required(VERSION 3.10)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

################################################################################
# Dependencies
################################################################################

# TODO

################################################################################
# Sources
################################################################################

set(SOURCE_FILES
core/retro_engine.cpp
core/retro_engine_embinder.cpp
)

################################################################################
# Libraries
################################################################################

# Add the executable based on the source files
add_executable(retro_engine ${SOURCE_FILES})

# Add flags for Empscripten builds
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
set_target_properties(retro_engine PROPERTIES
COMPILE_FLAGS " \
-O3 \
"
# 26214400 is 25 MiB
LINK_FLAGS " \
-gsource-map \
-s ALLOW_MEMORY_GROWTH=1 \
-s EXPORT_ES6=1 \
-s INITIAL_MEMORY=26214400 \
-s MODULARIZE=1 \
-s USE_WEBGL2=1 \
-s WASM=1 \
--bind \
--embind-emit-tsd retro_engine.d.ts \
--source-map-base https://retro.ai/ \
"
)
endif ()

################################################################################
# Install
################################################################################

INSTALL(
FILES
"${CMAKE_BINARY_DIR}/retro_engine.d.ts"
"${CMAKE_BINARY_DIR}/retro_engine.js"
"${CMAKE_BINARY_DIR}/retro_engine.wasm"
"${CMAKE_BINARY_DIR}/retro_engine.wasm.map"
DESTINATION
wasm
)
90 changes: 90 additions & 0 deletions src/engine/core/retro_engine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2024 retro.ai
* This file is part of retro3 - https://github.com/retroai/retro3
*
* SPDX-License-Identifier: AGPL-3.0-or-later
* See the file LICENSE.txt for more information.
*/

#include "retro_engine.hpp"

#include <iostream>
#include <stdexcept>
#include <string>

#include <GLES3/gl3.h>

namespace
{
constexpr const char* CANVAS_ID = "#retroEngine";
}

RetroEngine::RetroEngine() : m_webGLContext(0)
{
}

RetroEngine::~RetroEngine()
{
Deinitialize();
}

bool RetroEngine::Initialize()
{
if (!InitializeWebGL())
return false;

return true;
}

void RetroEngine::Deinitialize()
{
DeinitializeWebGL();
}

bool RetroEngine::InitializeWebGL()
{
EmscriptenWebGLContextAttributes attrs;
emscripten_webgl_init_context_attributes(&attrs);

attrs.alpha = EM_TRUE;
attrs.depth = EM_TRUE;
attrs.stencil = EM_TRUE;
attrs.antialias = EM_TRUE;
attrs.preserveDrawingBuffer = EM_FALSE;
attrs.powerPreference = EM_WEBGL_POWER_PREFERENCE_HIGH_PERFORMANCE;
attrs.failIfMajorPerformanceCaveat = EM_FALSE;
attrs.majorVersion = 2;
attrs.minorVersion = 0;

const EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context =
emscripten_webgl_create_context(CANVAS_ID, &attrs);
if (context <= 0)
throw std::runtime_error("Failed to create WebGL context");

EMSCRIPTEN_RESULT result = emscripten_webgl_make_context_current(context);
if (result != EMSCRIPTEN_RESULT_SUCCESS)
throw std::runtime_error("Failed to make WebGL context current: " + std::to_string(result));

// Success
m_webGLContext = context;

// Set the clear color to black (RGBA)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);

return true;
}

void RetroEngine::DeinitializeWebGL()
{
if (m_webGLContext > 0)
{
EMSCRIPTEN_RESULT result = emscripten_webgl_destroy_context(m_webGLContext);
if (result != EMSCRIPTEN_RESULT_SUCCESS)
std::cerr << "Failed to destroy WebGL context (result=" << result << ")" << std::endl;

m_webGLContext = 0;
}
}
36 changes: 36 additions & 0 deletions src/engine/core/retro_engine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2024 retro.ai
* This file is part of retro3 - https://github.com/retroai/retro3
*
* SPDX-License-Identifier: AGPL-3.0-or-later
* See the file LICENSE.txt for more information.
*/

#pragma once

#include <emscripten/html5.h>

class RetroEngine
{
public:
RetroEngine();
~RetroEngine();

/*!
* \brief Initialize the engine
*
* \return true if successful, false otherwise
*/
bool Initialize();

/*!
* \brief Deinitialize the engine
*/
void Deinitialize();

private:
bool InitializeWebGL();
void DeinitializeWebGL();

EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_webGLContext;
};
19 changes: 19 additions & 0 deletions src/engine/core/retro_engine_embinder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2024 retro.ai
* This file is part of retro3 - https://github.com/retroai/retro3
*
* SPDX-License-Identifier: AGPL-3.0-or-later
* See the file LICENSE.txt for more information.
*/

#include "retro_engine.hpp"

#include <emscripten/bind.h>

EMSCRIPTEN_BINDINGS(engine)
{
emscripten::class_<RetroEngine>("RetroEngine")
.constructor<>()
.function("initialize", &RetroEngine::Initialize)
.function("deinitialize", &RetroEngine::Deinitialize);
}
8 changes: 8 additions & 0 deletions src/frontend/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Node
/dist
/node_modules
/pnpm-lock.yaml

# Generated WASM files
/public/wasm
/src/wasm
17 changes: 17 additions & 0 deletions src/frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "simple-import-sort"],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"env": {
"browser": true,
"es2020": true,
"mocha": true,
"node": true
},
"rules": {
"brace-style": ["error", "1tbs", { "allowSingleLine": false }],
"curly": ["error", "all"],
"simple-import-sort/imports": "error"
}
}
8 changes: 8 additions & 0 deletions src/frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Node
/dist
/node_modules
/yarn-*.log*

# Generated WASM files
/public/wasm
/src/wasm
8 changes: 8 additions & 0 deletions src/frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Generated by Node
/dist
/node_modules
/pnpm-lock.yaml

# Generated WASM files
/public/wasm
/src/wasm
3 changes: 3 additions & 0 deletions src/frontend/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"tabWidth": 2
}
Loading

0 comments on commit 6fe7b71

Please sign in to comment.