Skip to content

Commit

Permalink
WIP native api
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitriySalnikov committed Sep 15, 2024
1 parent 3a608c1 commit 551c4b1
Show file tree
Hide file tree
Showing 17 changed files with 618 additions and 56 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ cmake_build_out/*
src/gen/*
src/editor/my_telemetry_modules
addons/debug_draw_3d/gen/
addons/debug_draw_3d/native_api/
clang_rt.asan_*
docs/images/classes/temp/
SUCCESS
38 changes: 34 additions & 4 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ from SCons.Script.SConscript import SConsEnvironment

import SCons, SCons.Script
import sys, os, platform
import lib_utils, lib_utils_external
import lib_utils, lib_utils_external, lib_utils_gen_dd3d_api

# Fixing the encoding of the console
if platform.system() == "Windows":
Expand Down Expand Up @@ -45,6 +45,7 @@ def setup_options(env: SConsEnvironment, arguments):
)
)

opts.Add(BoolVariable("build_cpp_api_tests", "Build only cpp api tests", False))
opts.Add(BoolVariable("telemetry_enabled", "Enable the telemetry module", False))
opts.Add(BoolVariable("tracy_enabled", "Enable tracy profiler", False))
opts.Add(BoolVariable("force_enabled_dd3d", "Keep the rendering code in the release build", False))
Expand Down Expand Up @@ -132,6 +133,10 @@ def apply_patches(target, source, env: SConsEnvironment):
return lib_utils_external.apply_git_patches(env, patches_to_apply, "godot-cpp")


def gen_apis(target, source, env: SConsEnvironment):
return lib_utils_gen_dd3d_api.gen_apis(env, os.path.join(os.path.dirname(env["addon_output_dir"]), "native_api"))


def get_android_toolchain() -> str:
sys.path.insert(0, "godot-cpp/tools")
import android
Expand Down Expand Up @@ -170,10 +175,35 @@ extra_tags = ""
if "release" in env["target"] and env["force_enabled_dd3d"]:
extra_tags += ".enabled"

lib_utils.get_library_object(
env, project_name, lib_name, extra_tags, env["addon_output_dir"], src_folder, additional_src
)
if not env["build_cpp_api_tests"]:
lib_utils.get_library_object(
env, project_name, lib_name, extra_tags, env["addon_output_dir"], src_folder, additional_src
)

# Register console commands
env.Command("apply_patches", [], apply_patches)
env.Command("gen_apis", [], gen_apis)
# env.Command("build_cmake", [], build_cmake)


## CPP API TESTS

if env["build_cpp_api_tests"]:
tests_src_folder = "tests_native_api/cpp"
env.Append(CPPPATH=src_folder)
env["SHOBJPREFIX"] = "#obj/"
additional_tags = ""
if env["platform"] == "web" and env.get("threads", True):
additional_tags = ".threads"

lib_filename = "lib{}.{}.{}.{}{}".format(
"dd3d_cpp_api", env["platform"], env["target"], env["arch"], additional_tags
)
lib_filename = os.path.join(tests_src_folder, "addon_cpp_api_test", "libs", lib_filename + env["SHLIBSUFFIX"])

shbin = env.Default(
env.SharedLibrary(
target=env.File(lib_filename),
source=lib_utils.get_sources(env.Glob(os.path.join(tests_src_folder, "*.cpp")), "", "test_c_api"),
)
)
105 changes: 105 additions & 0 deletions lib_utils_gen_dd3d_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python3

from SCons.Script.SConscript import SConsEnvironment
from patches import unity_tools

import SCons
import os, shutil, json, re, hashlib
import lib_utils


def get_api(out_folder: str) -> dict:
text_data = lib_utils.read_all_text("src/api/c_api.cpp")

lines = text_data.replace("\r\n", "\n").replace("\r", "\n").split("\n")
functions = {}
for line in lines:
if line.startswith("API_FUNCTION"):
def_args = line[line.find("(") + 1 : line.rfind(")")].split(",", 2)
if len(def_args) >= 2:
ret_type = def_args[0].strip()
fun_name = def_args[1].strip()
args = []
if len(def_args) > 2:
args = [a.strip() for a in def_args[2].split(",")]
fun_dict = {"return": ret_type, "args": args}
functions[fun_name] = fun_dict

result = {"hash": hashlib.sha1(json.dumps(functions, sort_keys=True).encode()).hexdigest(), "functions": functions}

lib_utils.write_all_text(os.path.join(out_folder, "api.json"), json.dumps(result, indent=" "))

return result


def gen_cpp_api(env: SConsEnvironment, api: dict, out_folder: str) -> bool:
os.makedirs(out_folder, exist_ok=True)
functions = api["functions"]

namespaces = {}
for key in functions:
key_split = key.split("_", 1)
func_name = key_split[1] if len(key_split) else key
func: dict = functions[key]
ret = func["return"]
args = func["args"]

ns = key_split[0]
if ns in ["dd3d", "dd2d", "dd3dm", "scoped3d"]:
ns = ns.upper()
else:
ns = "DD3D"
func_name = key

if ns not in namespaces:
namespaces[ns] = []

def get_default_ret_val(ret_type: str):
if ret_type.endswith("*") or ret_type.startswith("Ref<"):
return "nullptr"

return "{}"

new_lines = []
new_lines.append(f"{ret} {func_name}({", ".join(args)}) {{")
new_lines.append(f"\tstatic {ret}(*{key})({", ".join([a.split("=", 1)[0].strip() for a in args])}) = nullptr;")
def_ret_val = get_default_ret_val(ret)
call_args = ", ".join([a.split("=", 1)[0].strip().rsplit(" ", 1)[1].replace("*", "").replace("&", "") for a in args])
if ret != "void":
new_lines.append(f"\tLOAD_AND_CALL_FUNC_POINTER_RET({key}, {def_ret_val}{", " if len(args) else ""}{call_args});")
else:
new_lines.append(f"\tLOAD_AND_CALL_FUNC_POINTER({key}, {", " if len(args) else ""}{call_args});")
new_lines.append(f"}}")
new_lines.append("")

namespaces[ns] += new_lines

shutil.copyfile("src/api/include/c_api_shared.h", os.path.join(out_folder, "c_api_shared.h"))
text_data = lib_utils.read_all_text("src/api/include/dd3d_cpp_api.h")
lines = text_data.replace("\r\n", "\n").replace("\r", "\n").split("\n")
insert_mark = "// GENERATOR_DD3D_API_FUNCTIONS"
insert_index = lines.index(insert_mark)
lines.remove(insert_mark)

result_arr = [""]
for key in namespaces:
result_arr.append(f"namespace {key} {{")
result_arr += namespaces[key]
result_arr.append(f"}} // namespace {key}")
result_arr.append("")

lines[insert_index:insert_index] = result_arr
return lib_utils.write_all_text(os.path.join(out_folder, "dd3d_cpp_api.h"), "\n".join(lines))


def gen_apis(env: SConsEnvironment, out_folder: str):
os.makedirs(out_folder, exist_ok=True)

api = get_api(out_folder)
if api == None:
print("Couldn't get the Native API")
return 110

if not gen_cpp_api(env, api, os.path.join(out_folder, "cpp")):
return 111
return 0
100 changes: 100 additions & 0 deletions src/api/c_api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "c_api.h"

#include "include/c_api_shared.h"
#include "utils/utils.h"

#include "2d/debug_draw_2d.h"
#include "3d/config_scope_3d.h"
#include "3d/debug_draw_3d.h"
#include "debug_draw_manager.h"

using namespace godot;

namespace NATIVE_API {

#define API_FUNCTION(_ret, _name, ...) _ret _name(__VA_ARGS__)

API_FUNCTION(void *, test_api_func, const int &i, const Vector2 &v, const float *f, float const *ff = nullptr) {
UtilityFunctions::print("WTF WOW ", i, v);
return nullptr;
}

/*
Ref<DebugDraw3DScopeConfig> new_scoped_config();
Ref<DebugDraw3DScopeConfig> scoped_config();
void set_config(Ref<DebugDraw3DConfig> cfg);
Ref<DebugDraw3DConfig> get_config();
void set_empty_color(const Color &col) {};
Color get_empty_color();
void set_debug_enabled(const bool &state);
bool is_debug_enabled();
Ref<DebugDraw3DStats> get_render_stats();
Ref<DebugDraw3DStats> get_render_stats_for_world(Viewport *viewport);
void regenerate_geometry_meshes();
void clear_all();
void draw_sphere_base(const Transform3D &transform, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_sphere(const Vector3 &position, const real_t &radius = 0.5f, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_sphere_xf(const Transform3D &transform, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_cylinder(const Transform3D &transform, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_cylinder_ab(const Vector3 &a, const Vector3 &b, const real_t &radius = 0.5f, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_box(const Vector3 &position, const Quaternion &rotation, const Vector3 &size, const Color &color = Colors::empty_color, const bool &is_box_centered = false, const real_t &duration = 0){}
void draw_box_ab(const Vector3 &a, const Vector3 &b, const Vector3 &up, const Color &color = Colors::empty_color, const bool &is_ab_diagonal = true, const real_t &duration = 0){}
void draw_box_xf(const Transform3D &transform, const Color &color = Colors::empty_color, const bool &is_box_centered = true, const real_t &duration = 0){}
void draw_aabb(const AABB &aabb, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_aabb_ab(const Vector3 &a, const Vector3 &b, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_line_hit(const Vector3 &start, const Vector3 &end, const Vector3 &hit, const bool &is_hit, const real_t &hit_size = 0.25f, const Color &hit_color = Colors::empty_color, const Color &after_hit_color = Colors::empty_color, const real_t &duration = 0){}
void draw_line_hit_offset(const Vector3 &start, const Vector3 &end, const bool &is_hit, const real_t &unit_offset_of_hit = 0.5f, const real_t &hit_size = 0.25f, const Color &hit_color = Colors::empty_color, const Color &after_hit_color = Colors::empty_color, const real_t &duration = 0){}
void draw_lines_c(const std::vector<Vector3> &lines, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_line(const Vector3 &a, const Vector3 &b, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_ray(const Vector3 &origin, const Vector3 &direction, const real_t &length, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_lines(const PackedVector3Array &lines, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_line_path(const PackedVector3Array &path, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_arrowhead(const Transform3D &transform, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_arrow(const Vector3 &a, const Vector3 &b, const Color &color = Colors::empty_color, const real_t &arrow_size = 0.5f, const bool &is_absolute_size = false, const real_t &duration = 0){}
void draw_arrow_ray(const Vector3 &origin, const Vector3 &direction, const real_t &length, const Color &color = Colors::empty_color, const real_t &arrow_size = 0.5f, const bool &is_absolute_size = false, const real_t &duration = 0){}
void draw_arrow_path(const PackedVector3Array &path, const Color &color = Colors::empty_color, const real_t &arrow_size = 0.75f, const bool &is_absolute_size = true, const real_t &duration = 0){}
void draw_point_path(const PackedVector3Array &path, const PointType type = PointType::POINT_TYPE_SQUARE, const real_t &size = 0.25f, const Color &points_color = Colors::empty_color, const Color &lines_color = Colors::empty_color, const real_t &duration = 0){}
void draw_points(const PackedVector3Array &points, const PointType type = PointType::POINT_TYPE_SQUARE, const real_t &size = 0.25f, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_square(const Vector3 &position, const real_t &size = 0.2f, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_plane(const Plane &plane, const Color &color = Colors::empty_color, const Vector3 &anchor_point = Vector3(INFINITY, INFINITY, INFINITY), const real_t &duration = 0){}
void draw_position(const Transform3D &transform, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_gizmo(const Transform3D &transform, const Color &color = Colors::empty_color, const bool &is_centered = false, const real_t &duration = 0){}
void draw_grid(const Vector3 &origin, const Vector3 &x_size, const Vector3 &y_size, const Vector2i &subdivision, const Color &color = Colors::empty_color, const bool &is_centered = true, const real_t &duration = 0){}
void draw_grid_xf(const Transform3D &transform, const Vector2i &p_subdivision, const Color &color = Colors::empty_color, const bool &is_centered = true, const real_t &duration = 0){}
void draw_camera_frustum_planes_c(const std::array<Plane, 6> &planes, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_camera_frustum(const class godot::Camera3D *camera, const Color &color = Colors::empty_color, const real_t &duration = 0){}
void draw_camera_frustum_planes(const Array &camera_frustum, const Color &color = Colors::empty_color, const real_t &duration = 0){}
*/

