Compare commits
15 Commits
7c3ab21127
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97ff779911 | ||
|
|
dacbb2e043 | ||
|
|
27693a8fbf | ||
|
|
427c64ef5d | ||
|
|
52662e129b | ||
|
|
8283d9632c | ||
|
|
c4641182e3 | ||
|
|
e33d564844 | ||
|
|
b90dcde305 | ||
|
|
2ec0c4b742 | ||
|
|
bb3b897c16 | ||
|
|
7747217b36 | ||
|
|
5f9cc1e42e | ||
|
|
c5d45ad8ab | ||
|
|
5f5a14f69f |
44
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
44
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,44 +0,0 @@
|
|||||||
name: Bug report
|
|
||||||
description: Report a bug with the godot-cpp template
|
|
||||||
body:
|
|
||||||
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
- Write a descriptive issue title above.
|
|
||||||
- Search [open](https://github.com/godotengine/godot-cpp-template/issues) and [closed](https://github.com/godotengine/godot-cpp-template/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported.
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: Godot version
|
|
||||||
description: >
|
|
||||||
Specify the Git commit hash of your Godot build.
|
|
||||||
placeholder: v4.0.stable.official [92bee43ad]
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: godot-cpp version
|
|
||||||
description: >
|
|
||||||
Specify the Git commit hash of the godot-cpp submodule in your project. You can run `git status` inside the folder to check it.
|
|
||||||
placeholder: v4.0.stable.official [9d1c396c5]
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
attributes:
|
|
||||||
label: System information
|
|
||||||
description: |
|
|
||||||
Specify the OS version.
|
|
||||||
placeholder: Windows 10
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Issue description
|
|
||||||
description: |
|
|
||||||
Describe your issue briefly. What doesn't work, and how do you expect it to work instead?
|
|
||||||
You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
14
.github/ISSUE_TEMPLATE/config.yml
vendored
14
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,14 +0,0 @@
|
|||||||
blank_issues_enabled: false
|
|
||||||
|
|
||||||
contact_links:
|
|
||||||
- name: Godot proposals
|
|
||||||
url: https://github.com/godotengine/godot-proposals
|
|
||||||
about: Please submit feature proposals on the Godot proposals repository, not here.
|
|
||||||
|
|
||||||
- name: Godot documentation repository
|
|
||||||
url: https://github.com/godotengine/godot-docs
|
|
||||||
about: Please report issues with documentation on the Godot documentation repository, not here.
|
|
||||||
|
|
||||||
- name: Godot community channels
|
|
||||||
url: https://godotengine.org/community
|
|
||||||
about: Please ask for technical support on one of the other community channels, not here.
|
|
||||||
88
.github/workflows/ci.yml
vendored
88
.github/workflows/ci.yml
vendored
@@ -1,88 +0,0 @@
|
|||||||
# For syntax, see https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
|
|
||||||
# This workflow is automatically triggered for every push and pull request, to verify that everything still builds.
|
|
||||||
|
|
||||||
name: Continuous Integration
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
push:
|
|
||||||
pull_request:
|
|
||||||
merge_group:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
# Test a few selected combinations of parameters ("test case matrix").
|
|
||||||
# While it would be nice to test all needed combinations, in practice this would a waste of CI usage time.
|
|
||||||
# By building just with a few combinations, we only need a few runners,
|
|
||||||
# while still achieving adequate coverage.
|
|
||||||
# To make a full build with all combinations, use the make_build.yml workflow instead.
|
|
||||||
include:
|
|
||||||
- target: { platform: linux, arch: x86_64, os: ubuntu-22.04 }
|
|
||||||
target-type: template_debug
|
|
||||||
float-precision: double
|
|
||||||
- target: { platform: windows, arch: x86_64, os: windows-latest }
|
|
||||||
target-type: template_release
|
|
||||||
float-precision: single
|
|
||||||
- target: { platform: macos, arch: universal, os: macos-latest }
|
|
||||||
target-type: template_debug
|
|
||||||
float-precision: single
|
|
||||||
- target: { platform: android, arch: arm64, os: ubuntu-22.04 }
|
|
||||||
target-type: template_debug
|
|
||||||
float-precision: single
|
|
||||||
- target: { platform: web, arch: wasm32, os: ubuntu-22.04 }
|
|
||||||
target-type: template_release
|
|
||||||
float-precision: double
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.target.os }}
|
|
||||||
steps:
|
|
||||||
# Clone this repository
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
# Lint
|
|
||||||
#- name: Setup clang-format
|
|
||||||
# shell: bash
|
|
||||||
# run: |
|
|
||||||
# python -m pip install clang-format
|
|
||||||
#- name: Run clang-format
|
|
||||||
# shell: bash
|
|
||||||
# run: |
|
|
||||||
# clang-format src/** --dry-run --Werror
|
|
||||||
|
|
||||||
# Add linux x86_32 toolchain
|
|
||||||
- name: Install multilib support
|
|
||||||
if: ${{ matrix.target.platform == 'linux' && matrix.target.arch == 'x86_32' }}
|
|
||||||
run: |
|
|
||||||
sudo apt-get update && sudo apt-get install -y gcc-multilib g++-multilib
|
|
||||||
|
|
||||||
# Setup dependencies
|
|
||||||
- name: Setup godot-cpp
|
|
||||||
uses: ./godot-cpp/.github/actions/setup-godot-cpp
|
|
||||||
with:
|
|
||||||
platform: ${{ matrix.target.platform }}
|
|
||||||
em-version: 3.1.62
|
|
||||||
|
|
||||||
# Build GDExtension (with caches)
|
|
||||||
|
|
||||||
- name: Restore .scons_cache
|
|
||||||
uses: ./godot-cpp/.github/actions/godot-cache-restore
|
|
||||||
with:
|
|
||||||
scons-cache: ${{ github.workspace }}/.scons-cache/
|
|
||||||
cache-name: ${{ matrix.target.platform }}_${{ matrix.target.arch }}_${{ matrix.float-precision }}_${{ matrix.target-type }}
|
|
||||||
|
|
||||||
- name: Build GDExtension Debug Build
|
|
||||||
shell: sh
|
|
||||||
env:
|
|
||||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
|
||||||
run: |
|
|
||||||
scons target=${{ matrix.target-type }} platform=${{ matrix.target.platform }} arch=${{ matrix.target.arch }} precision=${{ matrix.float-precision }}
|
|
||||||
|
|
||||||
- name: Save .scons_cache
|
|
||||||
uses: ./godot-cpp/.github/actions/godot-cache-save
|
|
||||||
with:
|
|
||||||
scons-cache: ${{ github.workspace }}/.scons-cache/
|
|
||||||
cache-name: ${{ matrix.target.platform }}_${{ matrix.target.arch }}_${{ matrix.float-precision }}_${{ matrix.target-type }}
|
|
||||||
104
.github/workflows/make_build.yml
vendored
104
.github/workflows/make_build.yml
vendored
@@ -1,104 +0,0 @@
|
|||||||
# For syntax, see https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
|
|
||||||
# This workflow is triggered manually on the "Actions" tab on GitHub, and can be used to create releases.
|
|
||||||
|
|
||||||
name: Make a GDExtension build for all supported platforms
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
# A build is made for every possible combination of parameters
|
|
||||||
# You can add or remove entries from the arrays of each parameter to customize which builds you want to run.
|
|
||||||
# See https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/running-variations-of-jobs-in-a-workflow
|
|
||||||
target:
|
|
||||||
[
|
|
||||||
{ platform: linux, arch: x86_64, os: ubuntu-22.04 },
|
|
||||||
{ platform: linux, arch: x86_32, os: ubuntu-22.04 },
|
|
||||||
{ platform: linux, arch: arm64, os: ubuntu-22.04-arm },
|
|
||||||
{ platform: linux, arch: arm32, os: ubuntu-22.04-arm },
|
|
||||||
{ platform: windows, arch: x86_64, os: windows-latest },
|
|
||||||
{ platform: windows, arch: x86_32, os: windows-latest },
|
|
||||||
{ platform: windows, arch: arm64, os: windows-latest },
|
|
||||||
{ platform: macos, arch: universal, os: macos-latest },
|
|
||||||
{ platform: android, arch: x86_64, os: ubuntu-22.04 },
|
|
||||||
{ platform: android, arch: x86_32, os: ubuntu-22.04 },
|
|
||||||
{ platform: android, arch: arm64, os: ubuntu-22.04 },
|
|
||||||
{ platform: android, arch: arm32, os: ubuntu-22.04 },
|
|
||||||
{ platform: ios, arch: arm64, os: macos-latest },
|
|
||||||
{ platform: web, arch: wasm32, os: ubuntu-22.04 },
|
|
||||||
]
|
|
||||||
target-type: [template_debug, template_release]
|
|
||||||
float-precision: [single]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.target.os }}
|
|
||||||
steps:
|
|
||||||
# Clone this repository
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
# Add linux x86_32 toolchain
|
|
||||||
- name: Install multilib support
|
|
||||||
if: ${{ matrix.target.platform == 'linux' && matrix.target.arch == 'x86_32' }}
|
|
||||||
run: |
|
|
||||||
sudo apt-get update && sudo apt-get install -y gcc-multilib g++-multilib
|
|
||||||
|
|
||||||
# Setup dependencies
|
|
||||||
- name: Setup godot-cpp
|
|
||||||
uses: ./godot-cpp/.github/actions/setup-godot-cpp
|
|
||||||
with:
|
|
||||||
platform: ${{ matrix.target.platform }}
|
|
||||||
em-version: 3.1.62
|
|
||||||
|
|
||||||
# Build GDExtension (with caches)
|
|
||||||
|
|
||||||
- name: Restore .scons_cache
|
|
||||||
uses: ./godot-cpp/.github/actions/godot-cache-restore
|
|
||||||
with:
|
|
||||||
scons-cache: ${{ github.workspace }}/.scons-cache/
|
|
||||||
cache-name: ${{ matrix.target.platform }}_${{ matrix.target.arch }}_${{ matrix.float-precision }}_${{ matrix.target-type }}
|
|
||||||
|
|
||||||
- name: Build GDExtension Debug Build
|
|
||||||
shell: sh
|
|
||||||
env:
|
|
||||||
SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
|
|
||||||
run: |
|
|
||||||
scons target=${{ matrix.target-type }} platform=${{ matrix.target.platform }} arch=${{ matrix.target.arch }} precision=${{ matrix.float-precision }}
|
|
||||||
|
|
||||||
- name: Save .scons_cache
|
|
||||||
uses: ./godot-cpp/.github/actions/godot-cache-save
|
|
||||||
with:
|
|
||||||
scons-cache: ${{ github.workspace }}/.scons-cache/
|
|
||||||
cache-name: ${{ matrix.target.platform }}_${{ matrix.target.arch }}_${{ matrix.float-precision }}_${{ matrix.target-type }}
|
|
||||||
|
|
||||||
# Clean up compilation files
|
|
||||||
- name: Windows - Delete compilation files
|
|
||||||
if: ${{ matrix.target.platform == 'windows' }}
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
Remove-Item bin/* -Include *.exp,*.lib,*.pdb -Force
|
|
||||||
|
|
||||||
# Upload the build
|
|
||||||
- name: Upload Artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: godot-cpp-template-${{ matrix.target.platform }}-${{ matrix.target.arch }}-${{ matrix.float-precision }}-${{ matrix.target-type }}
|
|
||||||
path: |
|
|
||||||
${{ github.workspace }}/bin/**
|
|
||||||
|
|
||||||
# Merges all the build artifacts together into a single godot-cpp-template artifact.
|
|
||||||
# If you comment out this step, all the builds will be uploaded individually.
|
|
||||||
merge:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
needs: build
|
|
||||||
steps:
|
|
||||||
- name: Merge Artifacts
|
|
||||||
uses: actions/upload-artifact/merge@v4
|
|
||||||
with:
|
|
||||||
name: godot-cpp-template
|
|
||||||
pattern: godot-cpp-template-*
|
|
||||||
delete-merged: true
|
|
||||||
21
.gitignore
vendored
21
.gitignore
vendored
@@ -3,20 +3,10 @@
|
|||||||
.godot/
|
.godot/
|
||||||
|
|
||||||
# Ignore library files but not the gdextension file
|
# Ignore library files but not the gdextension file
|
||||||
project/bin/*
|
/bin/**
|
||||||
!project/bin/android
|
|
||||||
project/bin/android/*
|
|
||||||
!project/bin/android/.gitkeep
|
|
||||||
!project/bin/linux
|
|
||||||
project/bin/linux/*
|
|
||||||
!project/bin/linux/.gitkeep
|
|
||||||
!project/bin/macos
|
|
||||||
project/bin/macos/*
|
|
||||||
!project/bin/macos/.gitkeep
|
|
||||||
!project/bin/windows
|
|
||||||
project/bin/windows/*
|
|
||||||
!project/bin/windows/.gitkeep
|
|
||||||
!project/bin/*.gdextension
|
!project/bin/*.gdextension
|
||||||
|
|
||||||
|
# Ignore scons database
|
||||||
.sconsign*.dblite
|
.sconsign*.dblite
|
||||||
|
|
||||||
# Ignore custom.py
|
# Ignore custom.py
|
||||||
@@ -60,3 +50,8 @@ compile_commands.json
|
|||||||
# Cmake
|
# Cmake
|
||||||
cmake-build*
|
cmake-build*
|
||||||
CMakeUserPresets.json
|
CMakeUserPresets.json
|
||||||
|
|
||||||
|
# stupid godot developers using SCons
|
||||||
|
build/
|
||||||
|
|
||||||
|
godot/
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.17)
|
|||||||
if(CMAKE_C_COMPILER)
|
if(CMAKE_C_COMPILER)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(LIBNAME "EXTENSION-NAME" CACHE STRING "The name of the library")
|
set(LIBNAME "gdvapi") # "The name of the library"
|
||||||
set(GODOT_PROJECT_DIR "project" CACHE STRING "The directory of a Godot project folder")
|
set(GODOT_PROJECT_DIR "project" CACHE STRING "The directory of a Godot project folder")
|
||||||
|
|
||||||
# Make sure all the dependencies are satisfied
|
# Make sure all the dependencies are satisfied
|
||||||
@@ -26,6 +26,12 @@ if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/godot-cpp/src")
|
|||||||
endif()
|
endif()
|
||||||
add_subdirectory(godot-cpp SYSTEM)
|
add_subdirectory(godot-cpp SYSTEM)
|
||||||
|
|
||||||
|
# When compiling for emscripten, this toolchainhack needs to be included.
|
||||||
|
# set(CMAKE_PROJECT_<project-name>_INCLUDE ${godot-cpp_SOURCE_DIR}/cmake/emsdkHack.cmake)
|
||||||
|
|
||||||
|
# Create the gen directory at configure time so IDEs can see generated headers immediately after generate_bindings
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/godot-cpp/gen/include")
|
||||||
|
|
||||||
# Add godot-cpp's module path and include the exported functions.
|
# Add godot-cpp's module path and include the exported functions.
|
||||||
# This is made available for documentation generation
|
# This is made available for documentation generation
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${godot-cpp_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${godot-cpp_SOURCE_DIR}/cmake")
|
||||||
@@ -36,21 +42,38 @@ get_target_property(GODOTCPP_SUFFIX godot::cpp GODOTCPP_SUFFIX)
|
|||||||
get_target_property(GODOTCPP_PLATFORM godot::cpp GODOTCPP_PLATFORM)
|
get_target_property(GODOTCPP_PLATFORM godot::cpp GODOTCPP_PLATFORM)
|
||||||
|
|
||||||
# Now we can specify our own project which will inherit any global cmake properties or variables that have been defined.
|
# Now we can specify our own project which will inherit any global cmake properties or variables that have been defined.
|
||||||
project(godot-cpp-template
|
project(gdvapi
|
||||||
VERSION 1.0
|
VERSION 1.0
|
||||||
DESCRIPTION "This repository serves as a quickstart template for GDExtension development with Godot 4.0+."
|
DESCRIPTION "Godot extension to recieve streams"
|
||||||
HOMEPAGE_URL "https://github.com/enetheru/godot-cpp-template/tree/main"
|
HOMEPAGE_URL "https://git.epsncl.uk/rhys/gdvapi"
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
find_package(Vulkan REQUIRED)
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
|
pkg_check_modules(AVFORMAT REQUIRED IMPORTED_TARGET libavformat)
|
||||||
|
pkg_check_modules(AVCODEC REQUIRED IMPORTED_TARGET libavcodec)
|
||||||
|
pkg_check_modules(SWSCALE REQUIRED IMPORTED_TARGET libswscale)
|
||||||
|
pkg_check_modules(AVUTIL REQUIRED IMPORTED_TARGET libavutil)
|
||||||
|
|
||||||
add_library(${LIBNAME} SHARED)
|
add_library(${LIBNAME} SHARED)
|
||||||
|
|
||||||
|
target_link_libraries(${LIBNAME} PRIVATE
|
||||||
|
Vulkan::Headers
|
||||||
|
PkgConfig::AVFORMAT
|
||||||
|
PkgConfig::AVCODEC
|
||||||
|
PkgConfig::SWSCALE
|
||||||
|
PkgConfig::AVUTIL
|
||||||
|
)
|
||||||
|
|
||||||
target_sources(${LIBNAME}
|
target_sources(${LIBNAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
src/register_types.cpp
|
src/register_types.cpp
|
||||||
src/register_types.h
|
src/register_types.h
|
||||||
src/example_class.cpp
|
src/gdvapivideostream_class.cpp
|
||||||
src/example_class.h
|
src/gdvapivideostream_class.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fetch a list of the xml files to use for documentation and add to our target
|
# Fetch a list of the xml files to use for documentation and add to our target
|
||||||
@@ -59,7 +82,7 @@ file(GLOB_RECURSE DOC_XML LIST_DIRECTORIES NO CONFIGURE_DEPENDS "${PROJECT_SOURC
|
|||||||
# conditionally add doc data to compile output
|
# conditionally add doc data to compile output
|
||||||
if(DOC_XML)
|
if(DOC_XML)
|
||||||
if(GODOTCPP_TARGET MATCHES "editor|template_debug")
|
if(GODOTCPP_TARGET MATCHES "editor|template_debug")
|
||||||
target_doc_sources(${LIBNAME} ${DOC_XML})
|
target_doc_sources(${LIBNAME} "${DOC_XML}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
30
LICENSE.md
30
LICENSE.md
@@ -1,24 +1,12 @@
|
|||||||
This is free and unencumbered software released into the public domain.
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
|
Version 2, December 2004
|
||||||
|
|
||||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
Copyright (C) 2026 Rhys Tumelty <rhys@tumelty.co.uk>
|
||||||
distribute this software, either in source code form or as a compiled
|
Everyone is permitted to copy and distribute verbatim or modified
|
||||||
binary, for any purpose, commercial or non-commercial, and by any
|
copies of this license document, and changing it is allowed as long
|
||||||
means.
|
as the name is changed.
|
||||||
|
|
||||||
In jurisdictions that recognize copyright laws, the author or authors
|
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||||
of this software dedicate any and all copyright interest in the
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
software to the public domain. We make this dedication for the benefit
|
|
||||||
of the public at large and to the detriment of our heirs and
|
|
||||||
successors. We intend this dedication to be an overt act of
|
|
||||||
relinquishment in perpetuity of all present and future rights to this
|
|
||||||
software under copyright law.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
||||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
For more information, please refer to <https://unlicense.org>
|
|
||||||
|
|||||||
62
README.md
62
README.md
@@ -1,56 +1,8 @@
|
|||||||
# godot-cpp template
|
# GDVAPI
|
||||||
This repository serves as a quickstart template for GDExtension development with Godot 4.0+.
|
A godot extension to recieve video steams over UDP and render them
|
||||||
|
|
||||||
## Contents
|
# Building
|
||||||
* Preconfigured source files for C++ development of the GDExtension ([src/](./src/))
|
`nix develop`
|
||||||
* An empty Godot project in [project/](./project), to test the GDExtension
|
`cmake -B build`
|
||||||
* godot-cpp as a submodule (`godot-cpp/`)
|
`make -C build -j$(nproc)`
|
||||||
* GitHub Issues template ([.github/ISSUE_TEMPLATE.yml](./.github/ISSUE_TEMPLATE.yml))
|
`# package coming later`
|
||||||
* GitHub CI/CD workflows to publish your library packages when creating a release ([.github/workflows/builds.yml](./.github/workflows/builds.yml))
|
|
||||||
* An SConstruct file with various functions, such as boilerplate for [Adding documentation](https://docs.godotengine.org/en/stable/tutorials/scripting/cpp/gdextension_docs_system.html)
|
|
||||||
|
|
||||||
## Usage - Template
|
|
||||||
|
|
||||||
To use this template, log in to GitHub and click the green "Use this template" button at the top of the repository page. This will let you create a copy of this repository with a clean git history.
|
|
||||||
|
|
||||||
To get started with your new GDExtension, do the following:
|
|
||||||
|
|
||||||
* clone your repository to your local computer
|
|
||||||
* initialize the godot-cpp git submodule via `git submodule update --init`
|
|
||||||
* change the name of the compiled library file inside the [SConstruct](./SConstruct) file by modifying the `libname` string.
|
|
||||||
* change the paths of the to be loaded library name inside the [project/bin/example.gdextension](./project/bin/example.gdextension) file, by replacing `EXTENSION-NAME` with the name you chose for `libname`.
|
|
||||||
* change the `entry_symbol` string inside [project/bin/example.gdextension](./project/bin/example.gdextension) file.
|
|
||||||
* rename the `example_library_init` function in [src/register_types.cpp](./src/register_types.cpp) to the same name you chose for `entry_symbol`.
|
|
||||||
* change the name of the `project/bin/example.gdextension` file
|
|
||||||
|
|
||||||
Now, you can build the project with the following command:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
scons
|
|
||||||
```
|
|
||||||
|
|
||||||
If the build command worked, you can test it with the [project](./project) project. Import it into Godot, open it, and launch the main scene. You should see it print the following line in the console:
|
|
||||||
|
|
||||||
```
|
|
||||||
Type: 24
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuring an IDE
|
|
||||||
You can develop your own extension with any text editor and by invoking scons on the command line, but if you want to work with an IDE (Integrated Development Environment), you can use a compilation database file called `compile_commands.json`. Most IDEs should automatically identify this file, and self-configure appropriately.
|
|
||||||
To generate the database file, you can run one of the following commands in the project root directory:
|
|
||||||
```shell
|
|
||||||
# Generate compile_commands.json while compiling
|
|
||||||
scons compiledb=yes
|
|
||||||
|
|
||||||
# Generate compile_commands.json without compiling
|
|
||||||
scons compiledb=yes compile_commands.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage - Actions
|
|
||||||
|
|
||||||
This repository comes with continuous integration (CI) through a GitHub action that tests building the GDExtension.
|
|
||||||
It triggers automatically for each pushed change. You can find and edit it in [builds.yml](.github/workflows/ci.yml).
|
|
||||||
|
|
||||||
There is also a workflow ([make_build.yml](.github/workflows/make_build.yml)) that builds the GDExtension for all supported platforms that you can use to create releases.
|
|
||||||
You can trigger this workflow manually from the `Actions` tab on GitHub.
|
|
||||||
After it is complete, you can find the file `godot-cpp-template.zip` in the `Artifacts` section of the workflow run.
|
|
||||||
|
|||||||
64
SConstruct
64
SConstruct
@@ -1,64 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from methods import print_error
|
|
||||||
|
|
||||||
|
|
||||||
libname = "EXTENSION-NAME"
|
|
||||||
projectdir = "project"
|
|
||||||
|
|
||||||
localEnv = Environment(tools=["default"], PLATFORM="")
|
|
||||||
|
|
||||||
# Build profiles can be used to decrease compile times.
|
|
||||||
# You can either specify "disabled_classes", OR
|
|
||||||
# explicitly specify "enabled_classes" which disables all other classes.
|
|
||||||
# Modify the example file as needed and uncomment the line below or
|
|
||||||
# manually specify the build_profile parameter when running SCons.
|
|
||||||
|
|
||||||
# localEnv["build_profile"] = "build_profile.json"
|
|
||||||
|
|
||||||
customs = ["custom.py"]
|
|
||||||
customs = [os.path.abspath(path) for path in customs]
|
|
||||||
|
|
||||||
opts = Variables(customs, ARGUMENTS)
|
|
||||||
opts.Update(localEnv)
|
|
||||||
|
|
||||||
Help(opts.GenerateHelpText(localEnv))
|
|
||||||
|
|
||||||
env = localEnv.Clone()
|
|
||||||
|
|
||||||
if not (os.path.isdir("godot-cpp") and os.listdir("godot-cpp")):
|
|
||||||
print_error("""godot-cpp is not available within this folder, as Git submodules haven't been initialized.
|
|
||||||
Run the following command to download godot-cpp:
|
|
||||||
|
|
||||||
git submodule update --init --recursive""")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
env = SConscript("godot-cpp/SConstruct", {"env": env, "customs": customs})
|
|
||||||
|
|
||||||
env.Append(CPPPATH=["src/"])
|
|
||||||
sources = Glob("src/*.cpp")
|
|
||||||
|
|
||||||
if env["target"] in ["editor", "template_debug"]:
|
|
||||||
try:
|
|
||||||
doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml"))
|
|
||||||
sources.append(doc_data)
|
|
||||||
except AttributeError:
|
|
||||||
print("Not including class reference as we're targeting a pre-4.3 baseline.")
|
|
||||||
|
|
||||||
# .dev doesn't inhibit compatibility, so we don't need to key it.
|
|
||||||
# .universal just means "compatible with all relevant arches" so we don't need to key it.
|
|
||||||
suffix = env['suffix'].replace(".dev", "").replace(".universal", "")
|
|
||||||
|
|
||||||
lib_filename = "{}{}{}{}".format(env.subst('$SHLIBPREFIX'), libname, suffix, env.subst('$SHLIBSUFFIX'))
|
|
||||||
|
|
||||||
library = env.SharedLibrary(
|
|
||||||
"bin/{}/{}".format(env['platform'], lib_filename),
|
|
||||||
source=sources,
|
|
||||||
)
|
|
||||||
|
|
||||||
copy = env.Install("{}/bin/{}/".format(projectdir, env["platform"]), library)
|
|
||||||
|
|
||||||
default_args = [library, copy]
|
|
||||||
Default(*default_args)
|
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1787360063,
|
||||||
|
"narHash": "sha256-dt4WdcvsA8/RCe+VZZwqU0X+XMM3wBbGCWA0/sFWzGo=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2c423e03bbafcff28bfadc6781a4a8257f205cb5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
37
flake.nix
Normal file
37
flake.nix
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs: {
|
||||||
|
|
||||||
|
devShells = builtins.mapAttrs (system: pkgs: {
|
||||||
|
default = (pkgs.mkShell.override { stdenv = pkgs.llvmPackages.stdenv; }) {
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
cmake
|
||||||
|
ninja
|
||||||
|
clang
|
||||||
|
python3
|
||||||
|
godot
|
||||||
|
pkg-config
|
||||||
|
|
||||||
|
gst_all_1.gstreamer
|
||||||
|
gst_all_1.gst-plugins-base
|
||||||
|
gst_all_1.gst-plugins-good
|
||||||
|
gst_all_1.gst-plugins-bad
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
vulkan-loader
|
||||||
|
vulkan-headers
|
||||||
|
ffmpeg
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
export PS1="''${PS1//\\n/}"
|
||||||
|
export PS1="\[\033[1;31m\][gdvapi]\[\033[0m\] $PS1"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}) inputs.nixpkgs.legacyPackages;
|
||||||
|
};
|
||||||
|
}
|
||||||
BIN
project/badapple.mov
Normal file
BIN
project/badapple.mov
Normal file
Binary file not shown.
@@ -1,57 +0,0 @@
|
|||||||
[configuration]
|
|
||||||
|
|
||||||
entry_symbol = "example_library_init"
|
|
||||||
compatibility_minimum = "4.1"
|
|
||||||
reloadable = false
|
|
||||||
|
|
||||||
[libraries]
|
|
||||||
; Relative paths ensure that our GDExtension can be placed anywhere in the project directory.
|
|
||||||
macos.single.debug = "./macos/libEXTENSION-NAME.macos.template_debug.dylib"
|
|
||||||
macos.double.debug = "./macos/libEXTENSION-NAME.macos.template_debug.double.dylib"
|
|
||||||
macos.single.release = "./macos/libEXTENSION-NAME.macos.template_release.dylib"
|
|
||||||
macos.double.release = "./macos/libEXTENSION-NAME.macos.template_release.double.dylib"
|
|
||||||
|
|
||||||
ios.arm64.single.debug = "./ios/libEXTENSION-NAME.ios.template_debug.arm64.dylib"
|
|
||||||
ios.arm64.double.debug = "./ios/libEXTENSION-NAME.ios.template_debug.arm64.double.dylib"
|
|
||||||
ios.arm64.single.release = "./ios/libEXTENSION-NAME.ios.template_release.arm64.dylib"
|
|
||||||
ios.arm64.double.release = "./ios/libEXTENSION-NAME.ios.template_release.arm64.double.dylib"
|
|
||||||
|
|
||||||
windows.x86_32.single.debug = "./windows/EXTENSION-NAME.windows.template_debug.x86_32.dll"
|
|
||||||
windows.x86_32.double.debug = "./windows/EXTENSION-NAME.windows.template_debug.x86_32.double.dll"
|
|
||||||
windows.x86_32.single.release = "./windows/EXTENSION-NAME.windows.template_release.x86_32.dll"
|
|
||||||
windows.x86_32.double.release = "./windows/EXTENSION-NAME.windows.template_release.x86_32.double.dll"
|
|
||||||
|
|
||||||
windows.x86_64.single.debug = "./windows/EXTENSION-NAME.windows.template_debug.x86_64.dll"
|
|
||||||
windows.x86_64.double.debug = "./windows/EXTENSION-NAME.windows.template_debug.x86_64.double.dll"
|
|
||||||
windows.x86_64.single.release = "./windows/EXTENSION-NAME.windows.template_release.x86_64.dll"
|
|
||||||
windows.x86_64.double.release = "./windows/EXTENSION-NAME.windows.template_release.x86_64.double.dll"
|
|
||||||
|
|
||||||
linux.x86_64.single.debug = "./linux/libEXTENSION-NAME.linux.template_debug.x86_64.so"
|
|
||||||
linux.x86_64.double.debug = "./linux/libEXTENSION-NAME.linux.template_debug.x86_64.double.so"
|
|
||||||
linux.x86_64.single.release = "./linux/libEXTENSION-NAME.linux.template_release.x86_64.so"
|
|
||||||
linux.x86_64.double.release = "./linux/libEXTENSION-NAME.linux.template_release.x86_64.double.so"
|
|
||||||
|
|
||||||
linux.arm64.single.debug = "./linux/libEXTENSION-NAME.linux.template_debug.arm64.so"
|
|
||||||
linux.arm64.double.debug = "./linux/libEXTENSION-NAME.linux.template_debug.arm64.double.so"
|
|
||||||
linux.arm64.single.release = "./linux/libEXTENSION-NAME.linux.template_release.arm64.so"
|
|
||||||
linux.arm64.double.release = "./linux/libEXTENSION-NAME.linux.template_release.arm64.double.so"
|
|
||||||
|
|
||||||
linux.rv64.single.debug = "./linux/libEXTENSION-NAME.linux.template_debug.rv64.so"
|
|
||||||
linux.rv64.double.debug = "./linux/libEXTENSION-NAME.linux.template_debug.rv64.double.so"
|
|
||||||
linux.rv64.single.release = "./linux/libEXTENSION-NAME.linux.template_release.rv64.so"
|
|
||||||
linux.rv64.double.release = "./linux/libEXTENSION-NAME.linux.template_release.rv64.double.so"
|
|
||||||
|
|
||||||
android.x86_64.single.debug = "./android/libEXTENSION-NAME.android.template_debug.x86_64.so"
|
|
||||||
android.x86_64.double.debug = "./android/libEXTENSION-NAME.android.template_debug.x86_64.double.so"
|
|
||||||
android.x86_64.single.release = "./android/libEXTENSION-NAME.android.template_release.x86_64.so"
|
|
||||||
android.x86_64.double.release = "./android/libEXTENSION-NAME.android.template_release.x86_64.double.so"
|
|
||||||
|
|
||||||
android.arm64.single.debug = "./android/libEXTENSION-NAME.android.template_debug.arm64.so"
|
|
||||||
android.arm64.double.debug = "./android/libEXTENSION-NAME.android.template_debug.arm64.double.so"
|
|
||||||
android.arm64.single.release = "./android/libEXTENSION-NAME.android.template_release.arm64.so"
|
|
||||||
android.arm64.double.release = "./android/libEXTENSION-NAME.android.template_release.arm64.double.so"
|
|
||||||
|
|
||||||
web.wasm32.single.debug = "./web/libEXTENSION-NAME.web.template_debug.wasm32.nothreads.wasm"
|
|
||||||
web.wasm32.double.debug = "./web/libEXTENSION-NAME.web.template_debug.wasm32.double.nothreads.wasm"
|
|
||||||
web.wasm32.single.release = "./web/libEXTENSION-NAME.web.template_release.wasm32.nothreads.wasm"
|
|
||||||
web.wasm32.double.release = "./web/libEXTENSION-NAME.web.template_release.wasm32.double.nothreads.wasm"
|
|
||||||
7
project/bin/gdvapi.gdextension
Normal file
7
project/bin/gdvapi.gdextension
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[configuration]
|
||||||
|
entry_symbol = "gdvapi_library_init"
|
||||||
|
compatibility_minimum = "4.7"
|
||||||
|
|
||||||
|
[libraries]
|
||||||
|
linux.editor.x86_64 = "res://bin/linux/gdvapi.linux.editor.x86_64.so"
|
||||||
|
linux.template_debug.x86_64 = "res://bin/linux/gdvapi.linux.template_debug.x86_64.so"
|
||||||
1
project/bin/gdvapi.gdextension.uid
Normal file
1
project/bin/gdvapi.gdextension.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://vgmwthvwcljf
|
||||||
@@ -2,5 +2,5 @@ extends Node
|
|||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
var example := ExampleClass.new()
|
#$GDVAPIVideoStream.begin("udp://0.0.0.0:5000")
|
||||||
example.print_type(example)
|
pass
|
||||||
|
|||||||
1
project/example.gd.uid
Normal file
1
project/example.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bkwk40ybs8kgm
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://dh0oj81pufivs"]
|
[gd_scene format=3 uid="uid://dh0oj81pufivs"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://example.gd" id="1_jdh55"]
|
[ext_resource type="Script" uid="uid://bkwk40ybs8kgm" path="res://example.gd" id="1_jdh55"]
|
||||||
|
|
||||||
[node name="Node" type="Node"]
|
[node name="Node" type="Node" unique_id=2080300232]
|
||||||
script = ExtResource("1_jdh55")
|
script = ExtResource("1_jdh55")
|
||||||
|
|
||||||
|
[node name="GDVAPIVideoStream" type="GDVAPIVideoStream" parent="." unique_id=1053894928]
|
||||||
|
offset_right = 40.0
|
||||||
|
offset_bottom = 40.0
|
||||||
|
|||||||
49
project/export_presets.cfg
Normal file
49
project/export_presets.cfg
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
[runnable_presets]
|
||||||
|
|
||||||
|
Linux="Linux"
|
||||||
|
|
||||||
|
[preset.0]
|
||||||
|
|
||||||
|
name="Linux"
|
||||||
|
platform="Linux"
|
||||||
|
dedicated_server=false
|
||||||
|
custom_features=""
|
||||||
|
export_filter="all_resources"
|
||||||
|
include_filter=""
|
||||||
|
exclude_filter=""
|
||||||
|
export_path="exports/godot cpp template.x86_64"
|
||||||
|
patches=PackedStringArray()
|
||||||
|
patch_delta_encoding=false
|
||||||
|
patch_delta_compression_level_zstd=19
|
||||||
|
patch_delta_min_reduction=0.1
|
||||||
|
patch_delta_include_filters="*"
|
||||||
|
patch_delta_exclude_filters=""
|
||||||
|
encryption_include_filters=""
|
||||||
|
encryption_exclude_filters=""
|
||||||
|
seed=0
|
||||||
|
encrypt_pck=false
|
||||||
|
encrypt_directory=false
|
||||||
|
script_export_mode=2
|
||||||
|
|
||||||
|
[preset.0.options]
|
||||||
|
|
||||||
|
custom_template/debug=""
|
||||||
|
custom_template/release=""
|
||||||
|
debug/export_console_wrapper=1
|
||||||
|
binary_format/embed_pck=false
|
||||||
|
texture_format/s3tc_bptc=true
|
||||||
|
texture_format/etc2_astc=false
|
||||||
|
shader_baker/enabled=false
|
||||||
|
binary_format/architecture="x86_64"
|
||||||
|
ssh_remote_deploy/enabled=false
|
||||||
|
ssh_remote_deploy/host="user@host_ip"
|
||||||
|
ssh_remote_deploy/port="22"
|
||||||
|
ssh_remote_deploy/extra_args_ssh=""
|
||||||
|
ssh_remote_deploy/extra_args_scp=""
|
||||||
|
ssh_remote_deploy/run_script="#!/usr/bin/env bash
|
||||||
|
export DISPLAY=:0
|
||||||
|
unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\"
|
||||||
|
\"{temp_dir}/{exe_name}\" {cmd_args}"
|
||||||
|
ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash
|
||||||
|
pkill -x -f \"{temp_dir}/{exe_name} {cmd_args}\"
|
||||||
|
rm -rf \"{temp_dir}\""
|
||||||
BIN
project/exports/badapple.mov
Normal file
BIN
project/exports/badapple.mov
Normal file
Binary file not shown.
BIN
project/exports/godot cpp template.pck
Normal file
BIN
project/exports/godot cpp template.pck
Normal file
Binary file not shown.
4
project/exports/godot cpp template.sh
Executable file
4
project/exports/godot cpp template.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
printf '\033c\033]0;%s\a' godot cpp template
|
||||||
|
base_path="$(dirname "$(realpath "$0")")"
|
||||||
|
"$base_path/godot cpp template.x86_64" "$@"
|
||||||
BIN
project/exports/godot cpp template.x86_64
Executable file
BIN
project/exports/godot cpp template.x86_64
Executable file
Binary file not shown.
@@ -18,6 +18,8 @@ dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.cte
|
|||||||
compress/mode=0
|
compress/mode=0
|
||||||
compress/high_quality=false
|
compress/high_quality=false
|
||||||
compress/lossy_quality=0.7
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
compress/hdr_compression=1
|
compress/hdr_compression=1
|
||||||
compress/normal_map=0
|
compress/normal_map=0
|
||||||
compress/channel_pack=0
|
compress/channel_pack=0
|
||||||
@@ -25,6 +27,10 @@ mipmaps/generate=false
|
|||||||
mipmaps/limit=-1
|
mipmaps/limit=-1
|
||||||
roughness/mode=0
|
roughness/mode=0
|
||||||
roughness/src_normal=""
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
process/fix_alpha_border=true
|
process/fix_alpha_border=true
|
||||||
process/premult_alpha=false
|
process/premult_alpha=false
|
||||||
process/normal_map_invert_y=false
|
process/normal_map_invert_y=false
|
||||||
|
|||||||
@@ -8,8 +8,18 @@
|
|||||||
|
|
||||||
config_version=5
|
config_version=5
|
||||||
|
|
||||||
|
[animation]
|
||||||
|
|
||||||
|
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
||||||
|
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="godot cpp template"
|
config/name="godot cpp template"
|
||||||
config/features=PackedStringArray("4.1", "Forward Plus")
|
run/main_scene="uid://dh0oj81pufivs"
|
||||||
|
config/features=PackedStringArray("4.7", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[display]
|
||||||
|
|
||||||
|
window/size/viewport_width=1920
|
||||||
|
window/size/viewport_height=1080
|
||||||
|
|||||||
BIN
project/test.mp4
Normal file
BIN
project/test.mp4
Normal file
Binary file not shown.
2
server-ffmpeg.sh
Executable file
2
server-ffmpeg.sh
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
ffmpeg -re -i $1 -c copy -f mpegts udp://127.0.0.1:5000
|
||||||
5
server-gst.sh
Normal file
5
server-gst.sh
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
gst-launch-1.0 filesrc location=$1 ! qtdemux name=demux \
|
||||||
|
demux.video_0 ! queue ! h264parse ! mpegtsmux name=mux ! udpsink host=127.0.0.1 port=5000 \
|
||||||
|
demux.audio_0 ! queue ! aacparse ! mux.
|
||||||
5
server_camera.sh
Executable file
5
server_camera.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i "$1" \
|
||||||
|
-c:v libx264 -preset ultrafast -tune zerolatency -g 30 -flags +global_header \
|
||||||
|
-f mpegts udp://127.0.0.1:5000?pkt_size=1316
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include "example_class.h"
|
|
||||||
|
|
||||||
void ExampleClass::_bind_methods() {
|
|
||||||
godot::ClassDB::bind_method(D_METHOD("print_type", "variant"), &ExampleClass::print_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExampleClass::print_type(const Variant &p_variant) const {
|
|
||||||
print_line(vformat("Type: %d", p_variant.get_type()));
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "godot_cpp/classes/ref_counted.hpp"
|
|
||||||
#include "godot_cpp/classes/wrapped.hpp"
|
|
||||||
#include "godot_cpp/variant/variant.hpp"
|
|
||||||
|
|
||||||
using namespace godot;
|
|
||||||
|
|
||||||
class ExampleClass : public RefCounted {
|
|
||||||
GDCLASS(ExampleClass, RefCounted)
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void _bind_methods();
|
|
||||||
|
|
||||||
public:
|
|
||||||
ExampleClass() = default;
|
|
||||||
~ExampleClass() override = default;
|
|
||||||
|
|
||||||
void print_type(const Variant &p_variant) const;
|
|
||||||
};
|
|
||||||
324
src/gdvapivideostream_class.cpp
Normal file
324
src/gdvapivideostream_class.cpp
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
#include "gdvapivideostream_class.h"
|
||||||
|
#include "godot_cpp/classes/project_settings.hpp"
|
||||||
|
#include "godot_cpp/classes/rd_texture_format.hpp"
|
||||||
|
#include "godot_cpp/classes/rd_texture_view.hpp"
|
||||||
|
#include "godot_cpp/classes/rendering_device.hpp"
|
||||||
|
#include "godot_cpp/classes/rendering_server.hpp"
|
||||||
|
#include "godot_cpp/variant/utility_functions.hpp"
|
||||||
|
#include "godot_cpp/variant/color.hpp"
|
||||||
|
#include "godot_cpp/variant/rect2.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/hwcontext.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace godot;
|
||||||
|
|
||||||
|
enum HWMode { HW_NONE,
|
||||||
|
HW_VULKAN,
|
||||||
|
HW_VAAPI };
|
||||||
|
static HWMode active_hw_mode = HW_NONE;
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::_bind_methods() {
|
||||||
|
godot::ClassDB::bind_method(D_METHOD("begin", "source"), &GDVAPIVideoStream::begin);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_desired_width"), &GDVAPIVideoStream::get_desired_width);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_desired_width", "v"), &GDVAPIVideoStream::set_desired_width);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("get_desired_height"), &GDVAPIVideoStream::get_desired_height);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_desired_height", "v"), &GDVAPIVideoStream::set_desired_height);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "desired_width"), "set_desired_width", "get_desired_width");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "desired_height"), "set_desired_height", "get_desired_height");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum AVPixelFormat get_hw_format(AVCodecContext *ctx, const enum AVPixelFormat *formats) {
|
||||||
|
for (const enum AVPixelFormat *p = formats; *p != -1; p++) {
|
||||||
|
if (active_hw_mode == HW_VULKAN && *p == AV_PIX_FMT_VULKAN) {
|
||||||
|
return AV_PIX_FMT_VULKAN;
|
||||||
|
}
|
||||||
|
if (active_hw_mode == HW_VAAPI && *p == AV_PIX_FMT_VAAPI) {
|
||||||
|
return AV_PIX_FMT_VAAPI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UtilityFunctions::printerr("[gdvapi] hardware decoding unavailable");
|
||||||
|
active_hw_mode = HW_NONE;
|
||||||
|
return AV_PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::begin(const Variant &source) {
|
||||||
|
String res_path = source;
|
||||||
|
String global_path = ProjectSettings::get_singleton()->globalize_path(res_path);
|
||||||
|
CharString path_utf8 = global_path.utf8();
|
||||||
|
|
||||||
|
fmt_ctx = nullptr;
|
||||||
|
if (avformat_open_input(&fmt_ctx, path_utf8.get_data(), nullptr, nullptr) < 0) {
|
||||||
|
UtilityFunctions::printerr("[gdvapi] failed to open input stream");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avformat_find_stream_info(fmt_ctx, nullptr) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
video_stream_idx = -1;
|
||||||
|
for (unsigned int i = 0; i < fmt_ctx->nb_streams; i++) {
|
||||||
|
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
video_stream_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (video_stream_idx == -1) return;
|
||||||
|
|
||||||
|
AVStream *stream = fmt_ctx->streams[video_stream_idx];
|
||||||
|
if (stream->avg_frame_rate.den > 0 && stream->avg_frame_rate.num > 0) {
|
||||||
|
double fps = av_q2d(stream->avg_frame_rate);
|
||||||
|
frame_delay = 1.0 / fps;
|
||||||
|
UtilityFunctions::print("[gdvapi] fps: ", fps, " frame delay: ", frame_delay, "s");
|
||||||
|
} else {
|
||||||
|
frame_delay = 1.0 / 60.0; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodecParameters *codec_par = fmt_ctx->streams[video_stream_idx]->codecpar;
|
||||||
|
codec = avcodec_find_decoder(codec_par->codec_id);
|
||||||
|
if (!codec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
codec_ctx = avcodec_alloc_context3(codec);
|
||||||
|
if (!codec_ctx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (avcodec_parameters_to_context(codec_ctx, codec_par) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
active_hw_mode = HW_VULKAN;
|
||||||
|
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VULKAN, nullptr, nullptr, 0) < 0) {
|
||||||
|
UtilityFunctions::print("[gdvapi] vulkan video extensions missing on driver, trying va-api");
|
||||||
|
|
||||||
|
active_hw_mode = HW_VAAPI;
|
||||||
|
if (av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, nullptr, nullptr, 0) < 0) {
|
||||||
|
UtilityFunctions::print("[gdvapi] va-api acceleration unavailable. using software");
|
||||||
|
active_hw_mode = HW_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active_hw_mode != HW_NONE) {
|
||||||
|
codec_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx);
|
||||||
|
codec_ctx->get_format = get_hw_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avcodec_open2(codec_ctx, codec, nullptr) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
frame = av_frame_alloc();
|
||||||
|
sw_frame = av_frame_alloc();
|
||||||
|
packet = av_packet_alloc();
|
||||||
|
|
||||||
|
width = codec_ctx->width;
|
||||||
|
height = codec_ctx->height;
|
||||||
|
texture_init();
|
||||||
|
|
||||||
|
sws_ctx = sws_getContext(
|
||||||
|
width, height, codec_ctx->pix_fmt,
|
||||||
|
width, height, AV_PIX_FMT_RGBA,
|
||||||
|
SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
time_accumulator = 0.0;
|
||||||
|
set_process(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::_process(double delta) {
|
||||||
|
if (!fmt_ctx || !codec_ctx) return;
|
||||||
|
|
||||||
|
time_accumulator += delta;
|
||||||
|
|
||||||
|
if (time_accumulator < frame_delay) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_accumulator -= frame_delay;
|
||||||
|
|
||||||
|
bool frame_finished = false;
|
||||||
|
while (!frame_finished && av_read_frame(fmt_ctx, packet) >= 0) {
|
||||||
|
if (packet->stream_index == video_stream_idx) {
|
||||||
|
if (avcodec_send_packet(codec_ctx, packet) >= 0) {
|
||||||
|
while (avcodec_receive_frame(codec_ctx, frame) >= 0) {
|
||||||
|
frame_finished = true;
|
||||||
|
|
||||||
|
RenderingDevice *rd = RenderingServer::get_singleton()->get_rendering_device();
|
||||||
|
if (!rd || !texture_rd_rid.is_valid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (frame->format == AV_PIX_FMT_VULKAN || frame->format == AV_PIX_FMT_VAAPI) {
|
||||||
|
if (av_hwframe_transfer_data(sw_frame, frame, 0) >= 0) {
|
||||||
|
PackedByteArray gpu_bytes;
|
||||||
|
gpu_bytes.resize(width * height * 4);
|
||||||
|
|
||||||
|
uint8_t *dest_pointers[4] = { gpu_bytes.ptrw(), nullptr, nullptr, nullptr };
|
||||||
|
int dest_linesizes[4] = { width * 4, 0, 0, 0 };
|
||||||
|
|
||||||
|
enum AVPixelFormat src_fmt = (enum AVPixelFormat)sw_frame->format;
|
||||||
|
struct SwsContext *hw_sws = sws_getContext(
|
||||||
|
width, height, src_fmt,
|
||||||
|
width, height, AV_PIX_FMT_RGBA,
|
||||||
|
SWS_BILINEAR, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
|
if (hw_sws) {
|
||||||
|
sws_scale(hw_sws, sw_frame->data, sw_frame->linesize, 0, height, dest_pointers, dest_linesizes);
|
||||||
|
sws_freeContext(hw_sws);
|
||||||
|
rd->texture_update(texture_rd_rid, 0, gpu_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (frame->data[0] != nullptr) {
|
||||||
|
PackedByteArray rgba_data;
|
||||||
|
rgba_data.resize(width * height * 4);
|
||||||
|
uint8_t *dest_pointers[4] = { rgba_data.ptrw(), nullptr, nullptr, nullptr };
|
||||||
|
int dest_linesizes[4] = { width * 4, 0, 0, 0 };
|
||||||
|
|
||||||
|
if (sws_ctx) {
|
||||||
|
sws_scale(sws_ctx, frame->data, frame->linesize, 0, height, dest_pointers, dest_linesizes);
|
||||||
|
rd->texture_update(texture_rd_rid, 0, rgba_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queue_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_packet_unref(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GDVAPIVideoStream::~GDVAPIVideoStream() {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::_notification(int p_what) {
|
||||||
|
switch (p_what) {
|
||||||
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
|
cleanup();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::texture_init() {
|
||||||
|
RenderingDevice *rd = RenderingServer::get_singleton()->get_rendering_device();
|
||||||
|
if (!rd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (texture_rd_rid.is_valid()) {
|
||||||
|
rd->free_rid(texture_rd_rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<RDTextureFormat> format;
|
||||||
|
format.instantiate();
|
||||||
|
format->set_texture_type(RenderingDevice::TEXTURE_TYPE_2D);
|
||||||
|
format->set_format(RenderingDevice::DATA_FORMAT_R8G8B8A8_UNORM);
|
||||||
|
format->set_width(width);
|
||||||
|
format->set_height(height);
|
||||||
|
format->set_depth(1);
|
||||||
|
format->set_array_layers(1);
|
||||||
|
format->set_mipmaps(1);
|
||||||
|
format->set_usage_bits(RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT |
|
||||||
|
RenderingDevice::TEXTURE_USAGE_CAN_UPDATE_BIT);
|
||||||
|
|
||||||
|
PackedByteArray byte_array;
|
||||||
|
byte_array.resize(width * height * 4);
|
||||||
|
|
||||||
|
TypedArray<PackedByteArray> data;
|
||||||
|
data.push_back(byte_array);
|
||||||
|
|
||||||
|
Ref<RDTextureView> view;
|
||||||
|
view.instantiate();
|
||||||
|
|
||||||
|
texture_rd_rid = rd->texture_create(format, view, data);
|
||||||
|
|
||||||
|
if (texture_rd_rid.is_valid()) {
|
||||||
|
godot_texture.instantiate();
|
||||||
|
godot_texture->set_texture_rd_rid(texture_rd_rid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::cleanup() {
|
||||||
|
set_process(false);
|
||||||
|
RenderingDevice *rd = RenderingServer::get_singleton()->get_rendering_device();
|
||||||
|
|
||||||
|
godot_texture.unref();
|
||||||
|
|
||||||
|
if (rd && texture_rd_rid.is_valid()) {
|
||||||
|
rd->free_rid(texture_rd_rid);
|
||||||
|
texture_rd_rid = RID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sws_ctx) {
|
||||||
|
sws_freeContext(sws_ctx);
|
||||||
|
sws_ctx = nullptr;
|
||||||
|
}
|
||||||
|
if (frame) {
|
||||||
|
av_frame_free(&frame);
|
||||||
|
}
|
||||||
|
if (sw_frame) {
|
||||||
|
av_frame_free(&sw_frame);
|
||||||
|
}
|
||||||
|
if (packet) {
|
||||||
|
av_packet_free(&packet);
|
||||||
|
}
|
||||||
|
if (codec_ctx) {
|
||||||
|
avcodec_free_context(&codec_ctx);
|
||||||
|
}
|
||||||
|
if (hw_device_ctx) {
|
||||||
|
av_buffer_unref(&hw_device_ctx);
|
||||||
|
hw_device_ctx = nullptr;
|
||||||
|
}
|
||||||
|
if (fmt_ctx) {
|
||||||
|
avformat_close_input(&fmt_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::_draw() {
|
||||||
|
UtilityFunctions::print("_draw called");
|
||||||
|
if (godot_texture.is_valid()) {
|
||||||
|
draw_texture(godot_texture, Point2(0, 0));
|
||||||
|
} else {
|
||||||
|
Rect2 rect = Rect2(0, 0, desiredWidth, desiredHeight);
|
||||||
|
|
||||||
|
Color color = Color(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
draw_rect(rect, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::set_desired_width(const int v) {
|
||||||
|
if (desiredWidth != v) {
|
||||||
|
desiredWidth = v;
|
||||||
|
queue_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::set_desired_height(const int v) {
|
||||||
|
if (desiredHeight != v) {
|
||||||
|
desiredHeight = v;
|
||||||
|
queue_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int GDVAPIVideoStream::get_desired_width() const {
|
||||||
|
return desiredWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GDVAPIVideoStream::get_desired_height() const {
|
||||||
|
return desiredHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GDVAPIVideoStream::_ready() {
|
||||||
|
UtilityFunctions::print("_ready called");
|
||||||
|
queue_redraw();
|
||||||
|
}
|
||||||
67
src/gdvapivideostream_class.h
Normal file
67
src/gdvapivideostream_class.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "godot_cpp/classes/control.hpp"
|
||||||
|
#include "godot_cpp/classes/texture2drd.hpp"
|
||||||
|
#include "godot_cpp/variant/rid.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <libavcodec/avcodec.h>
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <libavutil/imgutils.h>
|
||||||
|
#include <libswscale/swscale.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace godot {
|
||||||
|
|
||||||
|
class GDVAPIVideoStream : public Control {
|
||||||
|
GDCLASS(GDVAPIVideoStream, Control)
|
||||||
|
|
||||||
|
private:
|
||||||
|
AVFormatContext *fmt_ctx = nullptr;
|
||||||
|
AVCodecContext *codec_ctx = nullptr;
|
||||||
|
const AVCodec *codec = nullptr;
|
||||||
|
AVFrame *frame = nullptr;
|
||||||
|
AVPacket *packet = nullptr;
|
||||||
|
struct SwsContext *sws_ctx = nullptr;
|
||||||
|
int video_stream_idx = -1;
|
||||||
|
int width = 256;
|
||||||
|
int height = 256;
|
||||||
|
AVBufferRef *hw_device_ctx = nullptr;
|
||||||
|
AVFrame *sw_frame = nullptr;
|
||||||
|
|
||||||
|
double frame_delay = 0.0;
|
||||||
|
double time_accumulator = 0.0;
|
||||||
|
|
||||||
|
RID texture_rd_rid;
|
||||||
|
Ref<Texture2DRD> godot_texture;
|
||||||
|
|
||||||
|
|
||||||
|
int desiredWidth = 256;
|
||||||
|
int desiredHeight = 256;
|
||||||
|
|
||||||
|
void cleanup();
|
||||||
|
void texture_init();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
GDVAPIVideoStream() = default;
|
||||||
|
~GDVAPIVideoStream() override;
|
||||||
|
|
||||||
|
void begin(const Variant &source);
|
||||||
|
|
||||||
|
void _process(double delta) override;
|
||||||
|
|
||||||
|
void _notification(int p_what);
|
||||||
|
void _draw() override;
|
||||||
|
void _ready() override;
|
||||||
|
|
||||||
|
void set_desired_width(const int v);
|
||||||
|
int get_desired_width() const;
|
||||||
|
|
||||||
|
void set_desired_height(const int v);
|
||||||
|
int get_desired_height() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,34 +5,32 @@
|
|||||||
#include <godot_cpp/core/defs.hpp>
|
#include <godot_cpp/core/defs.hpp>
|
||||||
#include <godot_cpp/godot.hpp>
|
#include <godot_cpp/godot.hpp>
|
||||||
|
|
||||||
#include "example_class.h"
|
#include "gdvapivideostream_class.h"
|
||||||
|
|
||||||
using namespace godot;
|
using namespace godot;
|
||||||
|
|
||||||
void initialize_gdextension_types(ModuleInitializationLevel p_level)
|
void initialize_gdextension_types(ModuleInitializationLevel p_level) {
|
||||||
{
|
|
||||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GDREGISTER_CLASS(ExampleClass);
|
|
||||||
|
GDREGISTER_RUNTIME_CLASS(GDVAPIVideoStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void uninitialize_gdextension_types(ModuleInitializationLevel p_level) {
|
void uninitialize_gdextension_types(ModuleInitializationLevel p_level) {
|
||||||
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C" {
|
||||||
{
|
GDExtensionBool GDE_EXPORT gdvapi_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
|
||||||
// Initialization
|
|
||||||
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
|
|
||||||
{
|
|
||||||
GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
|
GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
|
||||||
init_obj.register_initializer(initialize_gdextension_types);
|
init_obj.register_initializer(initialize_gdextension_types);
|
||||||
init_obj.register_terminator(uninitialize_gdextension_types);
|
init_obj.register_terminator(uninitialize_gdextension_types);
|
||||||
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
|
||||||
|
|
||||||
return init_obj.init();
|
return init_obj.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user