mirror of
https://github.com/litruv/PNGTuber-Plus.git
synced 2026-07-24 02:26:02 +10:00
NDI Working
This commit is contained in:
145
NDI_SETUP_GUIDE.md
Normal file
145
NDI_SETUP_GUIDE.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# NDI Output for PNGTuber-Plus
|
||||
|
||||
This guide explains how to use the NDI (Network Device Interface) output feature in PNGTuber-Plus to stream your avatar to OBS Studio or other NDI-compatible applications.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **NDI Runtime**: Download and install the NDI Runtime from [NDI website](http://ndi.link/NDIRedistV6)
|
||||
- Windows: [NDI Runtime for Windows](http://ndi.link/NDIRedistV6)
|
||||
- macOS: [NDI Runtime for macOS](http://ndi.link/NDIRedistV6Apple)
|
||||
- Linux: [NDI Runtime for Linux](https://github.com/DistroAV/DistroAV/wiki/1.-Installation#linux) (Note: Flatpak incompatible)
|
||||
|
||||
2. **Godot 4.4-stable or later**: This plugin requires Godot 4.4+ to function properly
|
||||
|
||||
3. **NDI-compatible software**: Such as OBS Studio with NDI plugin, vMix, Wirecast, etc.
|
||||
|
||||
## Features
|
||||
|
||||
- **Real-time NDI streaming**: Stream your PNGTuber avatar over the network
|
||||
- **Audio support**: Include system audio in the NDI stream (optional)
|
||||
- **Customizable source name**: Set a custom name for your NDI source
|
||||
- **Hotkey controls**: Quick toggle streaming with keyboard shortcuts
|
||||
- **Settings UI**: Easy configuration through the settings menu
|
||||
|
||||
## Getting Started
|
||||
|
||||
### 1. Basic Setup
|
||||
|
||||
The NDI output is automatically enabled when you start PNGTuber-Plus. The default settings are:
|
||||
- **Source Name**: "PNGTuber-Plus"
|
||||
- **Audio**: Enabled (Master bus)
|
||||
- **Auto-start**: Enabled
|
||||
|
||||
### 2. Settings Menu Configuration
|
||||
|
||||
Access the NDI settings through the Settings Menu:
|
||||
|
||||
1. Click the settings wheel in PNGTuber-Plus
|
||||
2. Scroll down to find the "NDI streaming" section
|
||||
3. Configure the following options:
|
||||
- **NDI streaming**: Enable/disable NDI output
|
||||
- **Source name**: Set a custom name for your NDI source (default: "PNGTuber-Plus")
|
||||
- **Include audio**: Toggle audio streaming on/off
|
||||
- **Status**: View current streaming status
|
||||
- **Start/Stop NDI**: Manual control button
|
||||
|
||||
### 3. Hotkey Controls
|
||||
|
||||
Quick keyboard shortcuts for NDI control:
|
||||
- **F9**: Toggle NDI streaming on/off
|
||||
- **F10**: Restart NDI streaming (useful for applying new settings)
|
||||
|
||||
### 4. OBS Studio Setup
|
||||
|
||||
To capture the NDI stream in OBS Studio:
|
||||
|
||||
1. **Install NDI Plugin for OBS**:
|
||||
- Download from [OBS NDI Plugin](https://github.com/Palakis/obs-ndi/releases)
|
||||
- Install following the provided instructions
|
||||
|
||||
2. **Add NDI Source in OBS**:
|
||||
- In OBS, click the "+" in Sources
|
||||
- Select "NDI Source"
|
||||
- Name your source (e.g., "PNGTuber Avatar")
|
||||
- In the properties, select your NDI source from the dropdown
|
||||
- Look for "PNGTuber-Plus" (or your custom name)
|
||||
- Configure audio settings as needed
|
||||
|
||||
3. **Position and Scale**:
|
||||
- Resize and position the NDI source in your scene
|
||||
- The stream will include the full PNGTuber viewport
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### NDI Source Not Appearing in OBS
|
||||
|
||||
1. **Check NDI Runtime**: Ensure NDI Runtime is installed on both machines
|
||||
2. **Network connectivity**: NDI works over network, ensure devices can communicate
|
||||
3. **Firewall settings**: NDI uses specific ports, check firewall rules
|
||||
4. **Restart applications**: Try restarting both PNGTuber-Plus and OBS
|
||||
5. **Check source name**: Verify the NDI source name matches in settings
|
||||
|
||||
### Audio Issues
|
||||
|
||||
1. **Audio bus**: Ensure the correct audio bus is selected (default: "Master")
|
||||
2. **System audio**: Check that PNGTuber-Plus is receiving audio input
|
||||
3. **OBS audio settings**: Verify NDI source audio is not muted in OBS
|
||||
|
||||
### Performance Issues
|
||||
|
||||
1. **Network bandwidth**: NDI requires good network performance for quality streaming
|
||||
2. **Local streaming**: For best performance, use NDI on the same machine
|
||||
3. **Resolution**: Lower viewport resolution if experiencing lag
|
||||
4. **Frame rate**: Adjust FPS settings in PNGTuber-Plus settings
|
||||
|
||||
### NDI Not Working
|
||||
|
||||
1. **Godot version**: Ensure you're using Godot 4.4-stable or later
|
||||
2. **Plugin enabled**: Verify the godot-ndi plugin is properly installed
|
||||
3. **System compatibility**: Check NDI Runtime compatibility with your OS
|
||||
4. **Console errors**: Check Godot console for any NDI-related errors
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom Audio Bus
|
||||
|
||||
You can route specific audio to NDI by:
|
||||
1. Creating a custom audio bus in PNGTuber-Plus
|
||||
2. Setting the NDI audio bus to your custom bus name
|
||||
3. Routing desired audio sources to that bus
|
||||
|
||||
### Network Performance
|
||||
|
||||
For optimal network streaming:
|
||||
- Use wired connections when possible
|
||||
- Ensure sufficient bandwidth (>100 Mbps recommended for high quality)
|
||||
- Keep NDI devices on the same network segment
|
||||
- Consider NDI quality settings if available
|
||||
|
||||
### Multiple Instances
|
||||
|
||||
You can run multiple PNGTuber-Plus instances with different NDI source names:
|
||||
1. Change the "Source name" in each instance
|
||||
2. Each will appear as a separate NDI source
|
||||
3. Useful for multiple avatars or backup streams
|
||||
|
||||
## Technical Details
|
||||
|
||||
- **Video Format**: NDI handles video format automatically based on viewport
|
||||
- **Audio Format**: Uses the selected audio bus output
|
||||
- **Compression**: NDI uses efficient compression for network streaming
|
||||
- **Latency**: Typically very low latency (<1 frame) on local network
|
||||
|
||||
## Legal Notice
|
||||
|
||||
NDI® is a registered trademark of Vizrt NDI AB. Your application must comply with the [NDI SDK license](http://ndi.link/ndisdk_license) when using this feature.
|
||||
|
||||
## Support
|
||||
|
||||
For issues specific to NDI functionality:
|
||||
1. Check the console output for error messages
|
||||
2. Verify NDI Runtime installation
|
||||
3. Test with other NDI applications to isolate issues
|
||||
4. Check network connectivity for remote streaming
|
||||
|
||||
For PNGTuber-Plus specific issues, refer to the main application documentation and support channels.
|
||||
Binary file not shown.
379
addons/godot-ndi/LICENSE
Normal file
379
addons/godot-ndi/LICENSE
Normal file
@@ -0,0 +1,379 @@
|
||||
|
||||
https://github.com/unvermuthet/godot-ndi
|
||||
|
||||
(C) 2025 Henry Muth - unvermuthet
|
||||
|
||||
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
52
addons/godot-ndi/NOTICE.md
Normal file
52
addons/godot-ndi/NOTICE.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Third-party software
|
||||
|
||||
## NDI SDK
|
||||
|
||||
- `ndi/*.h`
|
||||
|
||||
### MIT License
|
||||
|
||||
> The following MIT license applies to these files ONLY and not to the SDK as a whole. Please review the SDK documentation for the description of the full license terms, which are also provided in the file "NDI License Agreement.pdf" within the SDK or online at http://ndi.link/ndisdk_license. Your use of any part of this SDK is acknowledgment that you agree to the SDK license terms. The full NDI SDK may be downloaded at http://ndi.video/
|
||||
|
||||
Copyright (C) 2023-2024 Vizrt NDI AB. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files(the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 OR COPYRIGHT HOLDERS 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.
|
||||
|
||||
## godot-cpp
|
||||
|
||||
- `godot-cpp/**`
|
||||
|
||||
### MIT License
|
||||
|
||||
Copyright (c) 2017-present Godot Engine contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 OR COPYRIGHT HOLDERS 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.
|
||||
62
addons/godot-ndi/README.md
Normal file
62
addons/godot-ndi/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# godot-ndi [](https://godotengine.org) [](https://github.com/unvermuthet/godot-ndi/actions/workflows/builds.yml)
|
||||
|
||||
> Integrates the NDI® SDK with Godot
|
||||
>
|
||||
> [ NDI® is a registered trademark of Vizrt NDI AB ]
|
||||
|
||||
Adds a new [VideoStream](https://godot-ndi.readthedocs.io/stable/classes/class_videostreamndi.html) class to implement **NDI playback**.
|
||||
For **outputting the Viewport** as an NDI source, add the [NDIOutput](https://godot-ndi.readthedocs.io/stable/classes/class_ndioutput.html) Node to the scene.
|
||||
Check out the **demo scenes** included with all releases.
|
||||
|
||||
This was born out of work on my DMX Lighting Control Software. I'm fascinated by Live Event Productions, Projection Mapping, TechArt, and Broadcasting. [So reach out](https://discord.com/users/203583245223198722) or [show off](https://github.com/unvermuthet/godot-ndi/discussions/categories/show-and-tell) what you made with Godot NDI!
|
||||
|
||||
<!-- [](https://discord.com/users/203583245223198722) -->
|
||||
|
||||

|
||||
|
||||
> This GIF only shows local transmission, but imagine this over the network!
|
||||
|
||||
## Install
|
||||
|
||||
> [!IMPORTANT]
|
||||
> - Only compatible with `Godot 4.4-stable` and later
|
||||
> - Your application needs to comply with the [NDI SDK license](http://ndi.link/ndisdk_license).
|
||||
> - The NDI Runtime is required ([Windows](http://ndi.link/NDIRedistV6), [MacOS](http://ndi.link/NDIRedistV6Apple), [Linux (Flatpak incompatible)](https://github.com/DistroAV/DistroAV/wiki/1.-Installation#linux))
|
||||
|
||||
Download the latest version under `Releases` and install by extracting the ZIP file in your Godot project.
|
||||
Alternatively, you can install the extension from Godot's Asset Library.
|
||||
|
||||
## Support
|
||||
|
||||
For ***commercial*** support, exclusive alternative licensing, or [NDI Advanced SDK](https://ndi.video/for-developers/ndi-advanced/) integration, contact me at [godot-ndi@muth.pro](mailto:godot-ndi@muth.pro).
|
||||
|
||||
In the production industries, software usually comes with exorbitant licensing fees. If this project has been useful to you and you want to show appreciation for my time and effort, consider a donation.
|
||||
|
||||
[](https://ko-fi.com/I2I51A7ZC3)
|
||||
|
||||
## Building from source
|
||||
|
||||
To help you get going, I've configured a [Development Container](https://containers.dev/) with everything set up to target Windows or Linux. Just run `scons` or check `scons --help`!
|
||||
|
||||
If you want to configure the environment yourself, follow [Godot's "Building from source" Guide](https://docs.godotengine.org/en/latest/contributing/development/compiling/). This project uses an identical build system.
|
||||
|
||||
## License
|
||||
|
||||
**(C) 2025-present Henry Muth - unvermuthet and Godot NDI contributors**
|
||||
|
||||
### Software
|
||||
|
||||
Subject to the terms of the [Mozilla Public License, v. 2.0](https://www.mozilla.org/en-US/MPL/2.0/)
|
||||
|
||||
### Documentation
|
||||
|
||||
Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
### Attribution suggestion
|
||||
|
||||
```
|
||||
godot-ndi
|
||||
Licensed under MPL-2.0
|
||||
(C) 2025-present Henry Muth - unvermuthet and Godot NDI contributors
|
||||
https://github.com/unvermuthet/godot-ndi
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
73
addons/godot-ndi/demo/3DOutput.tscn
Normal file
73
addons/godot-ndi/demo/3DOutput.tscn
Normal file
@@ -0,0 +1,73 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://deioml0m7ep1t"]
|
||||
|
||||
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_4r73q"]
|
||||
emission_shape = 1
|
||||
emission_sphere_radius = 1.0
|
||||
direction = Vector3(0, 1, 0)
|
||||
initial_velocity_min = 2.0
|
||||
initial_velocity_max = 6.0
|
||||
|
||||
[sub_resource type="SphereMesh" id="SphereMesh_jpqj6"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_ln6fu"]
|
||||
font_size = 24
|
||||
shadow_size = 5
|
||||
shadow_color = Color(0, 0, 0, 0.235294)
|
||||
|
||||
[node name="3DOutput" type="SubViewportContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
stretch = true
|
||||
|
||||
[node name="Node3D" type="Node3D" parent="."]
|
||||
|
||||
[node name="GPUParticles3D" type="GPUParticles3D" parent="Node3D"]
|
||||
amount = 32
|
||||
lifetime = 2.0
|
||||
process_material = SubResource("ParticleProcessMaterial_4r73q")
|
||||
draw_pass_1 = SubResource("SphereMesh_jpqj6")
|
||||
|
||||
[node name="SubViewportB" type="SubViewport" parent="."]
|
||||
handle_input_locally = false
|
||||
size = Vector2i(1152, 648)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="NDIOutput" type="NDIOutput" parent="SubViewportB"]
|
||||
name = "Godot Cam B"
|
||||
enable_editor_output = true
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="SubViewportB"]
|
||||
transform = Transform3D(1, 0, 0, 0, -0.0010647, 0.999999, 0, -0.999999, -0.0010647, 0, 6.41845, 0)
|
||||
current = true
|
||||
|
||||
[node name="SubViewportA" type="SubViewport" parent="."]
|
||||
handle_input_locally = false
|
||||
size = Vector2i(1152, 648)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="NDIOutput" type="NDIOutput" parent="SubViewportA"]
|
||||
name = "Godot Cam A"
|
||||
enable_editor_output = true
|
||||
|
||||
[node name="Label" type="Label" parent="SubViewportA"]
|
||||
anchors_preset = 2
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 31.0
|
||||
offset_top = -357.0
|
||||
offset_right = 534.0
|
||||
offset_bottom = -27.0
|
||||
grow_vertical = 0
|
||||
text = "NDIOutput always transmits the Viewport closest up the Tree. When running in the Editor that's the 2D View.
|
||||
|
||||
If you want to display a camera view, add NDIOutput to a SubViewport instead. You can skip the SubViewportContainer incase you don't need the Scene to be visible when running the Game. "
|
||||
label_settings = SubResource("LabelSettings_ln6fu")
|
||||
horizontal_alignment = 3
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="SubViewportA"]
|
||||
transform = Transform3D(0.99299, -0.0520139, 0.106136, 0, 0.897966, 0.440065, -0.118196, -0.43698, 0.891672, -2.28829, 1.75016, 5.03714)
|
||||
current = true
|
||||
58
addons/godot-ndi/demo/AnimationOutput.tscn
Normal file
58
addons/godot-ndi/demo/AnimationOutput.tscn
Normal file
@@ -0,0 +1,58 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://p6ywmqtt7nke"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://cfvxj5cdj3n45" path="res://addons/godot-ndi/demo/assets/icon.svg" id="1_ekn6m"]
|
||||
|
||||
[sub_resource type="Animation" id="Animation_62e2m"]
|
||||
length = 0.001
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Icon:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [Vector2(1034, 527)]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_0fbet"]
|
||||
resource_name = "new_animation"
|
||||
length = 8.0
|
||||
loop_mode = 1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Icon:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 3.9627, 7.9587),
|
||||
"transitions": PackedFloat32Array(1, 1, 1),
|
||||
"update": 0,
|
||||
"values": [Vector2(116, 119), Vector2(1034, 527), Vector2(116, 119)]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ee4bf"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_62e2m"),
|
||||
&"new_animation": SubResource("Animation_0fbet")
|
||||
}
|
||||
|
||||
[node name="SubViewport" type="Node2D"]
|
||||
|
||||
[node name="NDIOutput" type="NDIOutput" parent="."]
|
||||
name = "Godot (Animation)"
|
||||
|
||||
[node name="Icon" type="Sprite2D" parent="."]
|
||||
position = Vector2(1034, 527)
|
||||
scale = Vector2(1.463, 1.463)
|
||||
texture = ExtResource("1_ekn6m")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
&"": SubResource("AnimationLibrary_ee4bf")
|
||||
}
|
||||
autoplay = "new_animation"
|
||||
28
addons/godot-ndi/demo/Finder.tscn
Normal file
28
addons/godot-ndi/demo/Finder.tscn
Normal file
@@ -0,0 +1,28 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://dydvtidqppffs"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://kbgdevvugj7k" path="res://addons/godot-ndi/demo/ndi_finder.gd" id="1_0rvup"]
|
||||
|
||||
[node name="Canvas" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VideoStreamPlayer" type="VideoStreamPlayer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
autoplay = true
|
||||
expand = true
|
||||
|
||||
[node name="NDIFinder" type="NDIFinder" parent="."]
|
||||
script = ExtResource("1_0rvup")
|
||||
|
||||
[connection signal="sources_changed" from="NDIFinder" to="NDIFinder" method="_on_sources_changed"]
|
||||
[connection signal="sources_found" from="NDIFinder" to="NDIFinder" method="_on_sources_found"]
|
||||
[connection signal="sources_gone" from="NDIFinder" to="NDIFinder" method="_on_sources_gone"]
|
||||
22
addons/godot-ndi/demo/VideoInput.tscn
Normal file
22
addons/godot-ndi/demo/VideoInput.tscn
Normal file
@@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://byblss3lhwvqm"]
|
||||
|
||||
[sub_resource type="VideoStreamNDI" id="VideoStreamNDI_lv7vm"]
|
||||
|
||||
[node name="Canvas" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VideoStreamPlayer" type="VideoStreamPlayer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
stream = SubResource("VideoStreamNDI_lv7vm")
|
||||
autoplay = true
|
||||
expand = true
|
||||
37
addons/godot-ndi/demo/VideoOutput.tscn
Normal file
37
addons/godot-ndi/demo/VideoOutput.tscn
Normal file
@@ -0,0 +1,37 @@
|
||||
[gd_scene load_steps=5 format=3 uid="uid://ddr3hiaft61tl"]
|
||||
|
||||
[ext_resource type="VideoStream" uid="uid://0whnog13yrlf" path="res://addons/godot-ndi/demo/assets/liftoff_space_shuttle_atlantis.ogv" id="1_utmvk"]
|
||||
[ext_resource type="AudioStream" uid="uid://dyvxmok1n3vu1" path="res://addons/godot-ndi/demo/assets/sub-d-more-jazz-guitar.wav" id="2_51pmd"]
|
||||
[ext_resource type="Script" uid="uid://d2sex4jisnkck" path="res://addons/godot-ndi/demo/video_stream_player.gd" id="2_w6vuq"]
|
||||
[ext_resource type="VideoStream" path="res://addons/godot-ndi/demo/assets/twitch_sync_footage.ogv" id="3_ug8g3"]
|
||||
|
||||
[node name="Canvas" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="VideoStreamPlayer" type="VideoStreamPlayer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
volume_db = -15.0
|
||||
autoplay = true
|
||||
script = ExtResource("2_w6vuq")
|
||||
playlist = Array[VideoStream]([ExtResource("1_utmvk"), ExtResource("3_ug8g3")])
|
||||
|
||||
[node name="AudioStreamPlayer" type="AudioStreamPlayer2D" parent="."]
|
||||
stream = ExtResource("2_51pmd")
|
||||
autoplay = true
|
||||
panning_strength = 0.0
|
||||
|
||||
[node name="NDIOutput" type="NDIOutput" parent="."]
|
||||
name = "Godot (Video)"
|
||||
audio_bus = &"Master"
|
||||
|
||||
[connection signal="finished" from="VideoStreamPlayer" to="VideoStreamPlayer" method="_on_finished"]
|
||||
1
addons/godot-ndi/demo/assets/icon.svg
Normal file
1
addons/godot-ndi/demo/assets/icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||
|
After Width: | Height: | Size: 994 B |
37
addons/godot-ndi/demo/assets/icon.svg.import
Normal file
37
addons/godot-ndi/demo/assets/icon.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cfvxj5cdj3n45"
|
||||
path="res://.godot/imported/icon.svg-5dbb75b05306facc4cf78b15baaae64d.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-ndi/demo/assets/icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-5dbb75b05306facc4cf78b15baaae64d.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
BIN
addons/godot-ndi/demo/assets/liftoff_space_shuttle_atlantis.ogv
Normal file
BIN
addons/godot-ndi/demo/assets/liftoff_space_shuttle_atlantis.ogv
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
uid://0whnog13yrlf
|
||||
BIN
addons/godot-ndi/demo/assets/sub-d-more-jazz-guitar.wav
Normal file
BIN
addons/godot-ndi/demo/assets/sub-d-more-jazz-guitar.wav
Normal file
Binary file not shown.
@@ -0,0 +1,24 @@
|
||||
[remap]
|
||||
|
||||
importer="wav"
|
||||
type="AudioStreamWAV"
|
||||
uid="uid://dyvxmok1n3vu1"
|
||||
path="res://.godot/imported/sub-d-more-jazz-guitar.wav-6bba7f91e7070b729764277f88bb96b0.sample"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-ndi/demo/assets/sub-d-more-jazz-guitar.wav"
|
||||
dest_files=["res://.godot/imported/sub-d-more-jazz-guitar.wav-6bba7f91e7070b729764277f88bb96b0.sample"]
|
||||
|
||||
[params]
|
||||
|
||||
force/8_bit=false
|
||||
force/mono=false
|
||||
force/max_rate=false
|
||||
force/max_rate_hz=44100
|
||||
edit/trim=false
|
||||
edit/normalize=true
|
||||
edit/loop_mode=2
|
||||
edit/loop_begin=0
|
||||
edit/loop_end=-1
|
||||
compress/mode=2
|
||||
BIN
addons/godot-ndi/demo/assets/twitch_sync_footage.ogv
Normal file
BIN
addons/godot-ndi/demo/assets/twitch_sync_footage.ogv
Normal file
Binary file not shown.
1
addons/godot-ndi/demo/assets/twitch_sync_footage.ogv.uid
Normal file
1
addons/godot-ndi/demo/assets/twitch_sync_footage.ogv.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://4mp8kyfc212k
|
||||
13
addons/godot-ndi/demo/ndi_finder.gd
Normal file
13
addons/godot-ndi/demo/ndi_finder.gd
Normal file
@@ -0,0 +1,13 @@
|
||||
extends NDIFinder
|
||||
|
||||
@onready var player: VideoStreamPlayer = $"../VideoStreamPlayer"
|
||||
|
||||
func _on_sources_changed() -> void:
|
||||
player.stream = get_sources().pop_front()
|
||||
player.play()
|
||||
|
||||
func _on_sources_found(found_sources: Array[VideoStreamNDI]) -> void:
|
||||
print("NDI sources found: ", found_sources.map(func (source: VideoStreamNDI): return source.get_name()))
|
||||
|
||||
func _on_sources_gone(gone_sources: Array[VideoStreamNDI]) -> void:
|
||||
print("NDI sources gone: ", gone_sources.map(func (source: VideoStreamNDI): return source.get_name()))
|
||||
1
addons/godot-ndi/demo/ndi_finder.gd.uid
Normal file
1
addons/godot-ndi/demo/ndi_finder.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://kbgdevvugj7k
|
||||
17
addons/godot-ndi/demo/video_stream_player.gd
Normal file
17
addons/godot-ndi/demo/video_stream_player.gd
Normal file
@@ -0,0 +1,17 @@
|
||||
extends VideoStreamPlayer
|
||||
|
||||
@export var playlist: Array[VideoStream] = []
|
||||
|
||||
func _ready() -> void:
|
||||
_on_finished()
|
||||
|
||||
func _on_finished() -> void:
|
||||
if playlist.is_empty():
|
||||
return
|
||||
|
||||
var next_idx = playlist.find(stream) + 1
|
||||
if next_idx >= playlist.size():
|
||||
next_idx = 0
|
||||
|
||||
stream = playlist[next_idx]
|
||||
play()
|
||||
1
addons/godot-ndi/demo/video_stream_player.gd.uid
Normal file
1
addons/godot-ndi/demo/video_stream_player.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d2sex4jisnkck
|
||||
18
addons/godot-ndi/godot-ndi.gdextension
Normal file
18
addons/godot-ndi/godot-ndi.gdextension
Normal file
@@ -0,0 +1,18 @@
|
||||
[configuration]
|
||||
|
||||
entry_symbol = "godot_ndi_init"
|
||||
compatibility_minimum = "4.4"
|
||||
reloadable = false
|
||||
|
||||
[libraries]
|
||||
|
||||
linux.x86_64.single = "bin/linux/libgodot-ndi.linux.template_debug.x86_64.so"
|
||||
linux.arm64.single = "bin/linux/libgodot-ndi.linux.template_debug.arm64.so"
|
||||
windows.x86_64.single = "bin/windows/libgodot-ndi.windows.template_debug.x86_64.dll"
|
||||
macos.single = "bin/macos/libgodot-ndi.macos.template_debug.universal.dylib"
|
||||
|
||||
[icons]
|
||||
|
||||
VideoStreamNDI = "icons/VideoStreamNDI.svg"
|
||||
NDIOutput = "icons/NDIOutput.svg"
|
||||
NDIFinder = "icons/NDIFinder.svg"
|
||||
1
addons/godot-ndi/godot-ndi.gdextension.uid
Normal file
1
addons/godot-ndi/godot-ndi.gdextension.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ccdh6w16n2no5
|
||||
8
addons/godot-ndi/icons/NDIFinder.svg
Normal file
8
addons/godot-ndi/icons/NDIFinder.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none">
|
||||
<path d="m6 10-3.5 3.5" stroke="#e4eded" stroke-linecap="round" stroke-width="3"/>
|
||||
<circle cx="9.3341" cy="6.5" r="4.0547" stroke="#fa3d49" stroke-width="1.5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 390 B |
37
addons/godot-ndi/icons/NDIFinder.svg.import
Normal file
37
addons/godot-ndi/icons/NDIFinder.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bjqtfd5qckc6l"
|
||||
path="res://.godot/imported/NDIFinder.svg-6145b2a9070199a0c93ffe21a332ddf0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-ndi/icons/NDIFinder.svg"
|
||||
dest_files=["res://.godot/imported/NDIFinder.svg-6145b2a9070199a0c93ffe21a332ddf0.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
6
addons/godot-ndi/icons/NDIOutput.svg
Normal file
6
addons/godot-ndi/icons/NDIOutput.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="8" cy="8" r="7.2363" fill="#e4eded" stroke-width="11.339"/>
|
||||
<circle cx="8" cy="8" r="3.247" fill="#fa3d49" stroke-width="1.284"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 346 B |
37
addons/godot-ndi/icons/NDIOutput.svg.import
Normal file
37
addons/godot-ndi/icons/NDIOutput.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cvv0gnogt1vac"
|
||||
path="res://.godot/imported/NDIOutput.svg-b19965324d53dea421ada474b6902c23.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-ndi/icons/NDIOutput.svg"
|
||||
dest_files=["res://.godot/imported/NDIOutput.svg-b19965324d53dea421ada474b6902c23.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
7
addons/godot-ndi/icons/VideoStreamNDI.svg
Normal file
7
addons/godot-ndi/icons/VideoStreamNDI.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m11 15 4.3235-7h-4.3235l-3.4993 5.5046-0.08129 1.4954z" fill="#484d3d"/>
|
||||
<path d="m11 15s-6-1-6-7 6-7 6-7h-10v14z" fill="#e4eded"/>
|
||||
<circle cx="11" cy="8" r="2.5288" fill="#fa3d49"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 397 B |
37
addons/godot-ndi/icons/VideoStreamNDI.svg.import
Normal file
37
addons/godot-ndi/icons/VideoStreamNDI.svg.import
Normal file
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://pfqe4htodj7k"
|
||||
path="res://.godot/imported/VideoStreamNDI.svg-79e19fa3a194ede543418d01dcbbb6a7.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/godot-ndi/icons/VideoStreamNDI.svg"
|
||||
dest_files=["res://.godot/imported/VideoStreamNDI.svg-79e19fa3a194ede543418d01dcbbb6a7.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
Binary file not shown.
110
main_scenes/NDIOutputManager.gd
Normal file
110
main_scenes/NDIOutputManager.gd
Normal file
@@ -0,0 +1,110 @@
|
||||
class_name NDIOutputManager
|
||||
extends Node
|
||||
|
||||
## NDI Output Manager for PNGTuber-Plus
|
||||
## Handles NDI streaming output for OBS integration
|
||||
##
|
||||
## This class manages the NDI output functionality, allowing the PNGTuber-Plus
|
||||
## avatar to be streamed as an NDI source that can be captured by OBS Studio
|
||||
## or other NDI-compatible applications.
|
||||
|
||||
@export var ndi_source_name: String = "PNGTuber-Plus"
|
||||
@export var enable_audio: bool = true
|
||||
@export var audio_bus_name: String = "Master"
|
||||
@export var auto_start: bool = true
|
||||
|
||||
var ndi_output: NDIOutput
|
||||
var is_streaming: bool = false
|
||||
|
||||
## Called when the node enters the scene tree
|
||||
func _ready() -> void:
|
||||
if auto_start:
|
||||
initialize_ndi_output()
|
||||
|
||||
## Initialize the NDI output node and configure it
|
||||
func initialize_ndi_output() -> void:
|
||||
# Create NDI output node if it doesn't exist
|
||||
if not ndi_output:
|
||||
ndi_output = NDIOutput.new()
|
||||
add_child(ndi_output)
|
||||
|
||||
# Configure NDI output settings
|
||||
configure_ndi_output()
|
||||
|
||||
print("NDI Output initialized with source name: ", ndi_source_name)
|
||||
|
||||
## Configure the NDI output with current settings
|
||||
func configure_ndi_output() -> void:
|
||||
if not ndi_output:
|
||||
push_error("NDI Output node not found")
|
||||
return
|
||||
|
||||
# Set the NDI source name
|
||||
ndi_output.name = ndi_source_name
|
||||
|
||||
# Configure audio if enabled
|
||||
if enable_audio:
|
||||
ndi_output.audio_bus = StringName(audio_bus_name)
|
||||
|
||||
print("NDI Output configured - Name: ", ndi_source_name, " Audio: ", enable_audio)
|
||||
|
||||
## Start NDI streaming
|
||||
func start_streaming() -> void:
|
||||
if not ndi_output:
|
||||
initialize_ndi_output()
|
||||
|
||||
if ndi_output and not is_streaming:
|
||||
is_streaming = true
|
||||
print("NDI streaming started - Source: ", ndi_source_name)
|
||||
|
||||
## Stop NDI streaming
|
||||
func stop_streaming() -> void:
|
||||
if ndi_output and is_streaming:
|
||||
is_streaming = false
|
||||
print("NDI streaming stopped")
|
||||
|
||||
## Toggle NDI streaming on/off
|
||||
func toggle_streaming() -> bool:
|
||||
if is_streaming:
|
||||
stop_streaming()
|
||||
return false
|
||||
else:
|
||||
start_streaming()
|
||||
return true
|
||||
|
||||
## Update the NDI source name
|
||||
func set_source_name(new_name: String) -> void:
|
||||
ndi_source_name = new_name
|
||||
if ndi_output:
|
||||
ndi_output.name = ndi_source_name
|
||||
print("NDI source name changed to: ", ndi_source_name)
|
||||
|
||||
## Enable or disable audio streaming
|
||||
func set_audio_enabled(enabled: bool) -> void:
|
||||
enable_audio = enabled
|
||||
if ndi_output:
|
||||
if enable_audio:
|
||||
ndi_output.audio_bus = StringName(audio_bus_name)
|
||||
else:
|
||||
ndi_output.audio_bus = StringName("")
|
||||
print("NDI audio ", "enabled" if enabled else "disabled")
|
||||
|
||||
## Change the audio bus for NDI output
|
||||
func set_audio_bus(bus_name: String) -> void:
|
||||
audio_bus_name = bus_name
|
||||
if ndi_output and enable_audio:
|
||||
ndi_output.audio_bus = StringName(audio_bus_name)
|
||||
print("NDI audio bus changed to: ", audio_bus_name)
|
||||
|
||||
## Get current streaming status
|
||||
func get_streaming_status() -> bool:
|
||||
return is_streaming
|
||||
|
||||
## Get current NDI source name
|
||||
func get_source_name() -> String:
|
||||
return ndi_source_name
|
||||
|
||||
## Clean up when node is removed
|
||||
func _exit_tree() -> void:
|
||||
if ndi_output and is_streaming:
|
||||
stop_streaming()
|
||||
@@ -25,6 +25,8 @@ var editMode = true
|
||||
|
||||
@onready var shadow = $shadowSprite
|
||||
|
||||
@onready var ndi_output = $NDIOutput
|
||||
|
||||
|
||||
#Scene Reference
|
||||
@onready var spriteObject = preload("res://ui_scenes/selectedSprite/spriteObject.tscn")
|
||||
@@ -154,6 +156,9 @@ func _ready():
|
||||
origin.position = s*0.5
|
||||
updateCameraPosition()
|
||||
|
||||
# Test NDI output on startup
|
||||
call_deferred("toggle_ndi")
|
||||
|
||||
func _process(delta):
|
||||
var hold = origin.get_parent().position.y
|
||||
|
||||
@@ -238,6 +243,33 @@ func _input(event):
|
||||
# Invert the movement so dragging right moves character right (not left)
|
||||
var panSensitivity = 0.5
|
||||
viewPanOffset = -totalDelta * panSensitivity
|
||||
|
||||
# Handle NDI output hotkeys
|
||||
elif event is InputEventKey and event.pressed:
|
||||
# F9 key to toggle NDI streaming
|
||||
if event.keycode == KEY_F9:
|
||||
toggle_ndi_streaming()
|
||||
# F10 key to restart NDI streaming with new settings
|
||||
elif event.keycode == KEY_F10:
|
||||
restart_ndi_streaming()
|
||||
|
||||
## Toggle NDI streaming on/off
|
||||
func toggle_ndi_streaming():
|
||||
if ndi_output:
|
||||
print("NDI Output is available - Source: ", ndi_output.name)
|
||||
Global.pushUpdate("NDI Output available - Source: " + ndi_output.name)
|
||||
else:
|
||||
print("NDI Output not found")
|
||||
Global.pushUpdate("NDI Output not found")
|
||||
|
||||
## Restart NDI streaming to apply any new settings
|
||||
func restart_ndi_streaming():
|
||||
if ndi_output:
|
||||
print("NDI Output available - Source: ", ndi_output.name)
|
||||
Global.pushUpdate("NDI Output available - Source: " + ndi_output.name)
|
||||
else:
|
||||
print("NDI Output not found")
|
||||
Global.pushUpdate("NDI Output not found")
|
||||
|
||||
func followShadow():
|
||||
# Shadow disabled for selected sprites
|
||||
@@ -888,4 +920,18 @@ func _on_background_input_capture_bg_key_pressed(node, keys_pressed):
|
||||
var i = costumeKeys.find(key)
|
||||
if i >= 0:
|
||||
changeCostume(i+1)
|
||||
|
||||
## Simple NDI control function
|
||||
func toggle_ndi():
|
||||
if ndi_output:
|
||||
print("NDI Output is available - Source: ", ndi_output.name)
|
||||
print("NDI should be streaming the main viewport")
|
||||
else:
|
||||
print("NDI Output not found")
|
||||
|
||||
## Set NDI source name
|
||||
func set_ndi_source_name(source_name: String):
|
||||
if ndi_output:
|
||||
ndi_output.name = source_name
|
||||
print("NDI source name set to: ", source_name)
|
||||
|
||||
|
||||
@@ -14753,6 +14753,10 @@ position = Vector2(0, 720)
|
||||
modulate = Color(0, 0, 0, 0.478431)
|
||||
z_index = -4096
|
||||
|
||||
[node name="NDIOutput" type="NDIOutput" parent="."]
|
||||
name = "PNGTuber-Plus"
|
||||
audio_bus = &"Master"
|
||||
|
||||
[connection signal="pressed" from="ControlPanel/MicButtong/Button" to="." method="_on_button_pressed"]
|
||||
[connection signal="pressed" from="ControlPanel/SettingsButton/settingsButtons" to="." method="_on_settings_buttons_pressed"]
|
||||
[connection signal="pressed" from="ControlPanel/Edit/Button" to="." method="swapMode"]
|
||||
|
||||
@@ -148,6 +148,6 @@ saveImages={
|
||||
|
||||
textures/canvas_textures/default_texture_filter=0
|
||||
textures/canvas_textures/default_texture_repeat=1
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
renderer/rendering_method="forward_plus"
|
||||
renderer/rendering_method.mobile="forward_plus"
|
||||
environment/defaults/default_clear_color=Color(0.376471, 0.376471, 0.376471, 1)
|
||||
|
||||
@@ -48,6 +48,9 @@ func setvalues():
|
||||
|
||||
$experimentalMicLoudness/checkmark.button_pressed = Global.experimentalMicLoudness
|
||||
|
||||
# Initialize NDI settings
|
||||
setup_ndi_settings()
|
||||
|
||||
func _on_color_picker_button_color_changed(color):
|
||||
get_viewport().transparent_bg = false
|
||||
RenderingServer.set_default_clear_color(color)
|
||||
@@ -264,3 +267,45 @@ func _on_delete_9_pressed():
|
||||
func _on_delete_10_pressed():
|
||||
var label = $CostumeInputs/ScrollContainer/VBoxContainer/costumeButton10/Label
|
||||
deleteKey(label,10)
|
||||
|
||||
## NDI Output Settings Methods
|
||||
|
||||
func _on_ndi_enabled_check_toggled(toggled_on: bool):
|
||||
# Enable/disable NDI streaming
|
||||
if Global.main.ndi_output:
|
||||
print("NDI streaming ", "enabled" if toggled_on else "disabled")
|
||||
update_ndi_status()
|
||||
|
||||
func _on_ndi_source_name_text_changed(new_text: String):
|
||||
# Update NDI source name
|
||||
if Global.main.ndi_output:
|
||||
Global.main.ndi_output.name = new_text
|
||||
print("NDI source name changed to: ", new_text)
|
||||
|
||||
func _on_ndi_audio_check_toggled(toggled_on: bool):
|
||||
# Enable/disable audio in NDI stream
|
||||
if Global.main.ndi_output:
|
||||
if toggled_on:
|
||||
Global.main.ndi_output.audio_bus = StringName("Master")
|
||||
else:
|
||||
Global.main.ndi_output.audio_bus = StringName("")
|
||||
print("NDI audio ", "enabled" if toggled_on else "disabled")
|
||||
|
||||
func _on_ndi_toggle_button_pressed():
|
||||
# Toggle NDI streaming on/off - NDI is always on when the node exists
|
||||
print("NDI toggle pressed - NDI is active when node exists")
|
||||
update_ndi_status()
|
||||
|
||||
func update_ndi_status():
|
||||
# Update the status label and button text
|
||||
if Global.main.ndi_output:
|
||||
$NDIOutput/StatusLabel.text = "Status: Active (NDI Source: " + Global.main.ndi_output.name + ")"
|
||||
$NDIOutput/toggleButton.text = "NDI Active"
|
||||
$NDIOutput/ndiEnabledCheck.button_pressed = true
|
||||
|
||||
func setup_ndi_settings():
|
||||
# Initialize NDI settings UI with current values
|
||||
if Global.main.ndi_output:
|
||||
$NDIOutput/ndiSourceName.text = Global.main.ndi_output.name
|
||||
$NDIOutput/ndiAudioCheck.button_pressed = (Global.main.ndi_output.audio_bus != StringName(""))
|
||||
update_ndi_status()
|
||||
|
||||
@@ -14335,8 +14335,68 @@ offset_right = 154.0
|
||||
offset_bottom = 25.0
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="NDIOutput" type="Node2D" parent="."]
|
||||
position = Vector2(16, 433)
|
||||
|
||||
[node name="Label" type="Label" parent="NDIOutput"]
|
||||
offset_right = 138.0
|
||||
offset_bottom = 34.0
|
||||
text = "NDI streaming"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="ndiEnabledCheck" type="CheckBox" parent="NDIOutput"]
|
||||
offset_left = 130.0
|
||||
offset_top = 1.0
|
||||
offset_right = 154.0
|
||||
offset_bottom = 25.0
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="SourceNameLabel" type="Label" parent="NDIOutput"]
|
||||
offset_top = 32.0
|
||||
offset_right = 100.0
|
||||
offset_bottom = 50.0
|
||||
text = "source name:"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="ndiSourceName" type="LineEdit" parent="NDIOutput"]
|
||||
offset_left = 105.0
|
||||
offset_top = 30.0
|
||||
offset_right = 250.0
|
||||
offset_bottom = 52.0
|
||||
text = "PNGTuber-Plus"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="AudioLabel" type="Label" parent="NDIOutput"]
|
||||
offset_top = 60.0
|
||||
offset_right = 100.0
|
||||
offset_bottom = 78.0
|
||||
text = "include audio:"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="ndiAudioCheck" type="CheckBox" parent="NDIOutput"]
|
||||
offset_left = 130.0
|
||||
offset_top = 58.0
|
||||
offset_right = 154.0
|
||||
offset_bottom = 82.0
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="NDIOutput"]
|
||||
offset_top = 88.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = 106.0
|
||||
text = "Status: Not streaming"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="toggleButton" type="Button" parent="NDIOutput"]
|
||||
offset_left = 260.0
|
||||
offset_top = 85.0
|
||||
offset_right = 340.0
|
||||
offset_bottom = 110.0
|
||||
text = "Start NDI"
|
||||
metadata/_edit_use_anchors_ = true
|
||||
|
||||
[node name="bounceOnCostume" type="Node2D" parent="."]
|
||||
position = Vector2(17, 305)
|
||||
position = Vector2(17, 565)
|
||||
|
||||
[node name="Label" type="Label" parent="bounceOnCostume"]
|
||||
offset_right = 138.0
|
||||
@@ -14935,3 +14995,7 @@ metadata/_edit_use_anchors_ = true
|
||||
[connection signal="pressed" from="CostumeInputs/ScrollContainer/VBoxContainer/costumeButton10/delete10" to="." method="_on_delete_10_pressed"]
|
||||
[connection signal="value_changed" from="BlinkSpeed/blinkSpeed" to="." method="_on_blink_speed_value_changed"]
|
||||
[connection signal="value_changed" from="BlinkChance/blinkChance" to="." method="_on_blink_chance_value_changed"]
|
||||
[connection signal="toggled" from="NDIOutput/ndiEnabledCheck" to="." method="_on_ndi_enabled_check_toggled"]
|
||||
[connection signal="text_changed" from="NDIOutput/ndiSourceName" to="." method="_on_ndi_source_name_text_changed"]
|
||||
[connection signal="toggled" from="NDIOutput/ndiAudioCheck" to="." method="_on_ndi_audio_check_toggled"]
|
||||
[connection signal="pressed" from="NDIOutput/toggleButton" to="." method="_on_ndi_toggle_button_pressed"]
|
||||
|
||||
Reference in New Issue
Block a user