#undef API_FUNCTION

Dictionary get_functions() {
static Dictionary result;
if (result.is_empty()) {
Dictionary functions;
#define ADD_FUNC(_name) functions[#_name] = Utils::make_dict("ptr", (int64_t) & _name, "signature", DD3DShared::get_function_signature(&_name))

ADD_FUNC(test_api_func);

#undef ADD_FUNC

result["hash"] = functions.hash();
result["functions"] = functions;
}
return result;
}
} // namespace NATIVE_API
11 changes: 11 additions & 0 deletions src/api/c_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "utils/compiler.h"

GODOT_WARNING_DISABLE()
#include <godot_cpp/variant/dictionary.hpp>
GODOT_WARNING_RESTORE()

namespace NATIVE_API {
godot::Dictionary get_functions();
}
50 changes: 50 additions & 0 deletions src/api/include/c_api_shared.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once

#include <sstream>
#include <string>
#include <typeinfo>

#if _MSC_VER
__pragma(warning(disable : 4244 26451 26495));
#endif
#include <godot_cpp/variant/variant.hpp>
#if _MSC_VER
__pragma(warning(default : 4244 26451 26495));
#endif
using namespace godot;

namespace DD3DShared {

template <typename T>
struct FunctionSignature;

template <typename R, typename... Args>
struct FunctionSignature<R (*)(Args...)> {
static String get() {
std::ostringstream oss;
oss << typeid(R).name() << " (";
((oss << getTypeName<Args>() << ", "), ...);
return String(oss.str().c_str()).trim_suffix(", ") + ")";
}

private:
template <typename U>
static std::string getTypeName() {
std::ostringstream oss;
if constexpr (std::is_const<U>::value) {
oss << "const ";
}
if constexpr (std::is_reference<U>::value) {
oss << getTypeName<std::remove_reference_t<U> >() << "&";
} else {
oss << typeid(U).name();
}
return oss.str();
}
};

template <typename Func>
String get_function_signature(Func func) {
return FunctionSignature<decltype(func)>::get();
}
} // namespace DD3DShared
Loading

0 comments on commit 551c4b1

Please sign in to comment.