remove submodules

This commit is contained in:
Nikolai Rodionov 2022-11-05 07:58:38 +01:00 committed by Nikolai Rodionov
parent 9035c08dd1
commit d30ea44d2c
No known key found for this signature in database
GPG Key ID: 906851F91B1DA3EF
3465 changed files with 0 additions and 1163021 deletions

6
.gitmodules vendored
View File

@ -1,6 +0,0 @@
[submodule "deps/clap-juce-extensions"]
path = deps/clap-juce-extensions
url = https://github.com/free-audio/clap-juce-extensions.git
[submodule "deps/juce"]
path = deps/juce
url = https://github.com/juce-framework/JUCE.git

View File

@ -1,59 +0,0 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
---
Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 4
AlignAfterOpenBracket: Align
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
ColumnLimit: 100
SortIncludes: false
---
Language: ObjC
BasedOnStyle: LLVM
IndentWidth: 4
AlignAfterOpenBracket: Align
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
ColumnLimit: 100
SortIncludes: false
---

View File

@ -1,70 +0,0 @@
name: CI-CMake
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
build_and_test:
name: Build example plugins with CMake and JUCE ${{ matrix.juce_version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # show all errors for each platform (vs. cancel jobs on error)
matrix:
os: [ubuntu-latest, windows-2019, macOS-latest]
juce_version: ["6.0.7", "6.1.5", "6.1.6", "7.0.0"]
steps:
- name: Install Linux Deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt install libasound2-dev libx11-dev libxcomposite-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev libfreetype6-dev libglu1-mesa-dev libjack-jackd2-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 9
- name: Get latest CMake
uses: lukka/get-cmake@latest
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: recursive
- name: Configure
shell: bash
run: cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCLAP_JUCE_VERSION=$JUCE_VERSION -DCLAP_EXAMPLES_TREAT_WARNINGS_AS_ERRORS=ON
env:
JUCE_VERSION: ${{ matrix.juce_version }}
- name: Build
shell: bash
run: cmake --build build --config Release --parallel 4 --target GainPlugin_CLAP
- name: Set up clap-info
shell: bash
run: |
git clone --recurse-submodules https://github.com/surge-synthesizer/clap-info
cd clap-info
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release --parallel 4
- name: Run clap-info (Max/Linux)
if: runner.os == 'Linux' || runner.os == 'MacOS'
shell: bash
run: |
clap-info/build/clap-info --version
clap-info/build/clap-info build/examples/GainPlugin/GainPlugin_artefacts/Release/CLAP/GainPlugin.clap
- name: Run clap-info (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
clap-info/build/Release/clap-info --version
clap-info/build/Release/clap-info build/examples/GainPlugin/GainPlugin_artefacts/Release/CLAP/GainPlugin.clap

View File

@ -1,132 +0,0 @@
name: CI-Projucer
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
jobs:
build_and_test:
name: Build example plugins with Projucer on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false # show all errors for each platform (vs. cancel jobs on error)
matrix:
include:
- os: ubuntu-latest
jucer: build/_deps/juce-src/extras/Projucer/Builds/LinuxMakefile/build/Projucer
clap_gen: "Unix Makefiles"
- os: macos-latest
jucer: build/_deps/juce-src/extras/Projucer/Builds/MacOSX/build/Debug/Projucer.app/Contents/MacOS/Projucer
clap_gen: "Xcode"
- os: windows-2019
jucer: build/_deps/juce-src/extras/Projucer/Builds/VisualStudio2019/x64/Debug/App/Projucer.exe
clap_gen: "Visual Studio 16 2019"
steps:
- name: Install Linux Deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt install libasound2-dev libcurl4-openssl-dev libx11-dev libxinerama-dev libxext-dev libfreetype6-dev libwebkit2gtk-4.0-dev libglu1-mesa-dev libjack-jackd2-dev
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 9
- name: Add msbuild to PATH
if: runner.os == 'Windows'
uses: microsoft/setup-msbuild@v1.0.3
- name: Set up Xcode
if: runner.os == 'MacOS'
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest-stable
- name: Checkout code
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install JUCE
shell: bash
run: git clone --depth 1 --branch 6.1.5 https://github.com/juce-framework/JUCE build/_deps/juce-src
- name: Build Projucer (MacOS)
if: runner.os == 'MacOS'
shell: bash
run: xcodebuild -project Projucer.xcodeproj -jobs 4 | xcpretty
working-directory: build/_deps/juce-src/extras/Projucer/Builds/MacOSX
- name: Build Projucer (Windows)
if: runner.os == 'Windows'
shell: bash
run: msbuild.exe -v:normal -m:4 Projucer.sln
working-directory: build/_deps/juce-src/extras/Projucer/Builds/VisualStudio2019
- name: Build Projucer (Linux)
if: runner.os == 'Linux'
shell: bash
run: make -j4
working-directory: build/_deps/juce-src/extras/Projucer/Builds/LinuxMakefile
- name: Resave jucer
shell: bash
run: $PROJUCER --resave examples/GainPlugin/GainPlugin.jucer
env:
PROJUCER: ${{ matrix.jucer }}
- name: Build Plugin (MacOS)
if: runner.os == 'MacOS'
shell: bash
run: xcodebuild -project GainPlugin.xcodeproj -jobs 4 | xcpretty
working-directory: examples/GainPlugin/Builds/MacOSX
- name: Build Plugin (Windows)
if: runner.os == 'Windows'
shell: bash
run: msbuild.exe -v:normal -m:4 GainPlugin.sln
working-directory: examples/GainPlugin/Builds/VisualStudio2019
- name: Build Plugin (Linux)
if: runner.os == 'Linux'
shell: bash
run: make -j4
working-directory: examples/GainPlugin/Builds/LinuxMakefile
- name: Get latest CMake
uses: lukka/get-cmake@latest
- name: Build CLAP
shell: bash
run: |
cmake -Bbuild-clap -G"$CLAP_GEN" -DCMAKE_BUILD_TYPE=Debug -DCLAP_WRAP_PROJUCER_PLUGIN=ON
cmake --build build-clap --config Debug --target GainPlugin_CLAP
env:
CLAP_GEN: ${{ matrix.clap_gen }}
- name: Set up clap-info
shell: bash
run: |
git clone --recurse-submodules https://github.com/surge-synthesizer/clap-info
cd clap-info
cmake -Bbuild -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release --parallel 4
- name: Run clap-info (Max/Linux)
if: runner.os == 'MacOS' || runner.os == 'Linux'
shell: bash
run: |
clap-info/build/clap-info --version
clap-info/build/clap-info build-clap/examples/GainPlugin/GainPlugin_artefacts/Debug/MyGreatGainPlugin.clap
- name: Run clap-info (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
clap-info/build/Release/clap-info --version
clap-info/build/Release/clap-info build-clap/examples/GainPlugin/GainPlugin_artefacts/Debug/MyGreatGainPlugin.clap

View File

@ -1,8 +0,0 @@
build*/
Builds/
JuceLibraryCode/
.vscode/
.idea/
.DS_Store

View File

@ -1,6 +0,0 @@
[submodule "clap-libs/clap"]
path = clap-libs/clap
url = https://github.com/free-audio/clap.git
[submodule "clap-libs/clap-helpers"]
path = clap-libs/clap-helpers
url = https://github.com/free-audio/clap-helpers.git

View File

@ -1,77 +0,0 @@
# CMAKE Support for out of tree clap plugin extensions to Juce 6
#
# To use these in your juce6 cmake project
# 1. Include this cmake file in your build path
# 2. Create your juce plugin as normal with formats VST3 etc...
# 3. After that, add the following lines (or similar) to your cmake
# clap_juce_extensions_plugin(TARGET my-target
# CLAP_ID "com.my-cool-plugs.my-target")
# 4. Reload your CMAKe file and my-target_CLAP will be a buildable target
# The INTERFACE targets to transmit CXX_STANDARD and POSITION INDEPENDENT
# require at least CMAKE 3.21
cmake_minimum_required (VERSION 3.21 FATAL_ERROR)
get_directory_property(parent_dir PARENT_DIRECTORY)
if ("${parent_dir}" STREQUAL "")
# OSX deployment target needs to be set before the `project()` call
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment target")
set(is_toplevel 1)
else ()
set(is_toplevel 0)
endif ()
project(clap-juce-extensions VERSION 0.1.0 LANGUAGES C CXX)
if (CMAKE_CXX_STANDARD)
set(CLAP_CXX_STANDARD ${CMAKE_CXX_STANDARD})
else()
set(CLAP_CXX_STANDARD 14)
endif()
if (${CLAP_CXX_STANDARD} LESS 14)
set(CLAP_CXX_STANDARD 14)
endif()
message( STATUS "Building CLAP with CLAP_CXX_STANDARD=${CLAP_CXX_STANDARD}")
set(CMAKE_CXX_EXTENSIONS OFF)
option(CLAP_JUCE_EXTENSIONS_BUILD_EXAMPLES "Add targets for building and running clap-juce-extensions examples" ${is_toplevel})
if(CLAP_JUCE_EXTENSIONS_BUILD_EXAMPLES)
# The examples need JUCE to be imported before the CLAP helper targets
set(CLAP_JUCE_VERSION "6.1.5" CACHE STRING "Version of JUCE to use for building example plugins")
message(STATUS "Building examples with JUCE version: ${CLAP_JUCE_VERSION}")
include(examples/cmake/CPM.cmake)
CPMAddPackage("gh:juce-framework/JUCE#${CLAP_JUCE_VERSION}")
endif()
add_subdirectory(clap-libs/clap clapjuceext_clap EXCLUDE_FROM_ALL)
add_subdirectory(clap-libs/clap-helpers clapjuceext_claphelpers EXCLUDE_FROM_ALL)
add_library(clap_juce_extensions STATIC src/extensions/clap-juce-extensions.cpp)
set_property(TARGET clap_juce_extensions PROPERTY CXX_STANDARD ${CLAP_CXX_STANDARD})
target_include_directories(clap_juce_extensions PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(clap_juce_extensions PUBLIC
HAS_CLAP_JUCE_EXTENSIONS=1)
target_link_libraries(clap_juce_extensions PUBLIC clap-core clap-helpers)
set_target_properties(clap_juce_extensions PROPERTIES
POSITION_INDEPENDENT_CODE TRUE
VISIBILITY_INLINES_HIDDEN TRUE
C_VISBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
)
add_library(clap_juce_sources INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/wrapper/clap-juce-wrapper.cpp)
set_property(TARGET clap_juce_sources PROPERTY CXX_STANDARD ${CLAP_CXX_STANDARD})
set_property(TARGET clap_juce_sources PROPERTY CLAP_JUCE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
if (APPLE)
target_sources(clap_juce_sources INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/src/wrapper/clap-juce-mac.mm)
endif()
target_include_directories(clap_juce_sources INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include)
include(cmake/ClapTargetHelpers.cmake)
if(CLAP_JUCE_EXTENSIONS_BUILD_EXAMPLES)
message(STATUS "Configuring clap-juce-extensions examples")
add_subdirectory(examples)
endif()

View File

@ -1,9 +0,0 @@
Copyright 2019-2020, Paul Walker
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.

View File

@ -1,267 +0,0 @@
# JUCE6 and 7 Unofficial CLAP Plugin Support
This is a set of code which, combined with a JUCE 6 or JUCE 7 plugin project, allows you to build a CLAP plugin. It
is licensed under the MIT license, and can be used for both open and closed source projects.
We are labeling it 'unofficial' for four reasons
1. It is not supported by the JUCE team,
2. There are some JUCE features which we have not translated to CLAP yet,
3. It presents a set of completely optional extensions which break JUCE abstractions to allow extended CLAP feature
support and
4. It does not support JUCE-based CLAP hosting
Despite those caveats, the basic use of this library has allowed a wide variety
of synths and effects to generate a CLAP from their JUCE program, including Surge, B-Step,
Monique, several ChowDSP plugins, Dexed and more.
By far the best solution for CLAP in JUCE would be full native support by the JUCE team. Until such a time as that
happens (and it may never happen), this code may help you if you have a JUCE plugin and want to generate a CLAP. We are
happy to merge changes and answer questions as you try to use it. Please feel free to raise github issues in this repo.
This version is based off of CLAP 1.0 and generates plugins which work in BWS 4.3beta5 and later, as well as
other CLAP 1.0 DAWs such as MultitrackStudio.
## Basics: Using these extensions to build a CLAP
### CMake
Given a starting point of a JUCE plugin using CMake which can build a VST3, AU, Standalone and so forth with
`juce_plugin`, building a CLAP is a simple exercise of checking out this CLAP extension code
somewhere in your dev environment, setting a few CMake variables, and adding a couple of lines to your CMake file.
The instructions are as follows:
1. Add `https://github.com/free-audio/clap-juce-extensions.git` as a submodule of your project, or otherwise make the
source available to your cmake (CPM, side by side check out in CI, etc...).
2. Load the `clap-juce-extension` in your CMake after you have loaded JUCE. For instance, you could do
```cmake
add_subdirectory(libs/JUCE) # this is however you load juce
add_subdirectory(libs/clap-juce-extensions EXCLUDE_FROM_ALL)
```
3. Create your JUCE plugin as normal with flags and formats using the `juce_plugin` CMake function
4. After your `juce_plugin` code, add the following lines (or similar)
to your CMake (a list of pre-defined CLAP
features can be found [here](https://github.com/free-audio/clap/blob/main/include/clap/plugin-features.h)):
```cmake
clap_juce_extensions_plugin(TARGET my-target
CLAP_ID "com.my-cool-plugs.my-target"
CLAP_FEATURES instrument "virtual analog" gritty basses leads pads)
```
5. Reload your CMake file and you will have a new target `my-target_CLAP` which will build a CLAP and leave
it side-by-side with your AU, Standalone, VST3, and so forth. Load that CLAP into a DAW and give it a whirl!
### Projucer
Given a starting point of a JUCE plugin using the Projucer, it is possible to build a CLAP plugin by adding
a small CMake configuration alongside the Projucer build setup.
1. Build your Projucer-based plugin.
2. Create `CMakeLists.txt` file in the same directory as your `.jucer` file. Here's an example CMakeLists.txt:
```cmake
cmake_minimum_required(VERSION 3.15)
# Make sure to set the same MacOS deployment target as you have set in the Projucer
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.12" CACHE STRING "Minimum OS X deployment target")
# If the Projucer is using "static runtime" for Visual Studio:
# set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" CACHE STRING "Runtime")
# set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Release>:Release>" CACHE STRING "Runtime")
# If running into issues when Xcode tries to codesign the CLAP plugin, you may want to add these lines:
# set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
# set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED "NO")
project(MyPlugin VERSION 1.0.0)
set(PATH_TO_JUCE path/to/JUCE)
set(PATH_TO_CLAP_EXTENSIONS path/to/clap-juce-extensions)
# define the exporter types used in your Projucer configuration
if (APPLE)
set(JUCER_GENERATOR "Xcode")
elseif (WIN32)
set(JUCER_GENERATOR "VisualStudio2019")
else () # Linux
set(JUCER_GENERATOR "LinuxMakefile")
endif ()
include(${PATH_TO_CLAP_EXTENSIONS}/cmake/JucerClap.cmake)
create_jucer_clap_target(
TARGET MyPlugin # "Binary Name" in the Projucer
PLUGIN_NAME "My Plugin"
BINARY_NAME "MyPlugin" # Name of the resulting plugin binary
MANUFACTURER_NAME "My Company"
MANUFACTURER_CODE Manu
PLUGIN_CODE Plg1
VERSION_STRING "1.0.0"
CLAP_ID "org.mycompany.myplugin"
CLAP_FEATURES instrument synthesizer
CLAP_MANUAL_URL "https://www.mycompany.com"
CLAP_SUPPORT_URL "https://www.mycompany.com"
EDITOR_NEEDS_KEYBOARD_FOCUS FALSE
)
```
3. Build the CLAP plugin using CMake. This step can be done manually,
as part of an automated build script, or potentially even as a
post-build step triggered from the Projucer:
```bash
cmake -Bbuild-clap -G<generator> -DCMAKE_BUILD_TYPE=<Debug|Release>
cmake --build build-clap --config <Debug|Release>
```
The resulting builds will be located in `build-clap/MyPlugin_artefacts`.
If you would like to use the [CLAP extensions API](#the-extensions-api), the necessary source
files must be added to the plugin's Projucer configuration.
### Arguments to CLAP CMake functions
In addition to `CLAP_ID` and `CLAP_FEATURES` described above the following arguments
are available
* `CLAP_MANUAL_URL` and `CLAP_SUPPORT_URL` generate the urls in your description
* `CLAP_MISBHEAVIOUR_HANDLER_LEVEL` can be set to `Terminate` or `Ignore` (default
is `Ignore`) to choose your behaviour for a misbehaving host.
* `CLAP_CHECKING_LEVEL` can be set to `None`, `Minimal`, or `Maximal` (default is
`Minimal`) to choose the level of sanity checks enabled for the plugin.
* `CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES` can be set to any integer value to choose the
resolution (in samples) used by the wrapper for doing sample-accurate event processing.
Setting the value to `0` (the default value) will turn off sample-accurate event processing.
* `CLAP_ALWAYS_SPLIT_BLOCK` can be set to `1` (on), or `0` (off, default), to tell the
wrapper to _always_ attempt to split incoming audio buffers into chunks of size
`CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES`, regardless of any input events being
sent from the host. Note that if the block size provided by the host is not an
even multiple of `CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES`, the plugin may be
required to process a chunk smaller than the chosen resolution.
* `CLAP_USE_JUCE_PARAMETER_RANGES` can be set to `ALL`, `DISCRETE` or `OFF` (default) to
tell the wrapper to use JUCE's parameter ranges for all parameters, discrete parameters only,
or no parameters. When not using JUCE's parameter ranges, the plugin will communicate with
the host using 0-1 parameter ranges for the given parameter,
## Risks of using this library
Using this library is, of course, not without risks. There could easily be bugs we haven't found and there are
APIs we don't cover. We are happy to discuss, investigate, and work to fix any of those.
The biggest risk, though, involves JUCE team providing official support in a way which is fundamentally incompatible
with these wrappers. As of this writing, the JUCE team has not committed to supporting CLAP in JUCE 7 or any future
version, although they are aware of the project. But if the JUCE team did provide official future support, it is not
clear that your CLAP plugin which resulted from their official support would work in the same way as the plugin
generated by this library would.
There are a couple of mitigants to that risk.
Most importantly, in the three critical places a DAW interacts with a plugin - CLAP ID, parameter IDs, and state
streaming -
we have endeavoured to write in as JUCE-natural a way as possible.
1. The CLAP ID is just a CMake parameter, as we expect it would be in an official build.
2. The parameter IDs we use uses the [internal JUCE hashing mechanism to generate
our `uint32_t`](https://github.com/free-audio/clap-juce-extensions/blob/85bc0d56dc784a5f1271602db46f0748954b180e/src/wrapper/clap-juce-wrapper.cpp#L198)
just like
the [current VST3 wrapper does](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp#L585).
3. Our stream implementation
transparently [calls `AudioProcessor::setStateInformation` and `AudioProcessor::getStateInformation`](https://github.com/free-audio/clap-juce-extensions/blob/85bc0d56dc784a5f1271602db46f0748954b180e/src/wrapper/clap-juce-wrapper.cpp#L930)
with no intervening
modification of the stream.
While there is no guarantee that an official JUCE implementation, if it were to exist, would make these choices,
it seems quite natural that it would, and in that case, your plugin would continue to work.
If, however, you use the extensions detailed below - which allows features outside of JUCE like note expressions,
sample accurate automation, and polyphonic and non-destructive modulation - there is very little assurance we can
give you that an official JUCE implementation, if it were to exist, would work with your code without modification,
or even that it would support those features at all. That would leave such a synth (of which Surge is the primary
example today) relying on these wrappers still.
## Major Missing API points
1. We have not tested any JUCE version earlier than 6.0.7, and plugins which use deprecated APIs may not work
2. The [`AudioProcessor::WrapperType`](https://docs.juce.com/master/classAudioProcessor.html#a2e1b21b8831ac529965abffc96223dcf)
API doesn't support CLAP. All CLAP plugins will define a `wrapperType` of `wrapperType_Undefined`. We do provide
a workaround for using our extensions mechanism, below.
3. Several parameter features - including discrete (stepped) parameters - don't translate from JUCE to CLAP
in our adapter (although they are supported in the CLAP API of course). We would love a test plugin to help us
resolve this.
## The `clap_juce_extensions` API for extended CLAP capabilities in JUCE
There are a set of things which JUCE doesn't support which CLAP does. Rather than not support them in our
plugins, we've decided to create an specific extensions API which allow you to decorate JUCE
classes with extended capabilities. These are a set of classes which your AudioProcessor can
implement and, if it does, then the CLAP JUCE wrapper will call the associated functions.
The extension are in "include/clap-juce-extensions.h" and are documented there, but currently have
three classes
- `clap_juce_extensions::clap_properties`
- if you subclass this your AudioProcessor will have a collection of members which give you extra CLAP info
- Most usefully, you get an `is_clap` member which is false if not a CLAP and true if it is, which works around
the fact that our 'forkless' approach doesn't let us add a `AudioProcessor::WrapperType` to the JUCE API
- `clap_juce_extensions::clap_juce_audio_processor_capabilities`
- these are a set of advanced extensions which let you optionally interact more directly with the CLAP API
and are mostly useful for advanced features like non-destructive modulation and note expression support
- `clap_juce_extensions::clap_juce_parameter_capabilities`
- If your AudioProcessorParameter subclass implements this API, you can share extended CLAP information on
a parameter by parameter basis
As an example, here's how to use `clap_properties` to work around `AudioProcessor::WrapperType` being `Undefined` in the
forkless
CLAP approach
- `#include "clap-juce-extensions/clap-juce-extensions.h"`
- Make your main plugin `juce::AudioProcessor` derive from `clap_juce_extensions::clap_properties`
- Use the `is_clap` member variable to figure out the correct wrapper type.
Here's a minimal example:
```cpp
#include <JuceHeader.h>
#include "clap-juce-extensions/clap-juce-extensions.h"
class MyCoolPlugin : public juce::AudioProcessor,
public clap_juce_extensions::clap_properties
{
String getWrapperTypeString()
{
if (wrapperType == wrapperType_Undefined && is_clap)
return "CLAP";
return juce::AudioProcessor::getWrapperTypeDescription (wrapperType);
}
...
};
```
If you are interested in using these extensions, please consult the documentation in the
[clap-juce-extensions header.](https://github.com/free-audio/clap-juce-extensions/blob/main/include/clap-juce-extensions/clap-juce-extensions.h)
The [Surge XT Synthesizer](https://github.com/surge-synthesizer/surge) is a worked example of using many of these.
We are also happy to discuss them - reach out in the issues here or in a shared discord server.
## Technical Detail: The "Forkless" approach
There's a couple of ways we could have gone adding experimental JUCE support. The way the LV2 extensions to JUCE work
requires a forked JUCE which places LV2 support fully inside the JUCE ecosystem at the cost of maintaining a fork (and
not allowing folks with their own forks to easily use LV2). We instead chose an 'out-of-JUCE' approach which has the
following pros and cons
Pros:
* You can use any JUCE 6 or 7 / CMake method you want and don't need to use our branch.
* We don't have to update our fork to pull latest JUCE features; you don't have to use our fork and choices to build
your plugin.
Cons:
* The CMake API is not consistent. Rather than add "CLAP" as a plugin type, you need a couple of extra lines of CMake to
activate your CLAP.
* We cannot support the `AudioProcessor::WrapperType` API, as discussed above.

View File

@ -1,194 +0,0 @@
function(clap_juce_extensions_plugin_internal)
set(oneValueArgs TARGET TARGET_PATH PLUGIN_BINARY_NAME IS_JUCER PLUGIN_VERSION DO_COPY CLAP_MANUAL_URL
CLAP_SUPPORT_URL CLAP_MISBEHAVIOUR_HANDLER_LEVEL CLAP_CHECKING_LEVEL CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES
CLAP_ALWAYS_SPLIT_BLOCK CLAP_USE_JUCE_PARAMETER_RANGES)
set(multiValueArgs CLAP_ID CLAP_FEATURES)
cmake_parse_arguments(CJA "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(target ${CJA_TARGET})
string(REPLACE " " "_" claptarget "${target}_CLAP")
message(STATUS "Creating CLAP ${claptarget} from ${target}")
if ("${CJA_CLAP_ID}" STREQUAL "")
message(FATAL_ERROR "You must specify CLAP_ID to add a clap" )
endif()
if ("${CJA_CLAP_FEATURES}" STREQUAL "")
message(WARNING "No CLAP_FEATURES were specified! Using \"instrument\" by default.")
set(CJA_CLAP_FEATURES instrument)
endif()
if ("${CJA_CLAP_MISBEHAVIOUR_HANDLER_LEVEL}" STREQUAL "")
message( STATUS "Setting Misbehaviour handler level to 'Ignore'")
set(CJA_CLAP_MISBEHAVIOUR_HANDLER_LEVEL "Ignore")
else()
message( STATUS "Setting Misbehaviour handler level to '${CJA_CLAP_MISBEHAVIOUR_HANDLER_LEVEL}'")
endif()
if ("${CJA_CLAP_CHECKING_LEVEL}" STREQUAL "")
message( STATUS "Setting Checking handler level to 'Minimal'")
set(CJA_CLAP_CHECKING_LEVEL "Minimal")
else()
message( STATUS "Setting Checking handler level to '${CJA_CLAP_CHECKING_LEVEL}'")
endif()
if ("${CJA_CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES}" STREQUAL "")
message( STATUS "Setting event resolution to 0 samples (no sample-accurate automation)")
set(CJA_CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 0)
else()
message( STATUS "Setting event resolution to ${CJA_CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES} samples")
endif()
if ("${CJA_CLAP_ALWAYS_SPLIT_BLOCK}" STREQUAL "")
message( STATUS "Setting \"Always split block\" to OFF")
set(CJA_CLAP_ALWAYS_SPLIT_BLOCK 0)
else()
message( STATUS "Setting \"Always split block\" to ${CJA_CLAP_ALWAYS_SPLIT_BLOCK}")
endif()
if ("${CJA_CLAP_USE_JUCE_PARAMETER_RANGES}" STREQUAL "")
message( STATUS "Setting \"Use JUCE parameter ranges\" to OFF")
set(CJA_CLAP_USE_JUCE_PARAMETER_RANGES OFF)
else()
message( STATUS "Setting \"Use JUCE parameter ranges\" to ${CJA_CLAP_USE_JUCE_PARAMETER_RANGES}")
endif()
# we need the list of features as comma separated quoted strings
foreach(feature IN LISTS CJA_CLAP_FEATURES)
list (APPEND CJA_CLAP_FEATURES_PARSED "\"${feature}\"")
endforeach()
list (JOIN CJA_CLAP_FEATURES_PARSED ", " CJA_CLAP_FEATURES_PARSED)
get_property(SRC TARGET clap_juce_sources PROPERTY SOURCES)
add_library(${claptarget} MODULE ${SRC})
get_property(CLAP_CXX_STANDARD TARGET clap_juce_sources PROPERTY CXX_STANDARD)
if(${CJA_IS_JUCER})
set(base_folder "${CMAKE_CURRENT_BINARY_DIR}/${target}_artefacts")
set(products_folder "${base_folder}/$<CONFIG>")
set_target_properties(${claptarget} PROPERTIES
CXX_STANDARD ${CLAP_CXX_STANDARD}
ARCHIVE_OUTPUT_DIRECTORY "${products_folder}"
LIBRARY_OUTPUT_DIRECTORY "${products_folder}"
RUNTIME_OUTPUT_DIRECTORY "${products_folder}")
else()
set_target_properties(${claptarget} PROPERTIES
CXX_STANDARD ${CLAP_CXX_STANDARD}
ARCHIVE_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},ARCHIVE_OUTPUT_DIRECTORY>>/CLAP"
LIBRARY_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},LIBRARY_OUTPUT_DIRECTORY>>/CLAP"
RUNTIME_OUTPUT_DIRECTORY "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},RUNTIME_OUTPUT_DIRECTORY>>/CLAP")
target_include_directories(${claptarget} PRIVATE $<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>)
endif()
get_target_property(products_folder ${claptarget} LIBRARY_OUTPUT_DIRECTORY)
set(product_name "${CJA_PLUGIN_BINARY_NAME}")
set_target_properties(${claptarget} PROPERTIES
JUCE_PLUGIN_ARTEFACT_FILE "${products_folder}/${product_name}.clap")
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
get_target_property(cjd clap_juce_sources CLAP_JUCE_SOURCE_DIR)
set_target_properties(${claptarget} PROPERTIES
BUNDLE True
BUNDLE_EXTENSION clap
PREFIX ""
OUTPUT_NAME "${product_name}"
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_GUI_IDENTIFIER "${CJA_CLAP_ID}"
MACOSX_BUNDLE_BUNDLE_NAME "${product_name}"
MACOSX_BUNDLE_BUNDLE_VERSION "${CJA_PLUGIN_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${CJA_PLUGIN_VERSION}"
MACOSX_BUNDLE_INFO_PLIST "${cjd}/cmake/macos_bundle/CLAP_Info.plist.in"
)
add_custom_command(TARGET ${claptarget} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${cjd}/cmake/macos_bundle/PkgInfo" "$<TARGET_FILE_DIR:${claptarget}>/.."
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:${claptarget}>/../Resources"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${cjd}/cmake/macos_bundle/clap.icns" "$<TARGET_FILE_DIR:${claptarget}>/../Resources"
)
else()
set_target_properties(${claptarget} PROPERTIES
PREFIX ""
SUFFIX ".clap"
OUTPUT_NAME "${product_name}"
)
endif()
target_compile_definitions(${claptarget} PRIVATE
CLAP_ID="${CJA_CLAP_ID}"
CLAP_FEATURES=${CJA_CLAP_FEATURES_PARSED}
CLAP_MANUAL_URL="${CJA_CLAP_MANUAL_URL}"
CLAP_SUPPORT_URL="${CJA_CLAP_SUPPORT_URL}"
CLAP_MISBEHAVIOUR_HANDLER_LEVEL=${CJA_CLAP_MISBEHAVIOUR_HANDLER_LEVEL}
CLAP_CHECKING_LEVEL=${CJA_CLAP_CHECKING_LEVEL}
CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES=${CJA_CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES}
CLAP_ALWAYS_SPLIT_BLOCK=${CJA_CLAP_ALWAYS_SPLIT_BLOCK}
CLAP_USE_JUCE_PARAMETER_RANGES=CLAP_USE_JUCE_PARAMETER_RANGES_${CJA_CLAP_USE_JUCE_PARAMETER_RANGES}
)
if(${CJA_IS_JUCER})
# Since we're working with a pre-compiled plugin lib we can't build
# the plugin with the extensions... however, we still need to compile
# the extensions, since we'll get a linker error otherwise.
target_link_libraries(${claptarget} PUBLIC clap_juce_extensions)
target_link_libraries(${claptarget} PUBLIC ${CJA_TARGET_PATH})
else()
target_link_libraries(${target} PUBLIC clap_juce_extensions)
target_link_libraries(${claptarget} PUBLIC ${target})
endif()
target_link_libraries(${claptarget} PUBLIC clap-core clap-helpers clap_juce_sources)
set_property(TARGET ${claptarget} PROPERTY C_VISIBILITY_PRESET hidden)
set_property(TARGET ${claptarget} PROPERTY VISIBILITY_INLINES_HIDDEN ON)
set_target_properties(${claptarget} PROPERTIES
POSITION_INDEPENDENT_CODE TRUE
VISIBILITY_INLINES_HIDDEN TRUE
C_VISBILITY_PRESET hidden
CXX_VISIBILITY_PRESET hidden
)
if(${CJA_DO_COPY})
message(STATUS "Copy After Build" )
if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
add_custom_command(TARGET ${claptarget} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Installing ${products_folder}/${product_name}.clap to ~/Library/Audio/Plug-Ins/CLAP/"
COMMAND ${CMAKE_COMMAND} -E make_directory "~/Library/Audio/Plug-Ins/CLAP"
COMMAND ${CMAKE_COMMAND} -E copy_directory "${products_folder}/${product_name}.clap" "~/Library/Audio/Plug-Ins/CLAP/${product_name}.clap"
)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
add_custom_command(TARGET ${claptarget} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Installing ${products_folder}/${product_name}.clap"
COMMAND ${CMAKE_COMMAND} -E make_directory "~/.clap"
COMMAND ${CMAKE_COMMAND} -E copy "${products_folder}/${product_name}.clap" "~/.clap/"
)
endif()
endif()
endfunction()
function(clap_juce_extensions_plugin)
set(oneValueArgs TARGET)
cmake_parse_arguments(CJA "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
get_target_property(product_name ${CJA_TARGET} JUCE_PRODUCT_NAME)
get_target_property(plugin_version ${CJA_TARGET} JUCE_VERSION)
get_target_property(docopy "${CJA_TARGET}" JUCE_COPY_PLUGIN_AFTER_BUILD)
clap_juce_extensions_plugin_internal(
PLUGIN_BINARY_NAME "${product_name}"
PLUGIN_VERSION "${plugin_version}"
IS_JUCER FALSE
DO_COPY ${docopy}
${ARGV}
)
endfunction()
# modified version of clap_juce_extensions_plugin
# for use with Projucer projects
function(clap_juce_extensions_plugin_jucer)
clap_juce_extensions_plugin_internal(
IS_JUCER TRUE
${ARGV}
)
endfunction()

View File

@ -1,127 +0,0 @@
# use this function to create a CLAP from a jucer project
function(create_jucer_clap_target)
set(oneValueArgs TARGET PLUGIN_NAME BINARY_NAME MANUFACTURER_NAME MANUFACTURER_URL VERSION_STRING MANUFACTURER_CODE PLUGIN_CODE EDITOR_NEEDS_KEYBOARD_FOCUS)
set(multiValueArgs CLAP_FEATURES)
cmake_parse_arguments(CJA "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if ("${CJA_BINARY_NAME}" STREQUAL "")
set(CJA_BINARY_NAME "${CJA_TARGET}")
endif()
if ("${CMAKE_BUILD_TYPE}" STREQUAL "")
message(WARNING "CMAKE_BUILD_TYPE not set... using Release by default")
set(CMAKE_BUILD_TYPE "Release")
endif()
if("${JUCER_GENERATOR}" STREQUAL "VisualStudio2019")
find_library(PLUGIN_LIBRARY_PATH ${CJA_TARGET} "Builds/VisualStudio2019/x64/${CMAKE_BUILD_TYPE}/Shared Code")
elseif("${JUCER_GENERATOR}" STREQUAL "VisualStudio2017")
find_library(PLUGIN_LIBRARY_PATH ${CJA_TARGET} "Builds/VisualStudio2017/x64/${CMAKE_BUILD_TYPE}/Shared Code")
elseif("${JUCER_GENERATOR}" STREQUAL "VisualStudio2015")
find_library(PLUGIN_LIBRARY_PATH ${CJA_TARGET} "Builds/VisualStudio2015/x64/${CMAKE_BUILD_TYPE}/Shared Code")
elseif("${JUCER_GENERATOR}" STREQUAL "Xcode")
find_library(PLUGIN_LIBRARY_PATH ${CJA_TARGET} "Builds/MacOSX/build/${CMAKE_BUILD_TYPE}")
elseif("${JUCER_GENERATOR}" STREQUAL "LinuxMakefile")
# for some reason Projucer makes a lib called "PluginName.a", but find_library needs "libPluginName.a"
set(LINUX_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Builds/LinuxMakefile/build")
configure_file("${LINUX_LIB_PATH}/${CJA_TARGET}.a" "${LINUX_LIB_PATH}/lib${CJA_TARGET}.a" COPYONLY)
find_library(PLUGIN_LIBRARY_PATH ${CJA_TARGET} "${LINUX_LIB_PATH}")
elseif("${JUCER_GENERATOR}" STREQUAL "")
message(FATAL_ERROR "JUCER_GENERATOR variable must be set!")
else()
message(FATAL_ERROR "Unknown Generator!")
endif()
message(STATUS "Plugin SharedCode library path: ${PLUGIN_LIBRARY_PATH}")
if(NOT CLAP_JUCE_EXTENSIONS_BUILD_EXAMPLES)
add_subdirectory(${PATH_TO_JUCE} clap_juce_juce)
add_subdirectory(${PATH_TO_CLAP_EXTENSIONS} clap_juce_clapext EXCLUDE_FROM_ALL)
endif()
clap_juce_extensions_plugin_jucer(
TARGET_PATH "${PLUGIN_LIBRARY_PATH}"
PLUGIN_BINARY_NAME "${CJA_BINARY_NAME}"
PLUGIN_VERSION "${CJA_VERSION_STRING}"
${ARGV}
)
string(REPLACE " " "_" clap_target "${CJA_TARGET}_CLAP")
target_include_directories(${clap_target}
PUBLIC
${PATH_TO_JUCE}/modules
JuceLibraryCode
)
target_compile_definitions(${clap_target}
PRIVATE
JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED=1
JucePlugin_Name="${CJA_PLUGIN_NAME}"
JucePlugin_Manufacturer="${CJA_MANUFACTURER_NAME}"
JucePlugin_ManufacturerWebsite="${CJA_MANUFACTURER_URL}"
JucePlugin_VersionString="${CJA_VERSION_STRING}"
JucePlugin_Desc=""
)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_definitions(${clap_target}
PRIVATE
DEBUG=1
_DEBUG=1
)
else()
target_compile_definitions(${clap_target}
PRIVATE
NDEBUG=1
_NDEBUG=1
)
endif()
if("${CJA_CLAP_FEATURES}" MATCHES "^instrument.*")
message(STATUS "Detected plugin category: instrument")
target_compile_definitions(${clap_target} PRIVATE JucePlugin_IsSynth=1)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_ProducesMidiOutput=0)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_WantsMidiInput=1)
elseif("${CJA_CLAP_FEATURES}" MATCHES "^audio-effect.*")
message(STATUS "Detected plugin category: audio-effect")
target_compile_definitions(${clap_target} PRIVATE JucePlugin_IsSynth=0)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_ProducesMidiOutput=0)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_WantsMidiInput=0)
elseif("${CJA_CLAP_FEATURES}" MATCHES "^note-effect.*")
message(STATUS "Detected plugin category: note-effect")
target_compile_definitions(${clap_target} PRIVATE JucePlugin_IsSynth=0)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_ProducesMidiOutput=1)
target_compile_definitions(${clap_target} PRIVATE JucePlugin_WantsMidiInput=1)
else()
message(FATAL_ERROR "No plugin category detected!")
endif()
if("${CJA_MANUFACTURER_CODE}" STREQUAL "")
message(WARNING "Manufacturer code not set! Using \"Manu\"")
set(CJA_MANUFACTURER_CODE "Manu")
endif()
target_compile_definitions(${clap_target} PRIVATE JucePlugin_ManufacturerCode=${CJA_MANUFACTURER_CODE})
if("${CJA_PLUGIN_CODE}" STREQUAL "")
message(WARNING "Plugin code not set! Using \"Xyz5\"")
set(CJA_PLUGIN_CODE "Xyz5")
endif()
target_compile_definitions(${clap_target} PRIVATE JucePlugin_PluginCode=${CJA_PLUGIN_CODE})
if(${CJA_EDITOR_NEEDS_KEYBOARD_FOCUS})
target_compile_definitions(${clap_target} PRIVATE JucePlugin_EditorRequiresKeyboardFocus=1)
else()
target_compile_definitions(${clap_target} PRIVATE JucePlugin_EditorRequiresKeyboardFocus=0)
endif()
if(APPLE)
_juce_link_frameworks("${clap_target}" PRIVATE AppKit Cocoa WebKit OpenGL CoreAudioKit CoreAudio CoreMidi CoreVideo CoreImage Quartz Accelerate AudioToolbox IOKit QuartzCore Metal MetalKit)
elseif(UNIX)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(Freetype REQUIRED)
find_package(ALSA REQUIRED)
target_link_libraries(${clap_target} PUBLIC Threads::Threads Freetype::Freetype ALSA::ALSA ${ALSA_LIBRARIES} rt dl)
endif()
endfunction()

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>clap.icns</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
</dict>
</plist>

View File

@ -1 +0,0 @@
BNDL????

View File

@ -1,24 +0,0 @@
# This generates the clap.icns file from the artwork PNG
IN=../../clap-libs/clap/artwork/clap-simple-logo-black.png
mkdir OUT
mkdir OUT/PNG
convert -geometry 512 $IN OUT/PNG/icon_512.png
convert -geometry 256 $IN OUT/PNG/icon_256.png
convert -geometry 128 $IN OUT/PNG/icon_128.png
convert -geometry 64 $IN OUT/PNG/icon_64.png
identify OUT/PNG/*png
mkdir OUT/SET.iconset
sips -z 512 512 OUT/PNG/icon_512.png --out OUT/SET.iconset/icon_512x512.png
sips -z 256 256 OUT/PNG/icon_512.png --out OUT/SET.iconset/icon_256x256.png
sips -z 128 128 OUT/PNG/icon_512.png --out OUT/SET.iconset/icon_128x128.png
sips -z 64 64 OUT/PNG/icon_512.png --out OUT/SET.iconset/icon_64x64.png
iconutil -c icns -o clap.icns OUT/SET.iconset
rm -rf OUT

View File

@ -1,250 +0,0 @@
# How To: Parameter Modulation
One of the most exciting features available to CLAP plugins is
[non-destructive parameter modulation](https://www.youtube.com/embed/B2mywWyI9es).
If you're using this repository to build your JUCE-based plugin as a CLAP,
you may be wondering how to get parameter modulation working with your plugin.
This document should be able to help you get started.
It is worth repeating that if JUCE implements CLAP support "natively"
in the future, it is unlikely that the approach outlined here would be
compatible with that implementation.
Note that the workflow below pre-supposes that your plugin uses the modern
JUCE parameter classes. If your plugin is using JUCE's "legacy" parameter
mechanisms, then the CLAP JUCE wrapper cannot support parameter modulation
(although regular parameter functionality will still work).
## Monophonic Modulation
For audio effects, monophonic synthesizers, and global parameters on
polyphonic synthesizers, monophonic parameter modulation can be enabled
as follows.
1. Link your plugin to the `clap_juce_extensions` header.
- For a CMake project, this can be done by adding
`target_link_libraries(MyPlugin PUBLIC clap_juce_extensions)`
to your CMake configuration.
- For a Projucer project, the user will need to add the
following include paths to your Projucer configuration:
- `path/to/clap-juce-extensions/include`
- `path/to/clap-juce-extensions/clap-libs/clap/include`
- `path/to/clap-juce-extensions/clap-libs/clap-helpers/include`
You'll also need to add the following file to your Projucer
source files:
- `path/to/clap-juce-extensions/src/extensions/clap-juce-extensions.cpp`
2. Implement a custom parameter type, derived from
`clap_juce_extensions::clap_juce_parameter_capabilities`.
An example can be seen [here](../examples/GainPlugin/ModulatableFloatParameter.h).
3. Implement `supportsMonophonicModulation()` and
`applyMonophonicModulation()` for your custom parameter.
The final parameter class should look something like this:
```cpp
#pragma once
#include <juce_audio_utils/juce_audio_utils.h>
#include <clap-juce-extensions/clap-juce-extensions.h>
class ModulatableFloatParameter : public juce::AudioParameterFloat,
public clap_juce_extensions::clap_juce_parameter_capabilities
{
public:
ModulatableFloatParameter (/* args */) {} // implement your constructor
bool supportsMonophonicModulation() override { return true; }
void applyMonophonicModulation(double modulationValue) override
{
// do something with the modulation value here...
}
float getCurrentValue() const noexcept
{
// return parameter value with modulation applied...
}
};
```
Any parameters in your plugin that should support non-destructuve modulation
should be derived from your custom parameter class. It's also important to
make sure that when accessing the parameter's value (for example, in your
`processBlock()` method), that you are calling `getCurrentValue()` (or the
equivalent in your code), rather than using the standard JUCE parameter APIs
for getting the parameter value, otherwise the processor will be using the
un-modulated value of the parameter. Notably, this constraint includes
`juce::AudioProcessorValueTreeState::getRawParameterValue()`.
4. Add `CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES` to your CLAP CMake arguments.
```cmake
# For CMake plugins:
clap_juce_extensions_plugin(TARGET my-target
CLAP_ID "com.my-cool-plugs.my-target"
CLAP_FEATURES instrument "virtual analog" gritty basses leads pads
CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 64)
# For Projucer plugins:
create_jucer_clap_target(
TARGET MyPlugin
PLUGIN_NAME "My Plugin"
BINARY_NAME "MyPlugin"
MANUFACTURER_NAME "My Company"
MANUFACTURER_CODE Manu
PLUGIN_CODE Plg1
VERSION_STRING "1.0.0"
CLAP_ID "org.mycompany.myplugin"
CLAP_FEATURES instrument synthesizer
CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 64
)
```
While not strictly necessary, defining `CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES`
will allow the plugin to respond to modulation events sent from the host at a
finer resolution than the host's block size. Bitwig Studio sends modulation
events at a resolution of 64 samples, but you may want to use a different resolution
size, for example, if your plugin already has a modulation system which uses a
different sample resolution for modulation.
And that's it! Now your plugin should support monophonic modulation!
## Polyphonic Modulation
If your plugin is a polyphonic synthesizer or MIDI effect, you may also want to
implement polyphonic modulation for some parameters. It should be noted that
any parameter which supports polyphonic modulation is also expected to support
monophonic modulation, so make sure to complete the steps from the previous
section before following along here.
1. Implement `supportsPolyphonicModulation()` and
`applyPolyphonicModulation()` for your custom parameter type.
```cpp
class PolyModulatableFloatParameter : public ModulatableFloatParameter
{
public:
PolyModulatableFloatParameter (/* args */) {} // implement your constructor
bool supportsPolyphonicModulation() override { return true; }
void applyPolyphonicModulation(int32_t note_id, int16_t port_index,
int16_t channel, int16_t key,
double amount) override
{
// apply the modulation here
}
float getCurrentValuePoly(int32_t note_id, int16_t port_index,
int16_t channel, int16_t key) const noexcept
{
// return parameter value with modulation applied
// for this note, channel, etc ...
}
};
```
2. Next we need our plugin to keep track of note IDs so we can know
which modulation events should apply to which notes. This can be
done by implementing custom event handlers for incoming note events.
```cpp
class MyPlugin : public juce::AudioProcessor,
public clap_juce_extensions::clap_juce_audio_processor_capabilities
{
public:
// All your other code here...
bool supportsDirectEvent(uint16_t space_id, uint16_t type) override
{
if (space_id != CLAP_CORE_EVENT_SPACE_ID)
return false; // only handle events in the core namespace
// do custom handling for note events
return type == CLAP_EVENT_NOTE_ON
&& type == CLAP_EVENT_NOTE_OFF;
}
void handleDirectEvent(const clap_event_header_t *evt, int sampleOffset) override
{
if (evt->space_id != CLAP_CORE_EVENT_SPACE_ID)
return;
switch (evt->type)
{
case CLAP_EVENT_NOTE_ON:
{
auto nevt = reinterpret_cast<const clap_event_note *>(evt);
const auto note_id = nevt->note_id;
// start the note here...
}
break;
case CLAP_EVENT_NOTE_OFF:
{
auto nevt = reinterpret_cast<const clap_event_note *>(evt);
const auto note_id = nevt->note_id;
// end the note here...
}
break;
};
}
};
```
3. Finally, we need to tell the host when each note is ending, by adding note
end events to the output event queue:
```cpp
class MyPlugin : public juce::AudioProcessor,
public clap_juce_extensions::clap_juce_audio_processor_capabilities
{
public:
// All your other code here...
bool supportsOutboundEvents() override { return true; }
void addOutboundEventsToQueue(const clap_output_events *out_events,
const juce::MidiBuffer &midiBuffer, int sampleOffset) override
{
// Assuming the plugin has implemented some container `notesThatEndedDuringLastBlock`
// to hold information for all the notes that ended during the previous `processBlock()`
for (auto& noteEndEvent : notesThatEndedDuringLastBlock)
{
auto evt = clap_event_note();
evt.header.size = sizeof(clap_event_note);
evt.header.type = (uint16_t)CLAP_EVENT_NOTE_END;
evt.header.space_id = CLAP_CORE_EVENT_SPACE_ID;
evt.header.flags = 0;
// The way the CLAP/JUCE wrapper is able to accomplish sample-accurate
// parameter automation/modulation is by splitting up the incoming CLAP
// audio block into multiple JUCE `processBlock()` calls. So when adding
// events to the output event queue, we need to take the note end time
// relative to the last `processBlock()` call and add the sample offset
// to get the correct event time relative to the start of the CLAP block.
evt.header.time = uint32_t(noteEndEvent.noteEndTime + sampleOffset);
// some of these values may be zero, for example
// your synth might not have a concept of "note ports".
evt.port_index = noteEndEvent.notePort;
evt.channel = noteEndEvent.channel;
evt.key = noteEndEvent.key;
evt.note_id = noteEndEvent.noteID;
evt.velocity = noteEndEvent.velocity;
out_events->try_push(out_events, reinterpret_cast<const clap_event_header *>(&evt));
}
}
};
```
For plugins that produce MIDI, extra care needs to be taken during this step.
Any MIDI events in the `juce::MidiBuffer` which is passed to
`addOutboundEventsToQueue()` will also need to be added to the output event
queue, however, since all the events in the queue need to be ordered sequentially,
the implementer may need to "interleave" the note end events with the MIDI events
in order to make sure all the events are in the correct order.
## Troubleshooting
If you run into difficulties when trying to implement parameter modulation in your
plugin, please create a GitHub Issue in this repo. If the wrapper API for supporting
parameter modulation appears to be incomplete, Pull Requests for improving the API
are welcome!

View File

@ -1,23 +0,0 @@
set(COMPANY_NAME "free-audio")
set(COMPANY_CODE "FrAu")
set(JUCE_FORMATS AU VST3 Standalone)
option(CLAP_WRAP_PROJUCER_PLUGIN "Wrap a CLAP plugin from a Projucer build" OFF)
option(CLAP_EXAMPLES_TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors for the example plugin builds" OFF)
if(CLAP_EXAMPLES_TREAT_WARNINGS_AS_ERRORS)
message(STATUS "Building CLAP example plugins with \"-Werror\"")
add_compile_options(
$<$<CXX_COMPILER_ID:MSVC>:/WX>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Werror>
)
# JUCE 6.0.7 gets a deprecated declaration in its CoreAudio
# code. We can remove this once we're no longer building JUCE
# 6.0.7 in our CI.
if(APPLE AND CLAP_JUCE_VERSION STREQUAL "6.0.7")
add_compile_options(-Wno-deprecated-declarations)
endif()
endif()
add_subdirectory(GainPlugin)

View File

@ -1,71 +0,0 @@
if(CLAP_WRAP_PROJUCER_PLUGIN)
set(PATH_TO_JUCE "${JUCE_SOURCE_DIR}")
set(PATH_TO_CLAP_EXTENSIONS ${CMAKE_CURRENT_SOURCE_DIR}/../..)
if(APPLE)
set(JUCER_GENERATOR "Xcode")
elseif(WIN32)
set(JUCER_GENERATOR "VisualStudio2019")
else() # Linux
set(JUCER_GENERATOR "LinuxMakefile")
endif()
include(${PATH_TO_CLAP_EXTENSIONS}/cmake/JucerClap.cmake)
create_jucer_clap_target(
TARGET "GainPlugin"
PLUGIN_NAME "GainPlugin"
BINARY_NAME "MyGreatGainPlugin"
PLUGIN_CODE "Gplg"
MANUFACTURER_NAME "${COMPANY_NAME}"
MANUFACTURER_CODE "${COMPANY_CODE}"
VERSION_STRING "${CMAKE_PROJECT_VERSION}"
CLAP_ID "org.free-audio.GainPlugin"
CLAP_FEATURES audio-effect utility
CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 64
)
return()
endif()
juce_add_plugin(GainPlugin
COMPANY_NAME "${COMPANY_NAME}"
PLUGIN_MANUFACTURER_CODE "${COMPANY_CODE}"
PLUGIN_CODE Gplg
FORMATS ${JUCE_FORMATS}
PRODUCT_NAME "GainPlugin"
)
clap_juce_extensions_plugin(
TARGET GainPlugin
CLAP_ID "org.free-audio.GainPlugin"
CLAP_FEATURES audio-effect utility
CLAP_PROCESS_EVENTS_RESOLUTION_SAMPLES 64
)
target_sources(GainPlugin PRIVATE
GainPlugin.cpp
PluginEditor.cpp
)
target_compile_definitions(GainPlugin PUBLIC
JUCE_DISPLAY_SPLASH_SCREEN=1
JUCE_REPORT_APP_USAGE=0
JUCE_WEB_BROWSER=0
JUCE_USE_CURL=0
JUCE_JACK=1
JUCE_ALSA=1
JUCE_MODAL_LOOPS_PERMITTED=1 # required for Linux FileChooser with JUCE 6.0.7
JUCE_VST3_CAN_REPLACE_VST2=0
)
target_link_libraries(GainPlugin
PRIVATE
juce::juce_audio_utils
juce::juce_audio_plugin_client
juce::juce_dsp
clap_juce_extensions
PUBLIC
juce::juce_recommended_config_flags
juce::juce_recommended_lto_flags
juce::juce_recommended_warning_flags
)

View File

@ -1,89 +0,0 @@
#include "GainPlugin.h"
#include "PluginEditor.h"
namespace
{
static const juce::String gainParamTag = "gain_db";
}
GainPlugin::GainPlugin()
: juce::AudioProcessor(BusesProperties()
.withInput("Input", juce::AudioChannelSet::stereo(), true)
.withOutput("Output", juce::AudioChannelSet::stereo(), true)),
vts(*this, nullptr, juce::Identifier("Parameters"), createParameters())
{
gainDBParameter = dynamic_cast<ModulatableFloatParameter *>(vts.getParameter(gainParamTag));
}
juce::AudioProcessorValueTreeState::ParameterLayout GainPlugin::createParameters()
{
std::vector<std::unique_ptr<juce::RangedAudioParameter>> params;
params.push_back(std::make_unique<ModulatableFloatParameter>(
gainParamTag, "Gain", juce::NormalisableRange<float>{-30.0f, 30.0f}, 0.0f,
[](float val) {
juce::String gainStr = juce::String(val, 2, false);
return gainStr + " dB";
},
[](const juce::String &s) { return s.getFloatValue(); }));
return {params.begin(), params.end()};
}
bool GainPlugin::isBusesLayoutSupported(const juce::AudioProcessor::BusesLayout &layouts) const
{
// only supports mono and stereo
if (layouts.getMainOutputChannelSet() != juce::AudioChannelSet::mono() &&
layouts.getMainOutputChannelSet() != juce::AudioChannelSet::stereo())
return false;
// input and output layout must be the same
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
return true;
}
void GainPlugin::prepareToPlay(double sampleRate, int samplesPerBlock)
{
gain.prepare(
{sampleRate, (juce::uint32)samplesPerBlock, (juce::uint32)getMainBusNumOutputChannels()});
gain.setRampDurationSeconds(0.05);
}
void GainPlugin::processBlock(juce::AudioBuffer<float> &buffer, juce::MidiBuffer &)
{
auto &&block = juce::dsp::AudioBlock<float>{buffer};
gain.setGainDecibels(gainDBParameter->getCurrentValue());
gain.process(juce::dsp::ProcessContextReplacing<float>{block});
}
juce::AudioProcessorEditor *GainPlugin::createEditor() { return new PluginEditor(*this); }
juce::String GainPlugin::getPluginTypeString() const
{
if (wrapperType == juce::AudioProcessor::wrapperType_Undefined && is_clap)
return "CLAP";
return juce::AudioProcessor::getWrapperTypeDescription(wrapperType);
}
void GainPlugin::getStateInformation(juce::MemoryBlock &data)
{
auto state = vts.copyState();
std::unique_ptr<juce::XmlElement> xml(state.createXml());
copyXmlToBinary(*xml, data);
}
void GainPlugin::setStateInformation(const void *data, int sizeInBytes)
{
std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
if (xmlState != nullptr)
if (xmlState->hasTagName(vts.state.getType()))
vts.replaceState(juce::ValueTree::fromXml(*xmlState));
}
// This creates new instances of the plugin
juce::AudioProcessor *JUCE_CALLTYPE createPluginFilter() { return new GainPlugin(); }

View File

@ -1,53 +0,0 @@
#pragma once
#include <juce_dsp/juce_dsp.h>
#include "ModulatableFloatParameter.h"
class ModulatableFloatParameter;
class GainPlugin : public juce::AudioProcessor,
public clap_juce_extensions::clap_juce_audio_processor_capabilities,
protected clap_juce_extensions::clap_properties
{
public:
GainPlugin();
static juce::AudioProcessorValueTreeState::ParameterLayout createParameters();
const juce::String getName() const override { return JucePlugin_Name; }
bool acceptsMidi() const override { return false; }
bool producesMidi() const override { return false; }
bool isMidiEffect() const override { return false; }
double getTailLengthSeconds() const override { return 0.0; }
int getNumPrograms() override { return 1; }
int getCurrentProgram() override { return 0; }
void setCurrentProgram(int) override {}
const juce::String getProgramName(int) override { return juce::String(); }
void changeProgramName(int, const juce::String &) override {}
bool isBusesLayoutSupported(const juce::AudioProcessor::BusesLayout &layouts) const override;
void prepareToPlay(double sampleRate, int samplesPerBlock) override;
void releaseResources() override {}
void processBlock(juce::AudioBuffer<float> &, juce::MidiBuffer &) override;
void processBlock(juce::AudioBuffer<double> &, juce::MidiBuffer &) override {}
bool hasEditor() const override { return true; }
juce::AudioProcessorEditor *createEditor() override;
void getStateInformation(juce::MemoryBlock &data) override;
void setStateInformation(const void *data, int sizeInBytes) override;
juce::String getPluginTypeString() const;
auto *getGainParameter() { return gainDBParameter; }
auto &getValueTreeState() { return vts; }
private:
ModulatableFloatParameter *gainDBParameter = nullptr;
juce::AudioProcessorValueTreeState vts;
juce::dsp::Gain<float> gain;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(GainPlugin)
};

View File

@ -1,109 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="luqvtz" name="GainPlugin" projectType="audioplug" useAppConfig="0"
jucerFormatVersion="1" headerPath="../../../../include&#10;../../../../clap-libs/clap/include&#10;../../../../clap-libs/clap-helpers/include"
cppLanguageStandard="17" defines="HAS_CLAP_JUCE_EXTENSIONS=1"
addUsingNamespaceToJuceHeader="0">
<MAINGROUP id="YenzOu" name="GainPlugin">
<GROUP id="{38320511-2ECE-0246-11DC-4FBB99C5617C}" name="CLAP">
<FILE id="i719ku" name="clap-juce-extensions.cpp" compile="1" resource="0"
file="../../src/extensions/clap-juce-extensions.cpp"/>
</GROUP>
<GROUP id="{422CF038-C3ED-FE29-2115-57EAEE923726}" name="Source">
<FILE id="sfdoog" name="GainPlugin.cpp" compile="1" resource="0" file="GainPlugin.cpp"/>
<FILE id="CwQ2Yq" name="GainPlugin.h" compile="0" resource="0" file="GainPlugin.h"/>
<FILE id="fADOqj" name="ModulatableFloatParameter.h" compile="0" resource="0"
file="ModulatableFloatParameter.h"/>
<FILE id="R7b3jn" name="PluginEditor.cpp" compile="1" resource="0"
file="PluginEditor.cpp"/>
<FILE id="ehXQhT" name="PluginEditor.h" compile="0" resource="0" file="PluginEditor.h"/>
</GROUP>
</MAINGROUP>
<JUCEOPTIONS JUCE_STRICT_REFCOUNTEDPOINTER="1" JUCE_VST3_CAN_REPLACE_VST2="0"
FOLEYS_SHOW_GUI_EDITOR_PALLETTE="0" FOLEYS_ENABLE_BINARY_DATA="1"
JUCE_USE_CURL="0" JUCE_WEB_BROWSER="0"/>
<EXPORTFORMATS>
<LINUX_MAKE targetFolder="Builds/LinuxMakefile">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" targetName="GainPlugin"/>
<CONFIGURATION isDebug="0" name="Release" targetName="GainPlugin"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_core" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_devices" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_events" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_formats" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_utils" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_processors" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_extra" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_graphics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_data_structures" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_dsp" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_plugin_client" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="chowdsp_plugin_base"/>
</MODULEPATHS>
</LINUX_MAKE>
<VS2019 targetFolder="Builds/VisualStudio2019">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" targetName="GainPlugin"/>
<CONFIGURATION isDebug="0" name="Release" targetName="GainPlugin"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_core" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_devices" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_events" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_formats" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_utils" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_processors" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_extra" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_graphics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_data_structures" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_dsp" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_plugin_client" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="chowdsp_plugin_base"/>
</MODULEPATHS>
</VS2019>
<XCODE_MAC targetFolder="Builds/MacOSX">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" targetName="GainPlugin" enablePluginBinaryCopyStep="0"/>
<CONFIGURATION isDebug="0" name="Release" targetName="GainPlugin" enablePluginBinaryCopyStep="0"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_core" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_devices" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_events" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_formats" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_utils" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_processors" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_extra" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_gui_basics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_graphics" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_data_structures" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_dsp" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="juce_audio_plugin_client" path="../../build/_deps/juce-src/modules"/>
<MODULEPATH id="chowdsp_plugin_base"/>
</MODULEPATHS>
</XCODE_MAC>
</EXPORTFORMATS>
<MODULES>
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"
useGlobalPath="0"/>
<MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
</MODULES>
</JUCERPROJECT>

View File

@ -1,61 +0,0 @@
#pragma once
#include <juce_audio_utils/juce_audio_utils.h>
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE("-Wunused-parameter", "-Wextra-semi", "-Wnon-virtual-dtor")
#include <clap-juce-extensions/clap-juce-extensions.h>
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
class ModulatableFloatParameter : public juce::AudioParameterFloat,
public clap_juce_extensions::clap_juce_parameter_capabilities
{
public:
ModulatableFloatParameter(const juce::String &parameterID, const juce::String &parameterName,
const juce::NormalisableRange<float> &valueRange,
float defaultFloatValue,
const std::function<juce::String(float)> &valueToTextFunction,
std::function<float(const juce::String &)> &&textToValueFunction)
#if JUCE_VERSION < 0x070000
: juce::AudioParameterFloat(
parameterID, parameterName, valueRange, defaultFloatValue, juce::String(),
AudioProcessorParameter::genericParameter,
valueToTextFunction == nullptr
? std::function<juce::String(float v, int)>()
: [valueToTextFunction](float v, int) { return valueToTextFunction(v); },
std::move(textToValueFunction)),
#else
: juce::AudioParameterFloat(
parameterID, parameterName, valueRange, defaultFloatValue,
juce::AudioParameterFloatAttributes()
.withStringFromValueFunction(
[valueToTextFunction](float v, int) { return valueToTextFunction(v); })
.withValueFromStringFunction(std::move(textToValueFunction))),
#endif
unsnappedDefault(valueRange.convertTo0to1(defaultFloatValue)),
normalisableRange(valueRange)
{
}
float getDefaultValue() const override { return unsnappedDefault; }
bool supportsMonophonicModulation() override { return true; }
void applyMonophonicModulation(double modulationValue) override
{
modulationAmount = (float)modulationValue;
}
float getCurrentValue() const noexcept
{
return normalisableRange.convertFrom0to1(
juce::jlimit(0.0f, 1.0f, normalisableRange.convertTo0to1(get()) + modulationAmount));
}
private:
const float unsnappedDefault;
const juce::NormalisableRange<float> normalisableRange;
float modulationAmount = 0.0f;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ModulatableFloatParameter)
};

View File

@ -1,53 +0,0 @@
#include "PluginEditor.h"
PluginEditor::PluginEditor(GainPlugin &plug) : juce::AudioProcessorEditor(plug), plugin(plug)
{
setSize(300, 300);
addAndMakeVisible(gainSlider);
gainSlider.setSliderStyle(juce::Slider::SliderStyle::RotaryHorizontalVerticalDrag);
gainSlider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, 100, 20);
auto *gainParameter = plugin.getGainParameter();
sliderAttachment =
std::make_unique<juce::SliderParameterAttachment>(*gainParameter, gainSlider, nullptr);
plugin.getValueTreeState().addParameterListener(gainParameter->paramID, this);
}
PluginEditor::~PluginEditor()
{
auto *gainParameter = plugin.getGainParameter();
plugin.getValueTreeState().removeParameterListener(gainParameter->paramID, this);
}
void PluginEditor::resized()
{
gainSlider.setBounds(juce::Rectangle<int>{200, 200}.withCentre(getLocalBounds().getCentre()));
}
void PluginEditor::paint(juce::Graphics &g)
{
g.fillAll(juce::Colours::grey);
g.setColour(juce::Colours::black);
g.setFont(25.0f);
const auto titleBounds = getLocalBounds().removeFromTop(30);
const auto titleText = "Gain Plugin " + plugin.getPluginTypeString();
g.drawFittedText(titleText, titleBounds, juce::Justification::centred, 1);
}
void PluginEditor::parameterChanged(const juce::String &, float)
{
// visual feedback so we know the parameter listeners are getting called:
struct FlashComponent : Component
{
void paint(juce::Graphics &g) override { g.fillAll(juce::Colours::red); }
} flashComp;
addAndMakeVisible(flashComp);
flashComp.setBounds(juce::Rectangle<int>{getWidth() - 10, 0, 10, 10});
auto &animator = juce::Desktop::getInstance().getAnimator();
animator.fadeOut(&flashComp, 100);
}

View File

@ -1,24 +0,0 @@
#pragma once
#include "GainPlugin.h"
class PluginEditor : public juce::AudioProcessorEditor,
private juce::AudioProcessorValueTreeState::Listener
{
public:
explicit PluginEditor(GainPlugin &plugin);
~PluginEditor() override;
void resized() override;
void paint(juce::Graphics &g) override;
private:
void parameterChanged(const juce::String &parameterID, float newValue) override;
GainPlugin &plugin;
juce::Slider gainSlider;
std::unique_ptr<juce::SliderParameterAttachment> sliderAttachment;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginEditor)
};

View File

@ -1,21 +0,0 @@
set(CPM_DOWNLOAD_VERSION 0.35.0)
if(CPM_SOURCE_CACHE)
# Expand relative path. This is important if the provided path contains a tilde (~)
get_filename_component(CPM_SOURCE_CACHE ${CPM_SOURCE_CACHE} ABSOLUTE)
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
else()
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
endif()
if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}")
file(DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
endif()
include(${CPM_DOWNLOAD_LOCATION})

View File

@ -1,272 +0,0 @@
/*
* This file contains C++ interface classes which allow your AudioProcessor or
* AudioProcessorParameter to implement additional clap-specific capabilities, and then allows the
* CLAP wrapper to detect those capabilities and activate advanced features beyond the base
* JUCE model.
*/
#ifndef SURGE_CLAP_JUCE_EXTENSIONS_H
#define SURGE_CLAP_JUCE_EXTENSIONS_H
#include <clap/events.h>
#include <clap/plugin.h>
#include <clap/helpers/plugin.hh>
#include <atomic>
/** Forward declaration of the wrapper class. */
class ClapJuceWrapper;
struct JUCEParameterVariant;
/** Forward declarations for any JUCE classes we might need. */
namespace juce
{
class MidiBuffer;
class AudioProcessorParameter;
class RangedAudioParameter;
} // namespace juce
namespace clap_juce_extensions
{
/*
* clap_properties contains simple properties about clap which you may want to use.
*/
struct clap_properties
{
clap_properties();
virtual ~clap_properties() = default;
// The three part clap version
static uint32_t clap_version_major, clap_version_minor, clap_version_revision;
// this will be true for the clap instance and false for all other flavors
bool is_clap{false};
// this will be non-null in the process block of a clap where the DAW provides transport
const clap_event_transport *clap_transport{nullptr};
// The processing and active clap state
std::atomic<bool> is_clap_active{false}, is_clap_processing{false};
// Internal implementation detail. Please disregard (and FIXME)
static bool building_clap;
};
/*
* clap_juce_audio_processor_capabilities allows you to interact with advanced properties of the
* CLAP api. The default implementations here mean if you implement
* clap_juce_audio_processor_capabilities and override nothing, you get the same behaviour as if you
* hadn't implemented it.
*/
struct clap_juce_audio_processor_capabilities
{
virtual ~clap_juce_audio_processor_capabilities() = default;
/*
* In some cases, there is no main input, and input 0 is not main. Allow your plugin
* to advertise that. (This case is usually for synths with sidechains).
*/
virtual bool isInputMain(int input)
{
if (input == 0)
return true;
else
return false;
}
/*
* If you want to provide information about voice structure, as documented
* in the voice-info clap extension.
*/
virtual bool supportsVoiceInfo() { return false; }
virtual bool voiceInfoGet(clap_voice_info * /*info*/) { return false; }
/*
* Do you want to receive note expression messages? Note that if you return true
* here and don't implement supportsDirectProcess, the note expression messages will
* be received and ignored.
*/
virtual bool supportsNoteExpressions() { return false; }
/**
* The regular CLAP/JUCE wrapper handles the following CLAP events:
* - MIDI note on/off events
* - MIDI CC events
* - Parameter change events
* - Parameter modulation events
*
* If you would like to handle these events using some custom behaviour, or if you would like
* to handle other CLAP events (e.g. note expression), or events from another namespace, you
* should override this method to return true for those event types.
*
* @param space_id The namespace ID for the given event.
* @param type The event type.
*/
virtual bool supportsDirectEvent(uint16_t /*space_id*/, uint16_t /*type*/) { return false; }
/**
* If your plugin returns true for supportsDirectEvent, then you'll need to
* implement this method to actually handle that event when it comes along.
*
* @param event The header for the incoming event.
* @param sampleOffset If the CLAP wrapper has split up the incoming buffer (e.g. to
* apply sample-accurate automation), then you'll need to apply
* this sample offset to the timestamp of the incoming event
* to get the actual event time relative to the start of the
* next incoming buffer to your processBlock method. For example:
* `const auto actualNoteTime = noteEvent->header.time - sampleOffset;`
*/
virtual void handleDirectEvent(const clap_event_header_t * /*event*/, int /*sampleOffset*/) {}
/**
* If your plugin needs to send outbound events (for example, telling the host that a
* note has ended), you should override this method to return true.
*/
virtual bool supportsOutboundEvents() { return false; }
/**
* If your plugin returns true for supportsOutboundEvents, then this method will be
* called after your `processBlock()` method, so that any outbound events can be
* added to the output event queue.
*
* NOTE: if your plugin produces MIDI, you must take care to make sure that any outgoing
* events which are not MIDI events are correctly interleaved with the outgoing events
* from the midiBuffer, such that all the events in the output queue are ordered sequentially.
*
* @param out_events The output event queue.
* @param midiBuffer The JUCE MIDI Buffer from the previous `processBlock()` call.
* @param sampleOffset If the CLAP wrapper has split up the incoming buffer, then
* you'll need to apply this sample offset to the timestamp of
* the outgoing event. For example:
* `auto eventTime = eventTimeRelativeToStartOfLastBlock + sampleOffset;`
*/
virtual void addOutboundEventsToQueue(const clap_output_events * /*out_events*/,
const juce::MidiBuffer & /* midiBuffer */,
int /*sampleOffset*/)
{
}
/*
* The JUCE process loop makes it difficult to do things like note expressions,
* sample accurate parameter automation, and other CLAP features. The custom event handlers
* (above) help make some of these features possible, but for some use cases, a synth may
* want the entirety of the JUCE infrastructure *except* the process loop. (Surge is one
* such synth).
*
* In this case, you can implement supportsDirectProcess to return true and then the clap
* juce wrapper will skip most parts of the process loop (it will still set up transport
* and deal with UI thread -> audio thread change events), and then call clap_direct_process.
*
* In this mode, it is the synth designer responsibility to implement clap_direct_process
* side by side with AudioProcessor::processBlock to use the CLAP api and synth internals
* directly.
*
* In order to do this, you almost definitely need to both implement clap_direct_process and
* clap_direct_paramsFlush
*/
virtual bool supportsDirectProcess() { return false; }
virtual clap_process_status clap_direct_process(const clap_process * /*process*/) noexcept
{
return CLAP_PROCESS_CONTINUE;
}
virtual bool supportsDirectParamsFlush() { return false; }
virtual void clap_direct_paramsFlush(const clap_input_events * /*in*/,
const clap_output_events * /*out*/) noexcept
{
}
/**
* If you're implementing `clap_direct_process`, you should use this method
* to handle `CLAP_EVENT_PARAM_VALUE`, so that the parameter listeners are
* called on the main thread without creating a feedback loop.
*/
void handleParameterChange(const clap_event_param_value *paramEvent)
{
parameterChangeHandler(paramEvent);
}
/*
* Do I support the CLAP_NOTE_DIALECT_CLAP? And prefer it if so? By default this
* is true if I support either note expressions, direct processing, or voice info,
* but you can override it for other reasons also, including not liking that default.
*
* The strictest hosts will not send note expression without this dialect, and so
* if you override this to return false, hosts may not give you NE or Voice level
* modulators in clap_direct_process.
*/
virtual bool supportsNoteDialectClap(bool /* isInput */)
{
return supportsNoteExpressions() || supportsVoiceInfo() || supportsDirectProcess();
}
virtual bool prefersNoteDialectClap(bool isInput) { return supportsNoteDialectClap(isInput); }
/*
* If you are working with a host that chooses to not implement cookies you will
* need to look up parameters by param_id. Use this method to do so.
*/
JUCEParameterVariant *findParameterByParameterId(clap_id param_id)
{
if (lookupParamByID)
return lookupParamByID(param_id);
return nullptr;
}
private:
friend class ::ClapJuceWrapper;
std::function<void(const clap_event_param_value *)> parameterChangeHandler = nullptr;
std::function<JUCEParameterVariant *(clap_id)> lookupParamByID = nullptr;
};
/*
* clap_juce_parameter_capabilities is intended to be applied to AudioParameter subclasses. When
* asking your JUCE plugin for parameters, the clap wrapper will check if your parameter
* implements the capabilities and call the associated functions.
*/
struct clap_juce_parameter_capabilities
{
virtual ~clap_juce_parameter_capabilities() = default;
/*
* Return true if this parameter should receive non-destructive
* monophonic modulation rather than simple setValue when a DAW
* initiated modulation changes.
*/
virtual bool supportsMonophonicModulation() { return false; }
/** Implement this method to apply the parameter modulation event to your parameter. */
virtual void applyMonophonicModulation(double /*amount*/) {}
/*
* Return true if this parameter should receive non-destructive polyphonic modulation. If this
* method returns true, then the host will also expect that the paramter can handle monophonic
* modulation. Additionally, your plugin must return note end events when notes are terminated,
* by implementing either `addOutboundEventsToQueue()` or `clap_direct_process()`.
*/
virtual bool supportsPolyphonicModulation() { return false; }
/** Implement this method to apply the parameter modulation event to your parameter. */
virtual void applyPolyphonicModulation(int32_t /*note_id*/, int16_t /*port_index*/,
int16_t /*channel*/, int16_t /*key*/, double /*amount*/)
{
}
};
} // namespace clap_juce_extensions
/**
* JUCE parameter that could be ranged, or could extend the clap_juce_parameter_capabilities.
*
* When handling CLAP parameter events (e.g. CLAP_EVENT_PARAM_VALUE or CLAP_EVENT_PARAM_MOD),
* the event `cookie` will be a `JUCEParameterVariant*`.
*/
struct JUCEParameterVariant
{
/** After the plugin has been initialized, this field should never be a nullptr! */
juce::AudioProcessorParameter *processorParam = nullptr;
/** Depending on the underlying parameter type, these could be nullptr. */
juce::RangedAudioParameter *rangedParameter = nullptr;
clap_juce_extensions::clap_juce_parameter_capabilities *clapExtParameter = nullptr;
};
#endif // SURGE_CLAP_JUCE_EXTENSIONS_H

View File

@ -1,15 +0,0 @@
//
// Created by Paul Walker on 12/19/21.
//
#include "clap-juce-extensions/clap-juce-extensions.h"
namespace clap_juce_extensions
{
bool clap_properties::building_clap{false};
uint32_t clap_properties::clap_version_major{0}, clap_properties::clap_version_minor{0},
clap_properties::clap_version_revision{0};
clap_properties::clap_properties() : is_clap{building_clap} {}
} // namespace clap_juce_extensions

View File

@ -1,13 +0,0 @@
/*
* This file allows our CLAP extension to load the objective
* C extensions that JUCE uses to create a UI on mac in the
* VST3 and VST implementations. Basically it provides the pair
* of functions to attach our NSView to the parent window properly
* from the juce editor. This code is maintained by the JUCE team
* but we need to link it here also, so create this little stub
* which (for this one file only) tells JUCE I'm a VST3 and makes
* the objective C symbols available.
*/
#define JucePlugin_Build_VST3 1
#include "juce_audio_plugin_client/VST/juce_VST_Wrapper.mm"

File diff suppressed because it is too large Load Diff

View File

@ -1,98 +0,0 @@
name: Bug Report
description: File a bug report
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Thank you for reporting an issue with JUCE.
- type: textarea
id: repro
attributes:
label: Detailed steps on how to reproduce the bug
description: If possible please use already existing JUCE code such as the examples or the demo plug-in
validations:
required: true
- type: textarea
id: expected
attributes:
label: What is the expected behaviour?
validations:
required: true
- type: dropdown
id: os
attributes:
label: Operating systems
description: What operating systems do you see the bug on?
multiple: true
options:
- Windows
- macOS
- Linux
- iOS
- Android
- Other
validations:
required: true
- type: textarea
id: osversion
attributes:
label: What versions of the operating systems?
validations:
required: true
- type: dropdown
id: architecture
attributes:
label: Architectures
description: What types of machine do you see the bug on?
multiple: true
options:
- x86_64
- ARM
- Other
- 64-bit
- 32-bit
validations:
required: true
- type: textarea
id: stacktrace
attributes:
label: Stacktrace
description: Please copy and paste any relevant stack trace. This will be automatically formatted into code, so no need for backticks.
render: shell
- type: dropdown
id: pluginformat
attributes:
label: Plug-in formats (if applicable)
multiple: true
options:
- VST2
- VST3
- AU
- AUv3
- AAX
- LV2
- Standalone
- type: textarea
id: pluginhost
attributes:
label: Plug-in host applications (DAWs) (if applicable)
- type: dropdown
id: branch
attributes:
label: Testing on the `develop` branch
description: We have often already fixed bugs on our `develop` branch. Please confirm if you have tested with the latest commit.
options:
- The bug is present on the `develop` branch
- I have not tested against the `develop` branch
validations:
required: true
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://berlincodeofconduct.org/)
options:
- label: I agree to follow the Code of Conduct
required: true

View File

@ -1,8 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: JUCE Support
url: https://forum.juce.com/
about: Please use the JUCE forum to ask questions.
- name: Feature Requests
url: https://forum.juce.com/c/feature-requests
about: Please submit feature requests on the JUCE forum.

View File

@ -1,34 +0,0 @@
## Contributing
#### Feature Requests
Any feature requests should be posted to the [Feature
Requests](https://forum.juce.com/c/feature-requests/) section of the JUCE
forum.
#### Bug Reports
The [JUCE forum](https://forum.juce.com/) is also the best place to file bug
reports. The JUCE developers are very active there and will read every post and
respond accordingly.
#### Pull Requests
You must sign the [JUCE Contribution Licence Agreement](https://cla.juce.com/)
before your code can be considered for inclusion into JUCE. The automated build
of your Pull Request (PR) will fail if either the author or committer of any
commits in your PR has not signed the Contribution Licence Agreement.
This repository contains just the public branches of the main JUCE development
repository. Any work in your PR will not be merged into any other branch in
this repository, but will instead be reproduced in our private repository. We
may refactor and rewite any code submitted to us in PRs.
All work should be based on our `develop` branch.
#### Code Of Conduct
All interactions of any kind with the code in this repository or the
surrounding commentary in Issues or Pull Requests must abide by our [Code of
Conduct](https://berlincodeofconduct.org/).

View File

@ -1,4 +0,0 @@
Thank you for submitting a pull request.
Please make sure you have read and followed our contribution guidelines (.github/contributing.md in this repository). Your pull request will not be accepted if you have not followed the instructions.

View File

@ -1,30 +0,0 @@
name: check-CLA
on: [pull_request_target]
jobs:
check-cla:
runs-on: ubuntu-latest
env:
PR_NUMBER: ${{ github.event.number }}
steps:
- name: check-CLA
run: |
import urllib.request
import json
import itertools
import sys
def jsonRequest(url, data={}):
req = urllib.request.Request(url,
headers={'Content-Type': 'application/json'},
data=json.dumps(data).encode('utf-8') if data else None)
with urllib.request.urlopen(req) as response:
return json.loads(response.read().decode('utf-8'))
prCommits = jsonRequest('https://api.github.com/repos/juce-framework/JUCE/pulls/${{ github.event.number }}/commits')
authors = map(lambda commit: [commit['author']['login'], commit['committer']['login']], prCommits)
uniqueAuthors = list(set(itertools.chain.from_iterable(authors)))
print(f'\nPR authors: {", ".join(uniqueAuthors)}')
claResult = jsonRequest('https://cla.juce.com/check', {'logins': uniqueAuthors})
unsignedLogins = claResult['unsigned']
if (len(unsignedLogins) != 0):
print(f'\nThe following GitHub users need to sign the JUCE CLA: {", ".join(unsignedLogins)}\n\nPlease go to https://cla.juce.com to sign the JUCE Contributor Licence Agreement\n')
sys.exit(1)
shell: python

67
deps/juce/.gitignore vendored
View File

@ -1,67 +0,0 @@
._*
*.mode1v3
*.pbxuser
*.perspectivev3
*.user
*.ncb
*.suo
*.ilk
*.pch
*.pdb
*.dep
*.idb
*.manifest
*.manifest.res
*.o
*.d
*.sdf
*.opensdf
*.VC.db
*.VC.opendb
xcuserdata
*.xccheckout
*.xcscmblueprint
*.xcscheme
contents.xcworkspacedata
.DS_Store
.svn
.deps
.dirstamp
profile
**/MacOSX/build
**/iOS/build
**/IDEWorkspaceChecks.plist
**/Linux/build
**/LinuxMakefile/build
**/VisualStudio[0-9]*/Win32
**/VisualStudio[0-9]*/x64
**/Builds/x64
**/.vs
**/CodeBlocks/bin
**/CodeBlocks/obj
**/CodeBlocks/*.depend
**/CodeBlocks/*.layout
**/Builds/Android/.gradle
**/Builds/Android/.idea
**/Builds/Android/build
**/Builds/Android/**/*.iml
**/Builds/Android/local.properties
**/Builds/Android/app/build
**/Builds/Android/app/.externalNativeBuild
**/Builds/Android/app/.cxx
**/Builds/Android/lib/build
**/Builds/Android/lib/.externalNativeBuild
**/Builds/MacOSX/**/Index
**/Builds/MacOSX/**/Intermediates.noindex
**/doxygen/doc
**/doxygen/build
**/.idea
extras/Projucer/JUCECompileEngine.dylib
.idea
**/cmake-build*
.vscode
/build
CMakeUserPresets.json

View File

@ -1,4 +0,0 @@
include:
- project: 'juce-repos/JUCE-utils'
file: '/CI/gitlab-ci.yml'

File diff suppressed because it is too large Load Diff

View File

@ -1,169 +0,0 @@
# ==============================================================================
#
# This file is part of the JUCE library.
# Copyright (c) 2022 - Raw Material Software Limited
#
# JUCE is an open source library subject to commercial or open-source
# licensing.
#
# By using JUCE, you agree to the terms of both the JUCE 7 End-User License
# Agreement and JUCE Privacy Policy.
#
# End User License Agreement: www.juce.com/juce-7-licence
# Privacy Policy: www.juce.com/juce-privacy-policy
#
# Or: You may also use this code under the terms of the GPL v3 (see
# www.gnu.org/licenses).
#
# JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
# EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
# DISCLAIMED.
#
# ==============================================================================
cmake_minimum_required(VERSION 3.15)
project(JUCE VERSION 7.0.2 LANGUAGES C CXX)
include(CMakeDependentOption)
set_property(GLOBAL PROPERTY USE_FOLDERS YES)
set(JUCE_MODULES_DIR "${JUCE_SOURCE_DIR}/modules" CACHE INTERNAL
"The path to JUCE modules")
# This option will disable most of the JUCE helper functions and tools. This option exists to
# facilitate existing CMake builds which handle things like bundle creation, icons, plists, and
# binary data independently of JUCE. This option is not recommended - use at your own risk!
option(JUCE_MODULES_ONLY "Only configure the JUCE modules" OFF)
include(extras/Build/CMake/JUCEModuleSupport.cmake)
# This option controls whether dummy targets are added to the build, where these targets contain all
# of the source files for each JUCE module. If you're planning to use an IDE and want to be able to
# browse all of JUCE's source files, this may be useful. However, it will increase the size of
# generated IDE projects and might slow down configuration a bit. If you enable this, you should
# probably also add `set_property(GLOBAL PROPERTY USE_FOLDERS YES)` to your top level CMakeLists,
# otherwise the module sources will be added directly to the top level of the project, instead of in
# a nice 'Modules' subfolder.
cmake_dependent_option(JUCE_ENABLE_MODULE_SOURCE_GROUPS
"Show all module sources in IDE projects" OFF
"NOT JUCE_MODULES_ONLY" OFF)
add_subdirectory(modules)
if(JUCE_MODULES_ONLY)
return()
endif()
include(extras/Build/CMake/JUCEUtils.cmake)
set_directory_properties(PROPERTIES
JUCE_COMPANY_NAME "JUCE"
JUCE_COMPANY_WEBSITE "https://juce.com"
JUCE_COMPANY_EMAIL "info@juce.com"
JUCE_COMPANY_COPYRIGHT "Copyright (c) 2020 - Raw Material Software Limited")
option(JUCE_COPY_PLUGIN_AFTER_BUILD
"Whether or not plugins should be installed to the system after building" OFF)
set_property(GLOBAL PROPERTY JUCE_COPY_PLUGIN_AFTER_BUILD ${JUCE_COPY_PLUGIN_AFTER_BUILD})
set(CMAKE_CXX_EXTENSIONS FALSE)
juce_disable_default_flags()
add_subdirectory(extras/Build)
# If you want to build the JUCE examples with VST2/AAX/ARA support, you'll need to make the
# VST2/AAX/ARA headers visible to the juce_audio_processors module. You can either set the paths on
# the command line, (e.g. -DJUCE_GLOBAL_AAX_SDK_PATH=/path/to/sdk) if you're just building the JUCE
# examples, or you can call the `juce_set_*_sdk_path` functions in your own CMakeLists after
# importing JUCE.
if(JUCE_GLOBAL_AAX_SDK_PATH)
juce_set_aax_sdk_path("${JUCE_GLOBAL_AAX_SDK_PATH}")
endif()
if(JUCE_GLOBAL_VST2_SDK_PATH)
juce_set_vst2_sdk_path("${JUCE_GLOBAL_VST2_SDK_PATH}")
endif()
# The ARA_SDK path should point to the "Umbrella installer" ARA_SDK directory.
# The directory can be obtained by recursively cloning https://github.com/Celemony/ARA_SDK and
# checking out the tag releases/2.1.0.
if(JUCE_GLOBAL_ARA_SDK_PATH)
juce_set_ara_sdk_path("${JUCE_GLOBAL_ARA_SDK_PATH}")
endif()
# We don't build anything other than the juceaide by default, because we want to keep configuration
# speedy and the number of targets low. If you want to add targets for the extra projects and
# example PIPs (there's a lot of them!), specify -DJUCE_BUILD_EXAMPLES=ON and/or
# -DJUCE_BUILD_EXTRAS=ON when initially generating your build tree.
option(JUCE_BUILD_EXTRAS "Add build targets for the Projucer and other tools" OFF)
if(JUCE_BUILD_EXTRAS)
add_subdirectory(extras)
endif()
option(JUCE_BUILD_EXAMPLES "Add build targets for the DemoRunner and PIPs" OFF)
if(JUCE_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# ==================================================================================================
# Install configuration
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.14")
set(extra_version_arg ARCH_INDEPENDENT)
endif()
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${JUCE_BINARY_DIR}/JUCEConfigVersion.cmake"
VERSION ${JUCE_VERSION}
COMPATIBILITY ExactVersion
${extra_version_arg})
set(JUCE_INSTALL_DESTINATION "lib/cmake/JUCE-${JUCE_VERSION}" CACHE STRING
"The location, relative to the install prefix, where the JUCE config file will be installed")
set(JUCE_MODULE_PATH "include/JUCE-${JUCE_VERSION}/modules")
set(UTILS_INSTALL_DIR "${JUCE_INSTALL_DESTINATION}")
set(JUCEAIDE_PATH "${JUCE_TOOL_INSTALL_DIR}/${JUCE_JUCEAIDE_NAME}")
configure_package_config_file("${JUCE_CMAKE_UTILS_DIR}/JUCEConfig.cmake.in"
"${JUCE_BINARY_DIR}/JUCEConfig.cmake"
PATH_VARS UTILS_INSTALL_DIR JUCEAIDE_PATH JUCE_MODULE_PATH
INSTALL_DESTINATION "${JUCE_INSTALL_DESTINATION}")
set(JUCE_MODULE_PATH "${JUCE_MODULES_DIR}")
set(UTILS_INSTALL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extras/Build/CMake")
get_target_property(JUCEAIDE_PATH juceaide IMPORTED_LOCATION)
configure_package_config_file("${JUCE_CMAKE_UTILS_DIR}/JUCEConfig.cmake.in"
"${JUCE_BINARY_DIR}/JUCEExportConfig.cmake"
PATH_VARS UTILS_INSTALL_DIR JUCEAIDE_PATH JUCE_MODULE_PATH
INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}"
INSTALL_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
install(FILES "${JUCE_BINARY_DIR}/JUCEConfigVersion.cmake"
"${JUCE_BINARY_DIR}/JUCEConfig.cmake"
"${JUCE_CMAKE_UTILS_DIR}/JUCECheckAtomic.cmake"
"${JUCE_CMAKE_UTILS_DIR}/JUCEHelperTargets.cmake"
"${JUCE_CMAKE_UTILS_DIR}/JUCEModuleSupport.cmake"
"${JUCE_CMAKE_UTILS_DIR}/JUCEUtils.cmake"
"${JUCE_CMAKE_UTILS_DIR}/JuceLV2Defines.h.in"
"${JUCE_CMAKE_UTILS_DIR}/LaunchScreen.storyboard"
"${JUCE_CMAKE_UTILS_DIR}/PIPAudioProcessor.cpp.in"
"${JUCE_CMAKE_UTILS_DIR}/PIPAudioProcessorWithARA.cpp.in"
"${JUCE_CMAKE_UTILS_DIR}/PIPComponent.cpp.in"
"${JUCE_CMAKE_UTILS_DIR}/PIPConsole.cpp.in"
"${JUCE_CMAKE_UTILS_DIR}/RecentFilesMenuTemplate.nib"
"${JUCE_CMAKE_UTILS_DIR}/UnityPluginGUIScript.cs.in"
"${JUCE_CMAKE_UTILS_DIR}/checkBundleSigning.cmake"
"${JUCE_CMAKE_UTILS_DIR}/copyDir.cmake"
"${JUCE_CMAKE_UTILS_DIR}/juce_runtime_arch_detection.cpp"
DESTINATION "${JUCE_INSTALL_DESTINATION}")
install(EXPORT LV2_HELPER NAMESPACE juce:: DESTINATION "${JUCE_INSTALL_DESTINATION}")

View File

@ -1,585 +0,0 @@
== Major JUCE features and updates ==
This file just lists the more notable headline features. For more detailed info
about changes and bugfixes please see the git log and BREAKING-CHANGES.txt.
Version 7.0.2
- Fixed accessibility table navigation
- Fixed Android file access on older APIs
- Improved Linux VST3 threading
- Improved ARA integration
Version 7.0.1
- Fixed some Xcode and MSVC compiler warnings
- Improved VST3 bus configuration and channel handling
- Fixed some Metal layer rendering bugs
Version 7.0.0
- Added Audio Random Access (ARA) SDK support
- Added support for authoring and hosting LV2 plug-ins
- Added a default renderer for macOS and iOS
- Added new macOS and iOS rendering options
- Added hardware synchronised drawing on Windows, macOS and iOS
- Updated the Android billing and file access APIs
- Revamped AudioPlayHead functionality
- Improved accessibility support
Version 6.1.6
- Improved the handling of AU multichannel layouts
- Added JUCE_NODISCARD to builder-patten functions
- Added recursion options to DirectoryIterator
- Unified the loading of OpenGL 3.2 core profiles
- Improved macOS full-screen behaviour with non-native titlebars
Version 6.1.5
- Improved the accessibility framework
- Added handling of non-Latin virtual key codes on macOS
- Improved X11 compatibility
- Updated the iOS in-app purchases workflow
- Improved macOS windowing behaviour
- Improved MinGW-w64 compatibility
- Added an MPEKeyboardComponent class
Version 6.1.4
- Restored Projucer project saving behavior
- Fixed a CGImage memory access violation on Monterey
- Improved macOS thread priority management
Version 6.1.3
- Added support for Visual Studio 2022 to the Projucer
- Added support for creating OpenGL 3.2 contexts on Windows
- Added support for plugin hosts to easily retrieve stable parameter IDs
- Added high-resolution image support to DragAndDropContainer
- Added support for a wider range of frame-rates in plugins and hosts
- Made Font and TypefaceCache threadsafe, to allow font rendering on background threads
- Improved FlexBox compatibility with the CSS FlexBox specification
- Improved macOS 12 compatibility, including OpenGL and FileChooser fixes
- Improved accessibility support
Version 6.1.2
- Fixed an OpenGL display refresh rate issue on macOS
- Improved the scaling behaviour of hosted VST3 plug-ins
- Improved accessibility support
Version 6.1.1
- Fixed a CMake installation issue
- Improved parameter value loading after plug-in restarts
- Fixed some problems with multi-line text layouts
- Added a fallback for modal native message boxes on Windows
- Fixed an issue setting OpenGL repaint events
- Improved accessibility support
Version 6.1.0
- Added accessibility support
- Enabled use of VST3 plug-in extensions
- Improved OpenGL function loading
- Updated to C++14
- Added support for macOS Monterey and iOS 15
- Added async versions of all modal functions
- Fixed some VST3 threading issues
- Added cross-platform-compatible VST3 UID hash
- Improved MinGW compatibility
- Fixed some issues with BufferingAudioReader
- Improved TextEditor repainting
- Added support for larger ASIO buffers
- Updated Android Oboe to 1.6.1
- Improved modal dismissing
- Improved assertion handling on macOS ARM
Version 6.0.8
- Fixed a macOS graphics invalidation region issue
- Improved the handling of modal dialog dismissal
- Fixed audio glitching in CoreAudio before microphone permission is granted
- Improved AUv3 resizing and initialisation
- Fixed some string to double conversions
- Improved iOS split view behaviour
- Added Display::safeAreaInserts
- Improved assertion behaviour on macOS ARM
- Multiple resizing and display scaling fixes
- Added more information to audioProcessorChanged callbacks
- Fixed some DSP convolution issues
- Added host detection on macOS ARM
Version 6.0.7
- Fixed a macOS drawing issue
- Updated the DemoRunner bundle ID
Version 6.0.6
- Moved to the new CoreMIDI API on supported platforms
- Added support for the "New Build System" in Xcode
- Made the audio format readers more robust
- Improved the HiResTimer implementation
- Fixed a VST3 program parameter issue
- Updated to Oboe 1.5 on Android
Version 6.0.5
- Added more support for styling PopupMenus
- Fixed some race conditions in the IPC and name named pipe classes
- Implemented multiple FileChooser improvements
- Added compatibility with the latest Android SDK
- Prevented CoreAudio glitches before accepting audio access permissions
- Made reading MIDI and audio files more robust
Version 6.0.4
- Improved the Projucer update mechanism
- Fixed an AUv3 parameter normalisation issue
- Fixed WASAPI exclusive mode sample rate selection bug
- Fixed a Linux build issue when omitting ALSA
Version 6.0.3
- Fixed version numbers in project files
Version 6.0.2
- Added support for macOS 11 and arm64
- Added Windows IAudioClient3 support for low latency audio drivers
- Added Windows and macOS precompiled header support in the Projucer
- Improved accessibility support in the macOS menu bar
- Fixed VST3 hosting for plug-ins requiring persistent DLL loads
- Updated macOS camera capture API
- Improved resave diffs in Projucer project files
- Fixed some Linux JACK issues
Version 6.0.1
- Fixed a bug in the Projucer GUI editor causing existing code to be overwritten
- Updated Android Oboe to 1.4.2
- Bumped default Android Studio gradle and plugin versions to the latest
- Fixed some Android Oboe and OpenSL issues
- Fixed some Doxygen parsing issues
- Fixed MIDI input/output bus enablement in VST3 plug-ins
- Improved Windows Clang compatibility
- Fixed GCC 4.8 and 5.0 compatibility
- Fixed some VST3 build errors and warnings on Linux
- Fixed dynamically loaded X11 library names on Linux
- Fixed Projucer CLion exporter generated CMakeLists.txt
- Fixed drag and drop for non-DPI aware plug-ins on Windows
Version 6.0.0
- Added support for building JUCE projects with CMake
- Revamped the DSP module
- Added VST3 support on Linux
- Added support for the latest webview components on macOS/iOS and Windows
- Removed the sign-in requirement, app reporting and analytics from the Projucer
- Added support for running headlessly on Linux
- Bundled Oboe source in JUCE and made it the default audio device on Android
- Various Oboe stability improvements
- Various Projucer UI improvements
- Added HWNDComponent for embedding native HWNDs on Windows
- Added support for all camera names on macOS
- Added support for building with Clang on Windows
- Modified MidiMessageCollector to preallocate storage
- Modified AudioProcessorGraph to allow extracting nodes
- Refactored the APVTS parameter attachment classes and added a new ParameterAttachment class
- Added IPP FFT implementation
- Added all example plugins as internal nodes in AudioPluginHost project
- Removed JuceHeader requirement from Projucer projects
- Added support for legacy CC output events
- Added MidiBuffer::Iterator class compatible with C++11 range-for
- Added RangedDirectoryIterator class compatible with C++11 range-for
- Provided range-for comaptibility for String class
- Windows and Linux hiDPI scaling improvements
- Various bug-fixes, improvements and documentation updates
Version 5.4.7
- Fixed a macOS focus bug causing Components to not receive mouse events
- Fixed a potential NullPointerException in the Android IAP code
- Fixed an entitlements file generation bug in the Projucer
- Send VST2 audioMasterUpdateDisplay opcode on the message thread to fix some hosts not updating
- Fixed some build errors and warnings when using Clang on Windows
- Changed the default architecture specified in Linux Makefiles generated by the Projucer
Version 5.4.6
- Fixed compatibility with macOS versions below 10.11
- Multiple thread safety improvements
- Added dynamic parameter and parameter group names
- Updated to the latest Android In-App Purchases API
- Improvements to the Windows message queue under high load
- Replaced WaitableEvent internals with std::condition_variable
- Fixed some macOS text alignment issues
Version 5.4.5
- Improved message queue performance on Linux
- Added missing lifecycle callbacks on Android Q
- Refactored the AudioBlock class
- Fixed APVTS parameter update recursion
- Updated Bela code to support latest release
- Fixed issues drawing italicised text on macOS
- Fixed broken back button behaviour on Android
- Added Bluetooth permissions settings needed for iOS 13.0+ to the Projucer
- Replaced select() calls with poll()
- Various bug-fixes, improvements and documentation updates
Version 5.4.4
- Improvements to floating point number printing
- Faster plug-in parameter indexing
- Added support for persisting attachements to MIDI devices
- Refactored Linux event loop handling
- Multiple C++ modernisation improvements to the API
- Added support for macOS 10.15 and iOS 13
- Added support for Visual Studio 2019
- Removed support for Visual Studio 2013
Version 5.4.3
- Added a Visual Studio 2019 exporter to the Projucer
- Added options to configure macOS Hardened Runtime in the Projucer
- Fixed a potential memory corruption when drawing on macOS/iOS
- Fixed file drag and drop for Windows 8
- Multiple DSP module enhancements
- Various bug-fixes, improvements and documentation updates
Version 5.4.2
- Restructured the low-level Android native code
- Added an ADSR envelope class
- AudioProcessorValueTreeState performance improvements
- Improved Xcode 10 support
- Improved VST3 hosting
- Windows hiDPI scaling enhancements
Version 5.4.1
- Fixed a VST2 compilation error in VS2013
- Fixed some live-build compilation errors in the Projucer
- Fixed a bug in the Oversampling class
- Made MPESynthesiserVoice::noteOnTime public
- Fixed some bugs in the Unity plug-in wrapper
- Fixed some VS2015 compiler errors
Version 5.4.0
- macOS Mojave and iOS 12 support
- Windows hiDPI support
- Unity native plug-in support
- Microsoft BLE MIDI support
- Plug-in parameter groups
- Support for production-ready Android OBOE
- Video playback support on Android and iOS
- AudioProcessorValueTreeState improvements
- Support for Android Studio 3.2
- Various bug-fixes, improvements and documentation updates
Version 5.3.2
- Removed the OSX 10.5 and 10.6 deployment target options from the Projucer and enabled more C++11 features across all platforms
- Replaced all usage of ScopedPointer with std::unique_ptr
- Added camera support for iOS and Android
- Fixed some issues using an UndoManager with an AudioProcessorValueTreeState
- Added MIDI input to IAA plug-ins
- Made multiple calls to MidiInput::openDevice share the same underlying win32 MIDI handle
- Added a config flag to juce_audio_processors for enabling LADSPA plugin hosting and enabled it in the AudioPluginHost
- Added a "plug-in can do" callback to the VSTCallbackHandler interface
- Fixed various undefined behavior in SIMDRegister
- Added the methods AudioBlock::copyTo/AudioBlock::copyFrom which facilitate copying to/from an AudioBuffer
- Added a lambda callback to OpenGLGraphicsContextCustomShader to allow custom set-up when the shader is activated
- Fixed a bug causing an unintentional menu item highlight disco party when using a popup menu in a plug-in's UI
- Marked as deprecated: String::empty, var::null, File::nonexistent, ValueTree::invalid and other problematic statically-initialised null values
Version 5.3.1
- Add Android and iOS support to AudioPluginHost
- Added support for Bela in the form of an AudioIODeviceType
- Add bypass support to both hosting and plug-in client code
- Added an isBoolean flag to APVTS parameters
- Re-worked plug-in wrappers to all use new parameter system via LegacyAudioParameter wrapper class
- Fixed an issue where opening the same midi device twice would cause a crash on Windows
- Deprecated MouseInputSource::hasMouseMovedSignificantlySincePressed() and replaced with more descriptive methods
- Added support for relative or special path symbolic links when compressing/uncompressing zip archives and creating/reading files
- Ensured that File::replaceInternal does not fail with ACL errors on Windows
- Merged-in some Ogg-Vorbis security fixes
- Fixed a bug which would prevent a SystemTrayIconComponent from creating a native popup window on macOS
- Various Android and iOS fixes
- Added a "PIP Creator" utility tool to the Projucer
- Added options for setting plugin categories and characteristics with MultiChoicePropertyComponent in the Projucer
- Fixed a Projucer bug where the OSX base SDK version was not being set
- Added a command-line option to use LF as linefeeds rather than CRLF in the Projucer cleanup tools
- Multiple documentation updates
Version 5.3.0
- Added support for Android OBOE (developer preview)
- Updated JUCE's MPE classes to comply with the new MMA-adopted specification
- Multiple documentation updates
- Restructured the examples and extras directories and updated all JUCE examples
- Multiple hosted parameter improvements
- Overhauled the GenericAudioProcessorEditor
- Added support for a subset of the Cockos VST extensions
- Added support for loading VST3 preset files
- Added boolean AudioProcessorParameters
- Added thread safe methods for getting and setting the AudioProcessorValueTreeState state
- Added customisable MacOS icons
Version 5.2.1
- Added native content sharing support for iOS and Android
- Added iOS and Android native file chooser support
- Implemented WebBrowserComponent on Android
- Added SystemStats::getDeviceManufacturer()
- Ensured that JUCE will always use the high-performance audio path on Android if the device supports it
- Added memory warning callbacks on iOS
- Refactored iOSAudioDevice to support multi-channel audio devices and improve the handling of sample rate changes from other apps
- Added SidePanel and BurgerMenu component classes
- Added PushNotifications support on OSX
- Added support for VST3 SDK 3.6.8
- Added support for loading VST3 preset files
- Added higher-order ambisonics support
- Added thread safe methods for getting and setting the AudioProcessorValueTreeState state
- Cleanup and refactoring work on the AudioProcessorGraph and the audio plugin host demo
- Changed the default language standard for new projects from C++11 to C++14 and set all JUCE projects to use C++14
- Made the ScopedPointer interface more compatible with std::unique_ptr
- Changed Windows projects to use dynamic runtime linking by default
- Added lambda callbacks to ListenerList, Slider, Button, Label, ComboBox and TextEditor
- Fixed the live-build engine on Windows
- Multiple DSP module fixes and features
- Multiple threading and undefined behaviour fixes and improvements
- Various graphics optimisations
- Multiple Projucer UI and UX improvements
- Various documentation tweaks and fixes
Version 5.2.0
- Added a CMake exporter to the Projucer
- JUCE analytics module
- Added support for push notifications on iOS and Android
- Added in-app purchase support for macOS
- Added a plugin binary copy step to the Visual Studio exporter
- Added an option to set the debug information format in the Visual Studio exporter
- Added a link-time optimisation option to all exporters
- Added support for adding asm files to Android projects
- Improved the reliability of the Projucer's live-build engine
- Added support for AUv2 Midi Effect plug-in hosting
- Added support for Atmos 7.0.2 and 7.1.2 Surround formats
- Added support for the OGG sub-format inside a WAV file
- Added support for querying the audio hardware on how many overruns/underruns occurred
- Implement Process::hide on mobile platforms
- Added support for multi-touch drag and drop
- Improved the performance of 3D rendering when multiple OpenGL contexts are used at the same time
- Tweaked the rate at which EdgeTable grows its internal storage, to improve performance rendering large and complex paths
Version 5.1.2
- Fixed multiple plugin-resizing bugs
- Added support for AUv3 MIDI and screen size negotiation
- Added support for Xcode 9 and iOS 11
- Added an In-App Purchases module
- Added backwards compatible constexpr support
- Standalone plug-in improvements
- Better .jucer file change monitoring in the Projucer
- Increased the speed of AU parameter lookup
- Improved the Android thread management when dealing with web requests
- Better denormal support
- Plug-in parameters can be explicitly marked as continuous or discrete
- Multiple documentation updates
Version 5.1.1
- Fixed Windows live build engine on Visual Studio 2017
- Fixed a compiler error in juce_MathFunctions.h in Visual Studio 2013
- Fixed a potential crash when using the ProcessorDuplicator
- Fixed a compiler-error in Filter::IIR
- Fixed an issue where the WavFileFormatWriter could not create files with discrete channels
- Fixed an issue where a window which is beneath a hidden window would not receive any clicks on Linux
- Altered the format of BREAKING-CHANGES.txt to display better on GitHub
- Projucer: Fixed an issue in exporter tilde expansion
- Fixed compiler errors when building the DSP module with a static version of FFTW
- Fixed an audio glitch when bypassing the convolution engine
- Fixed an issue where a JUCE VST2 would not correctly report that it supports resizing of its plugin editor
- Various documentation tweaks and fixes
Version 5.1.0
- Release of the JUCE DSP module
- Multichannel audio readers and writers
- Plugin editor Hi-DPI scaling support
- Major improvements to Projucer module search paths
- Added Projucer support for iOS app groups
- Added support for AVFoundation and deprecated the use of Quicktime
- Added a new real-time audio thread priority for Android
- Various Projucer UI fixes
- Various documentation fixes
- Various minor improvements and bug fixes
Version 5.0.2
- Improved project save speed in the Projucer
- Added option to save individual exporters in the Projucer
- Added the ability to create custom colour schemes for the Projucers code editor
- Minor fixes to JUCEs SVG parser
- Various bug fixes in the way JUCE handles Hi-DPI monitors
- Improved code browsing in Visual Studio Exports
- Improved the handling of audio device buffer size changes on iOS
- Fixed bug in the Win32 FileChooser dialog when selecting a nonexistent root drive
- Fixed a Projucer crash when saving projects with no targets
- Fixed a bug where Projucer generated Makefiles would not trigger a recompilation when header files had changed
- The standalone plugin target is now compatible with effect plug-ins
- Fixed an issue where it was not possible to use the live build engine on plugin projects
- Improved the way the Projucers live-build engine searches for platform headers on Windows
- Fixed an issue where the Projucer would complain about not having internet even if the user had a license
- Fixed a use-after-free in the AUv3 wrapper
- Fixed an issue where the channel layout would not be reported correctly in the AUv3 wrapper
- Fixed a potential memory overrun issue when hosting VST2 plugins with more than eight channels
- Fixed a problem with the Mac main menu bar showing menus in the wrong position
- Various Projucer UI fixes
- Various documentation fixes
- Various minor improvements and bug fixes
Version 5.0.1
- Fixed Windows live build engine on Visual Studio 2017
- Fixed memory-leak in Projucer live build engine
- Fixed an issue where you could not paste your redeem serial number with Cmd+V on macOS
- Fixed an issue where the Projucer would crash on linux due to missing symbols in WebKit
- Minor Projucer UI improvements
- Various minor improvements and bug fixes
Version 5.0.0
- New licensing model
- Projucer UI/UX overhaul
- New look and feel (version 4)
- New standalone plug-in format
- Added support for Visual Studio 2017
- Added support for VST3 SDK 3.6.7
- Added support for Apple Inter-App Audio on iOS
- Various Android stability and performance improvements
- Added support for non-experimental gradle plug-in versions >= 2.2 and Android Studio 2.3
- Added support for closed-source third-party modules
- Added support for Windows 10 Bluetooth LE MIDI devices
- Modernised JUCE codebase to use C++11/14 features
- Added support for Linux embedded platforms
- Added support for WebBrowserComponent on Linux
- Added support for IPv6
- Various minor improvements and bug fixes
- Various documentation improvements
Version 4.3.1
- Added support for iOS download tasks
- Added support for AAX plug-in meters
- Added support for dynamically disabling/enabling sidechains in ProTools
- Re-introduced support for VST3 plug-ins reporting which VST2 plug-in they can replace
- Added withRightX and withBottomY methods to Rectangle
- Added support for windows 10 on screen keyboard
- Added move semantics to AudioBuffer
- Added colour coding scheme to module icons in the Projucer to indicate which type of license a module uses
- Removed all deprecation warnings for macOS Sierra
- Fixed multiple touch, pen and mouse input related bugs on Windows
- Added submenu support to ComboBoxes and simplified the usage of ComboBoxes
- Various minor improvements and bug fixes
- Various documentation improvements
Version 4.3.0
- Added API and examples for ROLI Blocks
- Multiple Projucer live-build UI and diagnostics improvements
- JUCE now supports hosting multi-bus plug-ins
- BufferingAudioSource now supports pre-buffering (useful for offline processing)
- Added microphone permissions switch to Projucer for iOS targets
- Standalone wrappers now correctly save and restore midi settings
- Various performance improvements to BigInteger
- Fixed various FlexBox bugs
- Added a workaround for the broken “Open Recent…” menu on os x
- Various minor improvements and bug fixes
- Various documentation improvements
Version 4.2.4
- Pre-release of live build engine on Windows
- Added FlexBox layout engine
- Removed dependency on external Steinberg SDK when building and/or hosting VST2 plug-ins
- Added support for MIDI network sessions in the iOS simulator
- Added support for symmetric skew to Slider, NormalisableRange and SliderPropertyComponent
- Projucer now asks the user what to do when it detects that the .jucer file was modified outside of the Projucer
- Improved support for Windows 10 touch devices
- Added begin/end iterator methods for ValueTree, for handy range-based-for loops over its children
- Added support for recent mingw-w64 compilers
- Added useful proportional Rectangle utility methods
- Significantly improved the performance of BigInteger
- Added support for expiring licenses to juce_tracktion_marketplace
- Added support for retina mouse cursors on OS X
- Added a new low-quality mode for the CameraDevice
- Added pkg-config support for Linux
- Projucer will now wrap your AAX plug-in in the bundle format expected Pro Tools on Windows
- Multiple bug-fixes for AudioUnit parameter ids
- Fixed a bug where AlertWindows werent always on top
- Multiple fixes for web InputStreams
- Various improvements to the live build engine
- Various minor improvements and bug fixes
- Various documentation improvements
Version 4.2.3
- Various VST3 improvements: resizing VST3 windows, plug-in compatibility issues
- Use NSURLSession on newer OS X versions
- Add compatibility for VST 3 SDK update 3.6.6
- Miscellaneous fixes and improvements
Version 4.2.1
- New class CachedValue, for providing easy and efficient access to ValueTree properties
- Reduced audio plug-in binary sizes on OS X and added symbol-stripping option
- Miscellaneous fixes and improvements
Version 4.2
- Added support for AudioUnit v3 on OS X and iOS
- Simplified the JUCE module format. Removed the json module definition files, and made
it easier to manually add modules to projects. The format is fully described in the
document juce/modules/JUCE Module Format.txt
- iOS project support: added custom resource folders, custom xcassets, app capabilities,
and screen orientation settings.
- Deleted the Introjucer.. But don't panic! All of its functionality is now supplied by a
more open-source version of the Projucer. By refactoring the closed-source LLVM compilation
code into a DLL, we've been able to unify the Introjucer and Projucer into a single
open-source project. This will allow everyone to compile the Projucer's IDE themselves, and
having just one app instead of two will make things a lot less confusing!
Version 4.1
- Added multi-bus support for audio plug-in clients
- Added support for MIDI effect plug-ins (AU and AAX).
- Added new example: Network Graphics Demo
Version 4.0.3
- Added MPE (Multidimensional Polyphonic Expression) classes
- Added full support for generating and parsing Midi RPN/NRPN messages
- Made the LinearSmoothedValue class public
- Miscellaneous fixes and minor improvements
Version 4.0.2
- Miscellaneous fixes and house-keeping
Version 4.0.1
- Initial release of the Projucer!
- Full OSC support!
- Android Studio exporting from the Introjucer
- Android-M pro-audio low-latency i/o support
- Bluetooth MIDI device support on iOS and Android
- AudioSampleBuffer refactored into a templated class AudioBuffer, to allow
32 or 64 bit float support
- Audio plugin and hosting now supports 64-bit data
- Support for force-touch and pen pressure on iOS and Windows
- Added easy sound-file playing methods to AudioDeviceManager
- Many updates to Introjucer
- Many new tutorials and examples
Version 3.3.0
- New functions for Base64 conversion
- New command-line options in the introjucer for trimming whitespace and
replacing tabs in source files
Version 3.2.0
- Major OpenGL performance/stability improvements
- Performance improvements to FloatVectorOperations math functions
- New FloatVectorOperations: abs, min, max, addWithMultiply, clip
- Midi channel pressure support
- New example projects ComponentTutorialExample, SimpleFFTExample,
PluckedStringsDemo
- New class ValueTreeSynchroniser, for remote-syncing multiple
ValueTrees
- HTTPS/SSL support on Linux
- Added methods for degrees to radians conversions
- Added Neon instruction set support for Android targets
- JUCE ValueTree performance improvements
- Linux and Android multi-monitor HiDPI support
- Support the “display=none” attribute in SVG files
- Support for text elements in SVG files
- Added Whirlpool hash class to the cryptography module
- Various improvements for parameter automation in VST, VST-3,
AudioUnits and AAX
- Various improvements to JUCE Synthesiser
- Linux Code::Blocks project support
- Multicast support
- Add support to generate project version numbers from project git tags
- Various updates to example projects
- Stability improvements to re-order and resize code of plug-in windows
- Support for external third-party native libraries on Android
- Introjucers auto-update now displays release notes
- Various Introjucer usability improvements
- Support for in-memory fonts on Android
- New FFT class
- WASAPI exclusive mode support
- More C++11 feature support macros
- Performance improvements to XML parsing
- Add compatibility for AAX SDK 2.2.0
- Added parameters to the ValueTree::Listener::valueTreeChildRemoved()
and valueTreeChildOrderChanged() methods to include more info about
exactly what changed
- Over 400 minor changes, bug-fixes, documentation improvements, etc.

37
deps/juce/LICENSE.md vendored
View File

@ -1,37 +0,0 @@
# The JUCE Library
**BY DOWNLOADING, INSTALLING OR USING ANY PART OF THE JUCE LIBRARY, YOU AGREE
TO THE [JUCE 7 END-USER LICENSE AGREEMENT](https://www.juce.com/juce-7-licence)
AND THE [JUCE PRIVACY POLICY](https://www.juce.com/juce-privacy-policy), WHICH
ARE BINDING AGREEMENTS BETWEEN YOU AND RAW MATERIAL SOFTWARE LIMITED. IF YOU DO
NOT AGREE TO THE TERMS, DO NOT USE THE JUCE LIBRARY.**
JUCE has tier-leveled license terms, with different terms for each available
license: JUCE Personal (for developers or startup businesses with revenue under
the 50K USD Revenue Limit; free), JUCE Indie (for small businesses with under
500K USD Revenue Limit; $40/month), JUCE Pro (no Revenue Limit; $130/month),
and JUCE Educational (no Revenue Limit; free for bona fide educational
institutions). All licenses allow you to commercially release applications as
long as you do not exceed the Revenue Limit and pay the applicable Fees. Once
your business hits the Revenue Limit for your JUCE license tier, to continue
distributing your Applications you will either have to upgrade your JUCE
license, or instead release your Applications under the
[GNU General Public License v.3](https://www.gnu.org/licenses/gpl-3.0.en.html),
which means, amongst other things, that you must make the source code of your
Applications available.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE, ARE DISCLAIMED.
The juce_audio_basics, juce_audio_devices, juce_core and juce_events modules
are permissively licensed under the terms of the [ISC
license](http://www.isc.org/downloads/software-support-policy/isc-license).
For more information, visit the website:
[www.juce.com](https://www.juce.com)
FULL JUCE TERMS:
- [JUCE 7 END-USER LICENSE AGREEMENT](https://www.juce.com/juce-7-licence)
- [JUCE PRIVACY POLICY](https://www.juce.com/juce-privacy-policy)

118
deps/juce/README.md vendored
View File

@ -1,118 +0,0 @@
![alt text](https://assets.juce.com/juce/JUCE_banner_github.png "JUCE")
JUCE is an open-source cross-platform C++ application framework for creating high quality
desktop and mobile applications, including VST, VST3, AU, AUv3, AAX and LV2 audio plug-ins
and plug-in hosts. JUCE can be easily integrated with existing projects via CMake, or can
be used as a project generation tool via the [Projucer](https://juce.com/discover/projucer),
which supports exporting projects for Xcode (macOS and iOS), Visual Studio, Android Studio,
Code::Blocks and Linux Makefiles as well as containing a source code editor.
## Getting Started
The JUCE repository contains a [master](https://github.com/juce-framework/JUCE/tree/master)
and [develop](https://github.com/juce-framework/JUCE/tree/develop) branch. The develop branch
contains the latest bugfixes and features and is periodically merged into the master
branch in stable [tagged releases](https://github.com/juce-framework/JUCE/releases)
(the latest release containing pre-built binaries can be also downloaded from the
[JUCE website](https://juce.com/get-juce)).
JUCE projects can be managed with either the Projucer (JUCE's own project-configuration
tool) or with CMake.
### The Projucer
The repository doesn't contain a pre-built Projucer so you will need to build it
for your platform - Xcode, Visual Studio and Linux Makefile projects are located in
[extras/Projucer/Builds](/extras/Projucer/Builds)
(the minimum system requirements are listed in the __System Requirements__ section below).
The Projucer can then be used to create new JUCE projects, view tutorials and run examples.
It is also possible to include the JUCE modules source code in an existing project directly,
or build them into a static or dynamic library which can be linked into a project.
For further help getting started, please refer to the JUCE
[documentation](https://juce.com/learn/documentation) and
[tutorials](https://juce.com/learn/tutorials).
### CMake
Version 3.15 or higher is required. To use CMake, you will need to install it,
either from your system package manager or from the [official download
page](https://cmake.org/download/). For comprehensive documentation on JUCE's
CMake API, see the [JUCE CMake documentation](/docs/CMake%20API.md). For
examples which may be useful as starting points for new CMake projects, see the
[CMake examples directory](/examples/CMake).
#### Building Examples
To use CMake to build the examples and extras bundled with JUCE, simply clone
JUCE and then run the following commands, replacing "DemoRunner" with the name
of the target you wish to build.
cd /path/to/JUCE
cmake . -B cmake-build -DJUCE_BUILD_EXAMPLES=ON -DJUCE_BUILD_EXTRAS=ON
cmake --build cmake-build --target DemoRunner
## Minimum System Requirements
#### Building JUCE Projects
- __macOS/iOS__: Xcode 10.1 (macOS 10.13.6)
- __Windows__: Windows 8.1 and Visual Studio 2015 Update 3 64-bit
- __Linux__: g++ 5.0 or Clang 3.4 (for a full list of dependencies, see
[here](/docs/Linux%20Dependencies.md)).
- __Android__: Android Studio on Windows, macOS or Linux
#### Deployment Targets
- __macOS__: macOS 10.7
- __Windows__: Windows Vista
- __Linux__: Mainstream Linux distributions
- __iOS__: iOS 9.0
- __Android__: Jelly Bean (API 16)
## Contributing
Please see our [contribution guidelines](.github/contributing.md).
## Licensing
The core JUCE modules (juce_audio_basics, juce_audio_devices, juce_core and juce_events)
are permissively licensed under the terms of the
[ISC license](http://www.isc.org/downloads/software-support-policy/isc-license/).
Other modules are covered by a
[GPL](https://www.gnu.org/licenses/gpl-3.0.en.html)/Commercial license.
There are multiple commercial licensing tiers for JUCE, with different terms for each:
- JUCE Personal (developers or startup businesses with revenue under 50K USD) - free
- JUCE Indie (small businesses with revenue under 500K USD) - $40/month or $800 perpetual
- JUCE Pro (no revenue limit) - $130/month or $2600 perpetual
- JUCE Educational (no revenue limit) - free for bona fide educational institutes
For full terms see [LICENSE.md](LICENSE.md).
The JUCE framework contains the following dependencies:
- [Oboe](modules/juce_audio_devices/native/oboe/) ([Apache 2.0](modules/juce_audio_devices/native/oboe/LICENSE))
- [FLAC](modules/juce_audio_formats/codecs/flac/) ([BSD](modules/juce_audio_formats/codecs/flac/Flac%20Licence.txt))
- [Ogg Vorbis](modules/juce_audio_formats/codecs/oggvorbis/) ([BSD](modules/juce_audio_formats/codecs/oggvorbis/Ogg%20Vorbis%20Licence.txt))
- [CoreAudioUtilityClasses](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/) ([Apple](modules/juce_audio_plugin_client/AU/CoreAudioUtilityClasses/AUBase.cpp))
- [AUResources.r](modules/juce_audio_plugin_client/AUResources.r) ([Apple](modules/juce_audio_plugin_client/AUResources.r))
- [LV2](modules/juce_audio_processors/format_types/LV2_SDK/) ([ISC](modules/juce_audio_processors/format_types/LV2_SDK/lv2/COPYING))
- [pslextensions](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h) ([Public domain](modules/juce_audio_processors/format_types/pslextensions/ipslcontextinfo.h))
- [VST3](modules/juce_audio_processors/format_types/VST3_SDK/) ([Proprietary Steinberg VST3/GPLv3](modules/juce_audio_processors/format_types/VST3_SDK/LICENSE.txt))
- [zlib](modules/juce_core/zip/zlib/) ([zlib](modules/juce_core/zip/zlib/README))
- [Box2D](modules/juce_box2d/box2d/) ([zlib](modules/juce_box2d/box2d/Box2D.h))
- [jpeglib](modules/juce_graphics/image_formats/jpglib/) ([Independent JPEG Group License](modules/juce_graphics/image_formats/jpglib/README))
- [pnglib](modules/juce_graphics/image_formats/pnglib/) ([zlib](modules/juce_graphics/image_formats/pnglib/LICENSE))
- [GLEW](modules/juce_opengl/opengl/juce_gl.h) ([BSD](modules/juce_opengl/opengl/juce_gl.h)), including [Mesa](modules/juce_opengl/opengl/juce_gl.h) ([MIT](modules/juce_opengl/opengl/juce_gl.h)) and [Khronos](modules/juce_opengl/opengl/juce_gl.h) ([MIT](modules/juce_opengl/opengl/juce_gl.h))
The JUCE examples are licensed under the terms of the
[ISC license](http://www.isc.org/downloads/software-support-policy/isc-license/).
Dependencies in the examples:
- [reaper-sdk](examples/Plugins/extern/) ([zlib](examples/Plugins/extern/LICENSE.md))
Dependencies in the bundled applications:
- [Projucer icons](extras/Projucer/Source/Utility/UI/jucer_Icons.cpp) ([MIT](extras/Projucer/Source/Utility/UI/jucer_Icons.cpp))
Dependencies in the build system:
- [Android Gradle](examples/DemoRunner/Builds/Android/gradle/wrapper/LICENSE-for-gradlewrapper.txt) ([Apache 2.0](examples/DemoRunner/Builds/Android/gradle/wrapper/LICENSE-for-gradlewrapper.txt))

76
deps/juce/docs/ARA.md vendored
View File

@ -1,76 +0,0 @@
# ARA plugin support
JUCE supports the development of ARA enabled hosts and plugins. Since the ARA SDK is not included
in JUCE there are some steps you need to take to enable all ARA related functionality.
## External dependencies
- ARA SDK 2.1.0
You can download the ARA SDK from Celemony's Github. The command below will recursively clone the
right version into the `ARA_SDK` directory
git clone --recursive --branch releases/2.1.0 https://github.com/Celemony/ARA_SDK
## Enabling ARA features in JUCE
Once you have downloaded the ARA SDK you need to configure JUCE to use it.
### The Projucer
Add the path to the Global Paths settings.
### CMake
Use the `juce_set_ara_sdk_path` function in your CMakeLists file.
Alternatively, if you are building the examples and extras with CMake from the JUCE repo directory
you can also specify `-DJUCE_GLOBAL_ARA_SDK_PATH=/your/path/to/ARA_SDK` parameter to CMake to
enable ARA.
## Building the AudioPluginHost with ARA
The AudioPluginHost has simple ARA hosting features, but you need to modify its build configuration
to enable them.
### The Projucer
After opening `AudioPluginHost.jucer` go to *Modules**juce_audio_processors* and enable the
*JUCE_PLUGINHOST_ARA* setting.
### CMake
Set `JUCE_PLUGINHOST_ARA=1` inside `AudioPluginHost/CMakeLists.txt`.
### Loading ARA plugins
ARA capable plugins will now have two entries in the Create plugin menu, and the one saying (ARA)
will activate additional ARA features. If you right click on the plugin in the graph, you can use
the “Show ARA host control” item to assign an audio file that the plugin can read through the ARA
interfaces.
## Adding ARA features to existing plugins
### The Projucer
Check the Enable ARA option in the Plugin Formats settings. ARA is an extension to VST3 and AU
plugins, hence you need to have at least one of those options enabled too for valid build targets.
### CMake
Add the property `IS_ARA_EFFECT TRUE` to your `juce_add_plugin` call.
### Modifying the plugin code
In addition to the `createPluginFilter()` function that is needed for all audio plugins, you will
now need to provide an implementation to the `createARAFactory()` function as well. You can do this
by inheriting from `juce::ARADocumentControllerSpecialisation` and using its helper function. The
class documentation should make this clear by also providing an example. You can also find an
example in the ARAPluginDemo.
## Learning about ARA
ARA provides an extensive API that allows you to exchange information with the host in completely
new ways. To understand the basics and to build up your knowledge its best to read the official
ARA documentation, which has approachable introductory sections. You can find the documentation in
the SDK directory at `ARA_SDK/ARA_Library/html_docs/index.html`.

View File

@ -1,48 +0,0 @@
# JUCE Accessibility
## What is supported?
Currently JUCE supports VoiceOver on macOS and Narrator on Windows. The JUCE
accessibility API exposes the following to these clients:
- Title, description, and help text for UI elements
- Programmatic access to UI elements and text
- Interaction with UI elements
- Full UI keyboard navigation
- Posting notifications to listening clients
## Customising Behaviour
By default any visible and enabled `Component` is accessible to screen reader
clients and exposes some basic information such as title, description, help
text and its position in the hierarchy of UI elements.
The `setTitle()`, `setDescription()` and `setHelpText()` methods can be used
to customise the text that will be read out by accessibility clients when
interacting with UI elements and the `setExplicitFocusOrder()`,
`setFocusContainerType()` and `createFocusTraverser()` methods can be used to
control the parent/child relationships and the order of navigation between UI
elements.
## Custom Components
For further customisation of accessibility behaviours the `AccessibilityHandler`
class provides a unified API to the underlying native accessibility libraries.
This class wraps a component with a given role specified by the
`AccessibilityRole` enum and takes a list of optional actions and interfaces to
provide programmatic access and control over the UI element. Its state is used
to convey further information to accessibility clients via the
`getCurrentState()` method.
To implement the desired behaviours for a custom component, subclass
`AccessibilityHandler` and return an instance of this from the
`Component::createAccessibilityHandler()` method.
## Further Reading
- [NSAccessibility protocol](https://developer.apple.com/documentation/appkit/nsaccessibility?language=objc)
- [UI Automation for Win32 applications](https://docs.microsoft.com/en-us/windows/win32/winauto/entry-uiauto-win32)
- A talk giving an overview of this feature from ADC 2020 can be found on
YouTube at https://youtu.be/BqrEv4ApH3U

View File

@ -1,795 +0,0 @@
# The JUCE CMake API
## System Requirements
- All project types require CMake 3.15 or higher.
- Android targets are not currently supported.
- WebView2 on Windows via JUCE_USE_WIN_WEBVIEW2 flag in juce_gui_extra is not currently supported.
Most system package managers have packages for CMake, but we recommend using the most recent release
from https://cmake.org/download. You should always use a CMake that's newer than your build
toolchain, so that CMake can identify your build tools and understand how to invoke them.
In addition to CMake you'll need a build toolchain for your platform, such as Xcode or MSVC.
## Getting Started
### Using `add_subdirectory`
The simplest way to include JUCE in your project is to add JUCE as a
subdirectory of your project, and to include the line `add_subdirectory(JUCE)`
in your project CMakeLists.txt. This will make the JUCE targets and helper
functions available for use by your custom targets.
### Using `find_package`
To install JUCE globally on your system, you'll need to tell CMake where to
place the installed files.
# Go to JUCE directory
cd /path/to/clone/JUCE
# Configure build with library components only
cmake -B cmake-build-install -DCMAKE_INSTALL_PREFIX=/path/to/JUCE/install
# Run the installation
cmake --build cmake-build-install --target install
In your project which consumes JUCE, make sure the project CMakeLists.txt contains the line
`find_package(JUCE CONFIG REQUIRED)`. This will make the JUCE modules and CMake helper functions
available for use in the rest of your build. Then, run the build like so:
# Go to project directory
cd /path/to/my/project
# Configure build, passing the JUCE install path you used earlier
cmake -B cmake-build -DCMAKE_PREFIX_PATH=/path/to/JUCE/install
# Build the project
cmake --build cmake-build
### Example projects
In the JUCE/examples/CMake directory, you'll find example projects for a GUI app, a console app,
and an audio plugin. You can simply copy one of these subdirectories out of the JUCE repo, add JUCE
as a submodule, and uncomment the call to `add_subdirectory` where indicated in the CMakeLists.txt.
Alternatively, if you've installed JUCE using a package manager or the CMake install target, you can
uncomment the call to `find_package`.
Once your project is set up, you can generate a build tree for it in the normal way. To get started,
you might invoke CMake like this, from the new directory you created.
cmake -Bbuild (-GgeneratorName) (-DJUCE_BUILD_EXTRAS=ON) (-DJUCE_BUILD_EXAMPLES=ON)
This will create a build tree in a directory named 'build', using the CMakeLists in the current
working directory, using the default generator (makefiles on mac/linux, and the most recent Visual
Studio on Windows). You can choose a specific generator to use with the `-G` flag (call `cmake -G`
to see a full list of generators on your platform). If you included JUCE as a subdirectory, you can
enable the Extras and Examples targets by including the last two arguments (they're off by default).
There's quite a lot of example projects, and generating project files might take a bit longer when
these options are on, so you probably won't want to include them most of the time.
Then, to build the project:
cmake --build build (--target targetNameFromCMakeLists) (--config Release/Debug/...)
This tells cmake to build the target named `targetNameFromCMakeLists`, in the specified
configuration, using the appropriate tool. Of course, if you generated makefiles or ninja files, you
could call `make` or `ninja` in the build directory. If you generated an IDE project, like an Xcode
or Visual Studio project, then you could open the generated project in your IDE.
### Building for iOS
To build for iOS, you'll need CMake 3.14 or higher. Using the Xcode generator is highly recommended,
as other generators may not automatically find the correct SDK for the iPhone simulator, and may
fail to run certain parts of the build, such as compiling icons and processing the app's plist. By
default, CMake will build for the same system that originally configured the project, so to enable
cross-compilation for iOS, a few extra flags must be passed to the initial CMake invocation:
cmake -Bbuild-ios -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=9.3
Here we create a build tree in the directory named 'build-ios', using the Xcode generator. The
`-DCMAKE_SYSTEM_NAME=iOS` option tells CMake to enable cross-compiling for iOS. The
`-DCMAKE_OSX_DEPLOYMENT_TARGET=9.3` option sets the minimum deployment target (it applies to iOS
despite the 'OSX' in the variable name!).
Once the project has generated, we can open it as normal in Xcode (look for the project file in the
build directory). Alternatively, to build from the command-line, we could run this command:
cmake --build build-ios --target <targetName> -- -sdk iphonesimulator
Here, we're building the target named `<targetName>` from the build tree in the directory
`build-ios`. All the arguments after `--` are ignored by CMake, and are passed through to the
underlying build tool. In this case, the build tool will be `xcodebuild` because we used the Xcode
generator above. We tell xcodebuild that we're building the app for the iOS simulator, which doesn't
require special code signing.
If we wanted to build for a real device, we would need to pass some extra signing details to the
initial CMake configuration command:
cmake -Bbuild-ios -GXcode -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=9.3 \
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY="iPhone Developer"
-DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=<10 character id>
The `CODE_SIGN_IDENTITY` is the kind of certificate you want to use (iPhone Developer is appropriate
for development) and `DEVELOPMENT_TEAM` is the 10-character ID that can be found by opening the
Keychain Access app, finding your development certificate, and checking its 'Organizational Unit'
info field.
When building the target, you may also need to tell Xcode that it can automatically update
provisioning profiles, which is achieved by passing the `-allowProvisioningUpdates` flag:
cmake --build build-ios --target <targetName> -- -allowProvisioningUpdates
#### Archiving for iOS
CMake's out-of-the-box archiving behaviour doesn't always work as expected, especially for targets
that depend on custom static libraries. Xcode may generate these libraries into a 'DerivedData'
directory, but then omit this directory from the library search paths later in the build.
If the "Product -> Archive" action isn't working due to missing staticlibs, try setting the
`ARCHIVE_OUTPUT_DIRECTORY` property explicitly:
set_target_properties(my_static_lib_target PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "./")
Note that the static library produced by `juce_add_binary_data` automatically sets this property.
### Building universal binaries for macOS
Building universal binaries that will run on both arm64 and x86_64 can be achieved by
configuring the CMake project with `"-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64"`.
### Building with Clang on Windows
Clang-cl (Clang with MSVC-like command-line) should work by default. If you are generating a Visual
Studio project, and have installed the LLVM package which is distributed with Visual Studio, then
you can configure a Clang-cl build by passing "-T ClangCL" on your configuration commandline.
If you wish to use Clang with GNU-like command-line instead, you can pass
`-DCMAKE_CXX_COMPILER=clang++` and `-DCMAKE_C_COMPILER=clang` on your configuration commandline.
clang++ and clang must be on your `PATH` for this to work. Only more recent versions of CMake
support Clang's GNU-like command-line on Windows. CMake 3.12 is not supported, CMake 3.15 has
support, CMake 3.20 or higher is recommended. Note that CMake doesn't seem to automatically link a
runtime library when building in this configuration, but this can be remedied by setting the
`MSVC_RUNTIME_LIBRARY` property. See the [official
documentation](https://cmake.org/cmake/help/v3.15/prop_tgt/MSVC_RUNTIME_LIBRARY.html) of this
property for usage recommendations.
### A note about compile definitions
Module options and plugin options that would previously have been set in the Projucer can be set on
a target-by-target basis in CMake, via `target_compile_definitions`. To find the options exposed by
a particular module, check its module header for sections with the following structure:
/** Config: NAME_OF_KEY
Docs go here...
*/
#ifndef NAME_OF_KEY
#define NAME_OF_KEY ...
#endif
To override the default config option, use the following CMake code, replacing `<value>` as
appropriate:
target_compile_definitions(my_target PUBLIC NAME_OF_KEY=<value>)
The `JucePlugin_PreferredChannelConfig` preprocessor definition for plugins is difficult to specify
in a portable way due to its use of curly braces, which may be misinterpreted in Linux/Mac builds
using the Ninja/Makefile generators. It is recommended to avoid this option altogether, and to use
the newer buses API to specify the desired plugin inputs and outputs.
## API Reference
### Options
These flags can be enabled or disabled to change the behaviour of parts of the JUCE build.
These options would normally be configured by either:
- Supplying an option in the form `-DNAME_OF_OPTION=ON/OFF` to the initial CMake configuration call,
or
- Calling `set(NAME_OF_OPTION ON/OFF)` before including JUCE in your project via `add_subdirectory`
or `find_package`.
#### `JUCE_BUILD_EXTRAS`
This controls whether targets are added for the projects in the 'extras' folder, such as the
Projucer and AudioPluginHost. This is off by default, because you probably won't need these targets
if you've included JUCE in your own project.
#### `JUCE_BUILD_EXAMPLES`
This controls whether targets are added for the projects in the 'examples' folder, such as the
DemoRunner and PIPs. This is off by default, because you probably won't need these targets if you've
included JUCE in your own project.
#### `JUCE_ENABLE_MODULE_SOURCE_GROUPS`
This option will make module source files browsable in IDE projects. It has no effect in non-IDE
projects. This option is off by default, as it will increase the size of generated IDE projects and
might slow down configuration a bit. If you enable this, you should probably also add
`set_property(GLOBAL PROPERTY USE_FOLDERS YES)` to your top level CMakeLists as this is required for
source grouping to work.
Source groupings are a little sensitive to the project layout. As such, you should always ensure
that the call to `juce_add_module` which adds a specific module happens *before* calling
`juce_add_*` to add any dependent targets.
The modules will be placed in a group named "JUCE Modules" within the group for each target,
alongside the "Source Files" and "Header Files" groups.
Note: Source groups will only work when all JUCE-dependent targets are created using the
`juce_add_*` functions. The standard `add_executable` and `add_library` commands are likely to
result in broken builds when source groups are enabled!
#### `JUCE_COPY_PLUGIN_AFTER_BUILD`
Controls whether plugin targets should be installed to the system after building. Note that the
plugin folders may be protected, so the build may require elevated permissions in order for the
installation to work correctly, or you may need to adjust the permissions of the destination
folders.
### Functions
#### `juce_add_<target>`
juce_add_gui_app(<target> [KEY value]...)
juce_add_console_app(<target> [KEY value]...)
juce_add_plugin(<target> [KEY value]...)
`juce_add_gui_app` and `juce_add_console_app` add an executable target with name `<target>`.
`juce_add_plugin` adds a 'shared code' static library target with name `<target>`, along with extra
targets for each of the specified plugin formats. Each of these functions also takes a number of
optional arguments in the form of a `KEY` followed by one or more `value`s which can be used to set
additional attributes of the target. If these optional arguments aren't specified, their values will
fall back to sensible defaults.
Each of these arguments adds a property to the resulting target in the form `JUCE_paramName`, where
`paramName` is one of the parameter keys below. For example, after a call to
`juce_add_gui_app(my_target PRODUCT_NAME "Target")`, the target `my_target` will have a property
named `JUCE_PRODUCT_NAME` with the value `"Target"`. After creating a target with one of these
commands, properties beginning with `JUCE_` can be _queried_, but changing their values might not
have any effect (or might even break things in unexpected ways!), so always pass JUCE target
attributes directly to these creation functions, rather than adding them later.
`PRODUCT_NAME`
- The name of the output built by this target, similar to CMake's `OUTPUT_NAME` property. If not
specified, this will default to the target name.
`VERSION`
- A version number string in the format "major.minor.bugfix". If not specified, the `VERSION` of
the project containing the target will be used instead. On Apple platforms, this is the
user-facing version string. This option corresponds to the `CFBundleShortVersionString` field in
the target's plist.
`BUILD_VERSION`
- A version number string in the format "major.minor.bugfix". If not specified, this will match
the `VERSION` of the target. On Apple platforms, this is the private version string used to
distinguish between App Store builds. This option corresponds to the `CFBundleVersion` field in
the target's plist.
`BUNDLE_ID`
- An identifier string in the form "com.yourcompany.productname" which should uniquely identify
this target. Mainly used for macOS builds. If not specified, a default will be generated using
the target's `COMPANY_NAME` and `PRODUCT_NAME`.
`MICROPHONE_PERMISSION_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an app's Info.plist.
`MICROPHONE_PERMISSION_TEXT`
- The text your app will display when it requests microphone permissions.
`CAMERA_PERMISSION_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an app's Info.plist.
`CAMERA_PERMISSION_TEXT`
- The text your app will display when it requests camera permissions.
`BLUETOOTH_PERMISSION_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an app's Info.plist.
`BLUETOOTH_PERMISSION_TEXT`
- The text your app will display when it requests bluetooth permissions.
`SEND_APPLE_EVENTS_PERMISSION_ENABLED`
- May be either TRUE or FALSE. Enable this to allow your app to send Apple events.
`SEND_APPLE_EVENTS_PERMISSION_TEXT`
- The text your app will display when it requests permission to send Apple events.
`FILE_SHARING_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`DOCUMENT_BROWSER_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`STATUS_BAR_HIDDEN`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`REQUIRES_FULL_SCREEN`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`BACKGROUND_AUDIO_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`BACKGROUND_BLE_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist.
`APP_GROUPS_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's entitlements.
`APP_GROUP_IDS`
- The app groups to which your iOS app belongs. These will be added to your app's entitlements.
`ICLOUD_PERMISSIONS_ENABLED`
- May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's entitlements.
`IPHONE_SCREEN_ORIENTATIONS`
- May be one or more of `UIInterfaceOrientationUnknown`, `UIInterfaceOrientationPortrait`,
`UIInterfaceOrientationPortraitUpsideDown`, `UIInterfaceOrientationLandscapeLeft`, or
`UIInterfaceOrientationLandscapeRight`. Adds appropriate entries to an iOS app's plist.
`IPAD_SCREEN_ORIENTATIONS`
- May be one or more of `UIInterfaceOrientationUnknown`, `UIInterfaceOrientationPortrait`,
`UIInterfaceOrientationPortraitUpsideDown`, `UIInterfaceOrientationLandscapeLeft`, or
`UIInterfaceOrientationLandscapeRight`. Adds appropriate entries to an iOS app's plist.
`LAUNCH_STORYBOARD_FILE`
- A custom launch storyboard file to use on iOS. If not supplied, a default storyboard will be
used. If this is specified, then this will take precedence over a LaunchImage inside a custom
xcassets directory.
`CUSTOM_XCASSETS_FOLDER`
- A path to an xcassets directory, containing icons and/or launch images for this target. If this
is specified, the ICON_BIG and ICON_SMALL arguments will not have an effect on iOS. LaunchImages
have been deprecated from iOS 13 onward, but if your xcassets folder contains a LaunchImage and
a custom storyboard hasn't been specified, then it will be used.
`TARGETED_DEVICE_FAMILY`
- Specifies the device families on which the product must be capable of running. Allowed values
are "1", "2", and "1,2"; these correspond to "iPhone/iPod touch", "iPad", and "iPhone/iPod and
iPad" respectively. This will default to "1,2", meaning that the target will target iPhone,
iPod, and iPad.
`ICON_BIG`, `ICON_SMALL`
- Paths to image files that will be used to generate app icons. If only one of these parameters
is specified, then that image will be used for all icon resolutions. If both arguments are
specified, then the appropriate image will be picked for each icon resolution.
`COMPANY_COPYRIGHT`
- Copyright text which will be added to the app/plugin's Info.plist. The value of this argument
will be inherited from the `JUCE_COMPANY_COPYRIGHT` property, so if you want to use the same
`COMPANY_COPYRIGHT` for several targets in a build tree, you can call
`set_directory_properties(PROPERTIES JUCE_COMPANY_COPYRIGHT ...)` after including JUCE but
before adding the targets, and then omit the `COMPANY_COPYRIGHT` argument when creating the
individual targets.
`COMPANY_NAME`
- The name of this target's author. Will be added to the app/plugin's Info.plist, and may be used
to generate part of the `BUNDLE_ID` if no ID was given explicitly. The value of this argument
will be inherited from the `JUCE_COMPANY_NAME` property, so if you want to use the same
`COMPANY_NAME` for several targets in a build tree, you can call
`set_directory_properties(PROPERTIES JUCE_COMPANY_NAME ...)` after including JUCE but before
adding the targets, and then omit the `COMPANY_NAME` argument when creating the individual
targets.
`COMPANY_WEBSITE`
- The address of a website related to this target in some way. The value of this argument will be
inherited from the `JUCE_COMPANY_WEBSITE` property, so if you want to use the same
`COMPANY_WEBSITE` for several targets in a build tree, you can call
`set_directory_properties(PROPERTIES JUCE_COMPANY_WEBSITE ...)` after including JUCE but before
adding the targets, and then omit the `COMPANY_WEBSITE` argument when creating the individual
targets.
`COMPANY_EMAIL`
- An email address for this target's author. The value of this argument will be inherited from the
`JUCE_COMPANY_EMAIL` property, so if you want to use the same `COMPANY_EMAIL` for several
targets in a build tree, you can call `set_directory_properties(PROPERTIES JUCE_COMPANY_EMAIL
...)` after including JUCE but before adding the targets, and then omit the `COMPANY_EMAIL`
argument when creating the individual targets.
`DOCUMENT_EXTENSIONS`
- File extensions that should be associated with this target. For example, the Projucer passes
the string `jucer` because it wants to open `.jucer` files. If your target has several different
document types, you can pass them as multiple arguments, e.g. `DOCUMENT_EXTENSIONS wav mp3 aif`.
`NEEDS_CURL`
- On Linux, JUCE may or may not need to link to Curl depending on the compile definitions that are
set on a JUCE target. By default, we don't link Curl because you might not need it, but if you
get linker or include errors that reference Curl, just set this argument to `TRUE`.
`NEEDS_WEB_BROWSER`
- On Linux, JUCE may or may not need to link to Webkit depending on the compile definitions that
are set on a JUCE target. By default, we don't link Webkit because you might not need it, but
if you get linker or include errors that reference Webkit, just set this argument to `TRUE`.
`NEEDS_STORE_KIT`
- On macOS, JUCE may or may not need to link to StoreKit depending on the compile definitions that
are set on a JUCE target. By default, we don't link StoreKit because you might not need it, but
if you get linker or include errors that reference StoreKit, just set this argument to `TRUE`.
`PUSH_NOTIFICATIONS_ENABLED`
- Sets app entitlements to allow push notifications. False by default.
`NETWORK_MULTICAST_ENABLED`
- Sets app entitlements to allow IP multicast or broadcast on macOS/iOS. False by default.
`HARDENED_RUNTIME_ENABLED`
- Enables macOS' hardened runtime for this target. Required for notarisation. False by default.
`HARDENED_RUNTIME_OPTIONS`
- A set of space-separated entitlement keys that will be added to this target's entitlements
plist if `HARDENED_RUNTIME_ENABLED` is `TRUE`. Each key should be in the form
`com.apple.security.*` where `*` is a specific entitlement.
`APP_SANDBOX_ENABLED`
- Enables macOS' app sandbox for this target. False by default.
`APP_SANDBOX_INHERIT`
- Allows child processes to inherit the static entitlements of their parent process. If this
is set to `TRUE`, no other app sandbox entitlements will be set on this target.
`APP_SANDBOX_OPTIONS`
- A set of space-separated entitlement keys that will be added to this target's entitlements
plist if `APP_SANDBOX_ENABLED` is `TRUE`. Each key should be in the form `com.apple.security.*`
where `*` is a specific entitlement.
`APP_SANDBOX_FILE_ACCESS_HOME_RO`
- A set of space-separated paths that will be added to this target's entitlements plist for
accessing read-only paths relative to the home directory if `APP_SANDBOX_ENABLED` is `TRUE`.
`APP_SANDBOX_FILE_ACCESS_HOME_RW`
- A set of space-separated paths that will be added to this target's entitlements plist for
accessing read/write paths relative to the home directory if `APP_SANDBOX_ENABLED` is `TRUE`.
`APP_SANDBOX_FILE_ACCESS_ABS_RO`
- A set of space-separated paths that will be added to this target's entitlements plist for
accessing read-only absolute paths if `APP_SANDBOX_ENABLED` is `TRUE`.
`APP_SANDBOX_FILE_ACCESS_ABS_RW`
- A set of space-separated paths that will be added to this target's entitlements plist for
accessing read/write absolute paths if `APP_SANDBOX_ENABLED` is `TRUE`.
`PLIST_TO_MERGE`
- A string to insert into an app/plugin's Info.plist.
`FORMATS`
- For plugin targets, specifies the plugin targets to build. Should be provided as a
space-separated list. Valid values are `Standalone Unity VST3 AU AUv3 AAX VST`. `AU` and `AUv3`
plugins will only be enabled when building on macOS. It is an error to pass `AAX` or `VST`
without first calling `juce_set_aax_sdk_path` or `juce_set_vst2_sdk_path` respectively.
`PLUGIN_NAME`
- The name of the plugin. In a DAW environment, this is the name that will be displayed to the
user when they go to load a plugin. This name may differ from the name of the physical plugin
file (to set the name of the plugin file, use the `PRODUCT_NAME` option). If not specified,
the `PLUGIN_NAME` will default to match the `PRODUCT_NAME`.
`PLUGIN_MANUFACTURER_CODE`
- A four-character unique ID for your company. For AU compatibility, this must contain at least
one upper-case letter. GarageBand 10.3 requires the first letter to be upper-case, and the
remaining letters to be lower-case.
`PLUGIN_CODE`
- A four-character unique ID for your plugin. For AU compatibility, this must contain exactly one
upper-case letter. GarageBand 10.3 requires the first letter to be upper-case, and the remaining
letters to be lower-case.
`DESCRIPTION`
- A short description of your plugin.
`IS_SYNTH`
- Whether the plugin is a synth. Will be used to set sensible plugin category values if they
are not provided explicitly.
`NEEDS_MIDI_INPUT`
- Whether the plugin should provide a midi input.
`NEEDS_MIDI_OUTPUT`
- Whether the plugin should provide a midi output.
`IS_MIDI_EFFECT`
- Whether the plugin is a MIDI effect (some hosts provide a special channel-strip location for
MIDI effect plugins).
`EDITOR_WANTS_KEYBOARD_FOCUS`
- Whether the plugin requires keyboard focus, or should defer all keyboard handling to the host.
`DISABLE_AAX_BYPASS`
- Whether the AAX bypass function should be disabled.
`DISABLE_AAX_MULTI_MONO`
- Whether the AAX multi mono bus layout should be disabled.
`AAX_IDENTIFIER`
- The bundle ID for the AAX plugin target. Matches the `BUNDLE_ID` by default.
`VST_NUM_MIDI_INS`
- For VST2 and VST3 plugins that accept midi, this allows you to configure the number of inputs.
`VST_NUM_MIDI_OUTS`
- For VST2 and VST3 plugins that produce midi, this allows you to configure the number of outputs.
`VST2_CATEGORY`
- Should be one of: `kPlugCategUnknown`, `kPlugCategEffect`, `kPlugCategSynth`,
`kPlugCategAnalysis`, `kPlugCategMatering`, `kPlugCategSpacializer`, `kPlugCategRoomFx`,
`kPlugSurroundFx`, `kPlugCategRestoration`, `kPlugCategOfflineProcess`, `kPlugCategShell`,
`kPlugCategGenerator`.
`VST3_CATEGORIES`
- Should be one or more, separated by spaces, of the following: `Fx`, `Instrument`, `Analyzer`,
`Delay`, `Distortion`, `Drum`, `Dynamics`, `EQ`, `External`, `Filter`, `Generator`, `Mastering`,
`Modulation`, `Mono`, `Network`, `NoOfflineProcess`, `OnlyOfflineProcess`, `OnlyRT`,
`Pitch Shift`, `Restoration`, `Reverb`, `Sampler`, `Spatial`, `Stereo`, `Surround`, `Synth`,
`Tools`, `Up-Downmix`
`AU_MAIN_TYPE`
- Should be one of: `kAudioUnitType_Effect`, `kAudioUnitType_FormatConverter`,
`kAudioUnitType_Generator`, `kAudioUnitType_MIDIProcessor`, `kAudioUnitType_Mixer`,
`kAudioUnitType_MusicDevice`, `kAudioUnitType_MusicEffect`, `kAudioUnitType_OfflineEffect`,
`kAudioUnitType_Output`, `kAudioUnitType_Panner`
`AU_EXPORT_PREFIX`
- A prefix for the names of entry-point functions that your component exposes. Typically this
will be a version of your plugin's name that can be used as part of a C++ token. Defaults
to your plugin's name with the suffix 'AU'.
`AU_SANDBOX_SAFE`
- May be either TRUE or FALSE. Adds the appropriate entries to an AU plugin's Info.plist.
`SUPPRESS_AU_PLIST_RESOURCE_USAGE`
- May be either TRUE or FALSE. Defaults to FALSE. Set this to TRUE to disable the `resourceUsage`
key in the target's plist. This is useful for AU plugins that must access resources which cannot
be declared in the resourceUsage block, such as UNIX domain sockets. In particular,
PACE-protected AU plugins may require this option to be enabled in order for the plugin to load
in GarageBand.
`AAX_CATEGORY`
- Should be one or more of: `AAX_ePlugInCategory_None`, `AAX_ePlugInCategory_EQ`,
`AAX_ePlugInCategory_Dynamics`, `AAX_ePlugInCategory_PitchShift`, `AAX_ePlugInCategory_Reverb`,
`AAX_ePlugInCategory_Delay`, `AAX_ePlugInCategory_Modulation`, `AAX_ePlugInCategory_Harmonic`,
`AAX_ePlugInCategory_NoiseReduction`, `AAX_ePlugInCategory_Dither`,
`AAX_ePlugInCategory_SoundField`, `AAX_ePlugInCategory_HWGenerators`,
`AAX_ePlugInCategory_SWGenerators`, `AAX_ePlugInCategory_WrappedPlugin`,
`AAX_EPlugInCategory_Effect`
`PLUGINHOST_AU`
- May be either TRUE or FALSE (defaults to FALSE). If TRUE, will add the preprocessor definition
`JUCE_PLUGINHOST_AU=1` to the new target, and will link the macOS frameworks necessary for
hosting plugins. Using this parameter should be preferred over using
`target_compile_definitions` to manually set the `JUCE_PLUGINHOST_AU` preprocessor definition.
`USE_LEGACY_COMPATIBILITY_PLUGIN_CODE`
- May be either TRUE or FALSE (defaults to FALSE). If TRUE, will override the value of the
preprocessor definition "JucePlugin_ManufacturerCode" with the hex equivalent of "proj". This
option exists to maintain compatibility with a previous, buggy version of JUCE's CMake support
which mishandled the manufacturer code property. Most projects should leave this option set to
its default value.
`COPY_PLUGIN_AFTER_BUILD`
- Whether or not to install the plugin to the current system after building. False by default.
If you want all of the plugins in a subdirectory to be installed automatically after building,
you can set the property `JUCE_COPY_PLUGIN_AFTER_BUILD` on the directory before adding the
plugins, rather than setting this argument on each individual target. Note that on Windows,
the default install locations may not be writable by normal user accounts.
`VST_COPY_DIR`
- The location to which VST2 (legacy) plugins will be copied after building if
`COPY_PLUGIN_AFTER_BUILD` is set on this target. If you want to install all of the VST2 plugins
in a subdirectory to a non-default location, you can set the `JUCE_VST_COPY_DIR` property on
the directory before adding the plugin targets, rather than setting this argument on each
individual target.
`VST3_COPY_DIR`
- The location to which VST3 plugins will be copied after building if `COPY_PLUGIN_AFTER_BUILD`
is set on this target. If you want to install all of the VST3 plugins in a subdirectory to a
non-default location, you can set the `JUCE_VST3_COPY_DIR` property on the directory before
adding the plugin targets, rather than setting this argument on each individual target.
`AAX_COPY_DIR`
- The location to which AAX plugins will be copied after building if `COPY_PLUGIN_AFTER_BUILD`
is set on this target. If you want to install all of the AAX plugins in a subdirectory to a
non-default location, you can set the `JUCE_AAX_COPY_DIR` property on the directory before
adding the plugin targets, rather than setting this argument on each individual target.
`AU_COPY_DIR`
- The location to which AU plugins will be copied after building if `COPY_PLUGIN_AFTER_BUILD`
is set on this target. If you want to install all of the AU plugins in a subdirectory to a
non-default location, you can set the `JUCE_AU_COPY_DIR` property on the directory before
adding the plugin targets, rather than setting this argument on each individual target.
`UNITY_COPY_DIR`
- The location to which Unity plugins will be copied after building if `COPY_PLUGIN_AFTER_BUILD`
is set on this target. If you want to install all of the Unity plugins in a subdirectory to a
non-default location, you can set the `JUCE_UNITY_COPY_DIR` property on the directory before
adding the plugin targets, rather than setting this argument on each individual target.
Unlike the other `COPY_DIR` arguments, this argument does not have a default value so be sure
to set it if you have enabled `COPY_PLUGIN_AFTER_BUILD` and the `Unity` format.
`IS_ARA_EFFECT`
- May be either TRUE or FALSE (defaults to FALSE). If TRUE it enables additional codepaths in the
VST3 and AU plugin wrappers allowing compatible hosts to load the plugin with additional ARA
functionality. It will also add the preprocessor definition `JucePlugin_Enable_ARA=1`, which can
be used in preprocessor conditions inside the plugin code. You should not add this definition
using `target_compile_definitions` manually.
`ARA_FACTORY_ID`
- A globally unique and versioned identifier string. If not provided a sensible default will be
generated using the `BUNDLE_ID` and `VERSION` values. The version must be updated if e.g. the
plugin's (compatible) document archive ID(s) or its analysis or playback transformation
capabilities change.
`ARA_DOCUMENT_ARCHIVE_ID`
- Identifier string for document archives created by the document controller. This ID must be
globally unique and is shared only amongst document controllers that create the same archives and
produce the same render results based upon the same input data. This means that the ID must be
updated if the archive format changes in any way that is no longer downwards compatible. If not
provided a version independent default will be created that is only appropriate as long as the
format remains unchanged.
`ARA_ANALYSIS_TYPES`
- Defaults to having no analyzable types. Should be one or more of the following values if the
document controller has the corresponding analysis capability: `kARAContentTypeNotes`,
`kARAContentTypeTempoEntries`, `kARAContentTypeBarSignatures`, `kARAContentTypeStaticTuning `,
`kARAContentTypeKeySignatures`, `kARAContentTypeSheetChords`
`ARA_TRANSFORMATION_FLAGS`
- Defaults to `kARAPlaybackTransformationNoChanges`. If the document controller has the ability to
provide the corresponding change it should be one or more of:
`kARAPlaybackTransformationTimestretch`, `kARAPlaybackTransformationTimestretchReflectingTempo`,
`kARAPlaybackTransformationContentBasedFadeAtTail`,
`kARAPlaybackTransformationContentBasedFadeAtHead`
#### `juce_add_binary_data`
juce_add_binary_data(<name>
[HEADER_NAME ...]
[NAMESPACE ...]
SOURCES ...)
Create a static library that embeds the contents of the files passed as arguments to this function.
Adds a library target called `<name>` which can be linked into other targets using
`target_link_libraries`.
The `HEADER_NAME` argument is optional. If provided, the generated header will be given the
requested name, otherwise the generated header will be named "BinaryData.h". In completely new
projects, you should provide a unique name here, so that projects containing more than one binary
data target are able to include the binary data headers without ambiguity.
The `NAMESPACE` argument is also optional. If not provided, the generated files will use the default
namespace `BinaryData`. Each of the files located at the paths following `SOURCES` will be encoded
and embedded in the resulting static library. This library can be linked as normal using
`target_link_libraries(<otherTarget> PRIVATE <name>)`, and the header can be included using
`#include <BinaryData.h>`.
#### `juce_add_bundle_resources_directory`
juce_add_bundle_resources_directory(<target> <folder>)
Copy the entire directory at the location `<folder>` into an Apple bundle's resource directory, i.e.
the `Resources` directory for a macOS bundle, and the top-level directory of an iOS bundle.
#### `juce_generate_juce_header`
juce_generate_juce_header(<target>)
Introspects the JUCE modules that have been linked to `<target>` and generates a `JuceHeader.h`
which contains `#include` statements for each of the module headers. This header also contains an
optional `using namespace juce` statement, and an optional `ProjectInfo` block, each of which can be
disabled by setting the compile definitions `DONT_SET_USING_JUCE_NAMESPACE` and
`JUCE_DONT_DECLARE_PROJECTINFO` respectively. The resulting header can be included with `#include
<JuceHeader.h>`. In plain CMake projects which don't require Projucer compatibility, the use of
JuceHeader.h is optional. Instead, module headers can be included directly in source files that
require them.
#### `juce_enable_copy_plugin_step`
juce_enable_copy_plugin_step(<target>)
As an alternative to the JUCE_COPY_PLUGIN_AFTER_BUILD property, you may call this function to
manually enable post-build copy on a plugin. The argument to this function should be a target
previously created with `juce_add_plugin`.
JUCE_COPY_PLUGIN_AFTER_BUILD will cause plugins to be installed immediately after building. This is
not always appropriate, if extra build steps (such as signing or modifying the plugin bundle) must
be executed before the install. In such cases, you should leave JUCE_COPY_PLUGIN_AFTER_BUILD
disabled, use `add_custom_command(TARGET POST_BUILD)` to add your own post-build steps, and then
finally call `juce_enable_copy_plugin_step`.
If your custom build steps need to use the location of the plugin artefact, you can extract this
by querying the property `JUCE_PLUGIN_ARTEFACT_FILE` on a plugin target (*not* the shared code
target!).
#### `juce_set_<kind>_sdk_path`
juce_set_aax_sdk_path(<absolute path>)
juce_set_vst2_sdk_path(<absolute path>)
juce_set_vst3_sdk_path(<absolute path>)
juce_set_ara_sdk_path(<absolute path>)
Call these functions from your CMakeLists to set up your local AAX, VST2, VST3 and ARA SDKs. These
functions should be called *before* adding any targets that may depend on the AAX/VST2/VST3/ARA SDKs
(plugin hosts, AAX/VST2/VST3/ARA plugins etc.).
#### `juce_add_module`
juce_add_module(<path to module>)
juce_add_modules(<names of module>...)
`juce_add_module` adds a library target for the JUCE module located at the provided path. `<path>`
must be the path to a module directory (e.g. /Users/me/JUCE/modules/juce_core). This will add an
interface library with a name matching the directory name of the module. The resulting library can
be linked to other targets as normal, using `target_link_libraries`.
Due to the way that `INTERFACE` libraries work in CMake, linking to a module added in this way
*must* be done using `PRIVATE` visibility. Using `PUBLIC` will cause the module sources to be added
both to the target's `SOURCES` and `INTERFACE_SOURCES`, which may result in many copies of the
module being built into a single target, which would cause build failures in the best case and
silent ODR violations in the worst case. Scary stuff!
This command has a few optional arguments: `INSTALL_PATH` is a path, relative to the install prefix,
to which the module sources will be copied during installation of the module. ALIAS_NAMESPACE will
add an alias for the module target(s) with the provided namespace. For example, the following
invocation will add a module target named `my_module`, along with an alias named
`company::my_module`. ``` juce_add_module(my_module ALIAS_NAMESPACE company)` ```
`juce_add_modules` is a convenience function that can be used to add multiple JUCE modules at once.
This version accepts many module paths, rather than just one. For an example of usage, see the
CMakeLists in the `modules` directory.
#### `juce_add_pip`
juce_add_pip(<header>)
This function parses the PIP metadata block in the provided header, and adds appropriate build
targets for a console app, GUI app, or audio plugin. For audio plugin targets, it builds as many
plugin formats as possible. To build AAX or VST2 targets, call `juce_set_aax_sdk_path` and/or
`juce_set_vst2_sdk_path` *before* calling `juce_add_pip`.
This is mainly provided to build the built-in example projects in the JUCE repo, and for building
quick proof-of-concept demo apps with minimal set-up. For any use-case more complex than a
proof-of-concept, you should prefer the `juce_add_gui_app`, `juce_add_plugin`, or
`juce_add_console_app` functions, which provide more fine-grained control over the properties of
your target.
#### `juce_disable_default_flags`
juce_disable_default_flags()
This function sets the `CMAKE_<LANG>_FLAGS_<MODE>` to empty in the current directory and below,
allowing alternative optimisation/debug flags to be supplied without conflicting with the
CMake-supplied defaults.
### Targets
#### `juce::juce_recommended_warning_flags`
target_link_libraries(myTarget PUBLIC juce::juce_recommended_warning_flags)
This is a target which can be linked to other targets using `target_link_libraries`, in order to
enable the recommended JUCE warnings when building them.
This target just sets compiler and linker flags, and doesn't have any associated libraries or
include directories. When building plugins, it's probably desirable to link this to the shared code
target with `PUBLIC` visibility, so that all the plugin wrappers inherit the same compile/link
flags.
#### `juce::juce_recommended_config_flags`
target_link_libraries(myTarget PUBLIC juce::juce_recommended_config_flags)
This is a target which can be linked to other targets using `target_link_libraries`, in order to
enable the recommended JUCE optimisation and debug flags.
This target just sets compiler and linker flags, and doesn't have any associated libraries or
include directories. When building plugins, it's probably desirable to link this to the shared code
target with `PUBLIC` visibility, so that all the plugin wrappers inherit the same compile/link
flags.
#### `juce::juce_recommended_lto_flags`
target_link_libraries(myTarget PUBLIC juce::juce_recommended_lto_flags)
This is a target which can be linked to other targets using `target_link_libraries`, in order to
enable the recommended JUCE link time optimisation settings.
This target just sets compiler and linker flags, and doesn't have any associated libraries or
include directories. When building plugins, it's probably desirable to link this to the shared code
target with `PUBLIC` visibility, so that all the plugin wrappers inherit the same compile/link
flags.

View File

@ -1,244 +0,0 @@
# The JUCE Module Format
A JUCE module is a collection of header and source files which can be added to a project
to provide a set of classes and libraries or related functionality.
Their structure is designed to make it as simple as possible for modules to be added to
user projects on many platforms, either via automated tools, or by manual inclusion.
Each module may have dependencies on other modules, but should be otherwise self-contained.
## File structure
Each module lives inside a folder whose name is the same as the name of the module. The
JUCE convention for naming modules is lower-case with underscores, e.g.
juce_core
juce_events
juce_graphics
But any name that is a valid C++ identifier is OK.
Inside the root of this folder, there must be a set of public header and source files which
the user's' project will include. The module may have as many other internal source files as
it needs, but these must all be inside sub-folders!
### Master header file
In this root folder there must be ONE master header file, which includes all the necessary
header files for the module. This header must have the same name as the module, with
a .h/.hpp/.hxx suffix. E.g.
juce_core/juce_core.h
IMPORTANT! All code within a module that includes other files from within its own subfolders
must do so using RELATIVE paths!
A module must be entirely relocatable on disk, and it must not rely on the user's project
having any kind of include path set up correctly for it to work. Even if the user has no
include paths whatsoever and includes the module's master header via an absolute path,
it must still correctly find all of its internally included sub-files.
This master header file must also contain a comment with a BEGIN_JUCE_MODULE_DECLARATION
block which defines the module's requirements - the syntax for this is described later on..
### Module CPP files
A module consists of a single header file and zero or more .cpp files. Fewer is better!
Ideally, a module could be header-only module, so that a project can use it by simply
including the master header file.
For various reasons it's usually necessary or preferable to have a simpler header and
some .cpp files that the user's project should compile as stand-alone compile units.
In this case you should ideally provide just a single cpp file in the module's root
folder, and this should internally include all your other cpps from their sub-folders,
so that only a single cpp needs to be added to the user's project in order to completely
compile the module.
In some cases (e.g. if your module internally relies on 3rd-party code which can't be
easily combined into a single compile-unit) then you may have more than one source file
here, but avoid this if possible, as it will add a burden for users who are manually
adding these files to their projects.
The names of these source files must begin with the name of the module, but they can have
a number or other suffix if there is more than one.
In order to specify that a source file should only be compiled on a specific platform,
then the filename can be suffixed with one of the following strings:
_OSX
_Windows
_Linux
_Android
_iOS
e.g.
juce_mymodule/juce_mymodule_1.cpp <- compiled on all platforms
juce_mymodule/juce_mymodule_2.cpp <- compiled on all platforms
juce_mymodule/juce_mymodule_OSX.cpp <- compiled only on OSX
juce_mymodule/juce_mymodule_Windows.cpp <- compiled only on Windows
Often this isn't necessary, as in most cases you can easily add checks inside the files
to do different things depending on the platform, but this may be handy just to avoid
clutter in user projects where files aren't needed.
To simplify the use of obj-C++ there's also a special-case rule: If the folder contains
both a .mm and a .cpp file whose names are otherwise identical, then on OSX/iOS the .mm
will be used and the cpp ignored. (And vice-versa for other platforms, of course).
### Precompiled libraries
Precompiled libraries can be included in a module by placing them in a libs/ subdirectory.
The following directories are automatically added to the library search paths, and libraries
placed in these directories can be linked with projects via the OSXLibs, iOSLibs,
windowsLibs, linuxLibs and mingwLibs keywords in the module declaration (see the following
section).
- OS X
- libs/MacOSX - to support multiple architectures, you may place libraries built as universal
binaries at this location. For backwards compatibility, the Projucer will also include the
directories libs/MacOSX/{arch}, where {arch} is the architecture you are targeting in Xcode
("x86_64" or "i386", for example). When building with CMake, only libraries built as universal
binaries are supported and the arch subfolders are ignored.
- Visual Studio
- libs/VisualStudio{year}/{arch}/{run-time}, where {year} is the four digit year of the Visual Studio
release, arch is the target architecture in Visual Studio ("x64" or "Win32", for example), and
{runtime} is the type of the run-time library indicated by the corresponding compiler flag
("MD", "MDd", "MT", "MTd").
- Linux
- libs/Linux/{arch}, where {arch} is the architecture you are targeting with the compiler. Some
common examples of {arch} are "x86_64", "i386" and "armv6".
- MinGW
- libs/MinGW/{arch}, where {arch} can take the same values as Linux.
- iOS
- libs/iOS - to support multiple architectures, you may place libraries built as universal
binaries at this location. For backwards compatibility, the Projucer will also include the
directories libs/iOS/{arch}, where {arch} is the architecture you are targeting in Xcode
("arm64" or "x86_64", for example). When building with CMake, only libraries built as universal
binaries are supported and the arch subfolders are ignored.
- Android
- libs/Android/{arch}, where {arch} is the architecture provided by the Android Studio variable
"${ANDROID_ABI}" ("x86", "armeabi-v7a", "mips", for example).
## The BEGIN_JUCE_MODULE_DECLARATION block
This block of text needs to go inside the module's main header file. It should be commented-out
and perhaps inside an `#if 0` block too, but the Introjucer will just scan the whole file for the
string BEGIN_JUCE_MODULE_DECLARATION, and doesn't care about its context in terms of C++ syntax.
The block needs a corresponding END_JUCE_MODULE_DECLARATION to finish the block.
These should both be on a line of their own.
Inside the block, the parser will expect to find a list of value definitions, one-per-line, with
the very simple syntax
value_name: value
The value_name must be one of the items listed below, and is case-sensitive. Whitespace on the
line is ignored. Some values are compulsory and must be supplied, but others are optional.
The order in which they're declared doesn't matter.
Possible values:
- ID
- (Compulsory) This ID must match the name of the file and folder, e.g. juce_core.
The main reason for also including it here is as a sanity-check
- vendor
- (Compulsory) A unique ID for the vendor, e.g. "juce". This should be short
and shouldn't contain any spaces
- version
- (Compulsory) A version number for the module
- name
- (Compulsory) A short description of the module
- description
- (Compulsory) A longer description (but still only one line of text, please!)
- dependencies
- (Optional) A list (space or comma-separated) of other modules that are required by
this one. The Introjucer can use this to auto-resolve dependencies.
- website
- (Optional) A URL linking to useful info about the module]
- license
- (Optional) A description of the type of software license that applies
- minimumCppStandard
- (Optional) A number indicating the minimum C++ language standard that is required for this module.
This must be just the standard number with no prefix e.g. 14 for C++14
- searchpaths
- (Optional) A space-separated list of internal include paths, relative to the module's
parent folder, which need to be added to a project's header search path
- OSXFrameworks
- (Optional) A list (space or comma-separated) of OSX frameworks that are needed by this module
- WeakOSXFrameworks
- (Optional) A list (space or comma-separated) of weak linked OSX frameworks that are needed
by this module
- iOSFrameworks
- (Optional) A list (space or comma-separated) of iOS frameworks that are needed by this module
- WeakiOSFrameworks
- (Optional) A list (space or comma-separated) of weak linked iOS frameworks that are needed
by this module
- linuxPackages
- (Optional) A list (space or comma-separated) pkg-config packages that should be used to pass
compiler (CFLAGS) and linker (LDFLAGS) flags
- linuxLibs
- (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a
linux build (these are passed to the linker via the -l flag)
- mingwLibs
- (Optional) A list (space or comma-separated) of static libs that should be linked in a
win32 mingw build (these are passed to the linker via the -l flag)
- OSXLibs
- (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an
OS X build (these are passed to the linker via the -l flag)
- iOSLibs
- (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in an
iOS build (these are passed to the linker via the -l flag)
- windowsLibs
- (Optional) A list (space or comma-separated) of static or dynamic libs that should be linked in a
Visual Studio build (without the .lib suffixes)
Here's an example block:
BEGIN_JUCE_MODULE_DECLARATION
ID: juce_audio_devices
vendor: juce
version: 4.1.0
name: JUCE audio and MIDI I/O device classes
description: Classes to play and record from audio and MIDI I/O devices
website: http://www.juce.com/juce
license: GPL/Commercial
dependencies: juce_audio_basics, juce_audio_formats, juce_events
OSXFrameworks: CoreAudio CoreMIDI DiscRecording
iOSFrameworks: CoreAudio CoreMIDI AudioToolbox AVFoundation
linuxLibs: asound
mingwLibs: winmm
END_JUCE_MODULE_DECLARATION

View File

@ -1,62 +0,0 @@
# JUCE Dependencies on Linux
Below is a list of the current dependencies required to build JUCE projects on
Ubuntu, separated by module. Where the dependency is optional, the preprocessor
flag used to disable it is noted.
This has been tested on Ubuntu 16.04 LTS (Xenial Xerus), 18.04 LTS (Bionic
Beaver), and 20.04 LTS (Focal Fossa). Packages may differ in name or not be
available on other distributions.
## Compiler
A C++ compiler is required. JUCE has been tested thoroughly with Clang and GCC:
sudo apt update
sudo apt install clang
or
sudo apt update
sudo apt install g++
## Packages
#### juce_audio_devices
- libasound2-dev
- libjack-jackd2-dev (unless `JUCE_JACK=0`)
#### juce_audio_processors
- ladspa-sdk (unless `JUCE_PLUGINHOST_LADSPA=0`)
#### juce_core
- libcurl4-openssl-dev (unless `JUCE_USE_CURL=0`)
#### juce_graphics
- libfreetype6-dev (unless `JUCE_USE_FREETYPE=0`)
#### juce_gui_basics
- libx11-dev
- libxcomposite-dev
- libxcursor-dev (unless `JUCE_USE_XCURSOR=0`)
- libxext-dev
- libxinerama-dev (unless `JUCE_USE_XINERAMA=0`)
- libxrandr-dev (unless `JUCE_USE_XRANDR=0`)
- libxrender-dev (unless `JUCE_USE_XRENDER=0`)
#### juce_gui_extra
- libwebkit2gtk-4.0-dev (unless `JUCE_WEB_BROWSER=0`)
#### juce_opengl
- libglu1-mesa-dev
- mesa-common-dev
The full command is as follows:
sudo apt update
sudo apt install libasound2-dev libjack-jackd2-dev \
ladspa-sdk \
libcurl4-openssl-dev \
libfreetype6-dev \
libx11-dev libxcomposite-dev libxcursor-dev libxcursor-dev libxext-dev libxinerama-dev libxrandr-dev libxrender-dev \
libwebkit2gtk-4.0-dev \
libglu1-mesa-dev mesa-common-dev

View File

@ -1,34 +0,0 @@
# JUCE Documentation
This directory contains files documenting the JUCE Module Format, and the JUCE
CMake API.
The JUCE modules themselves can be found in the `modules` subdirectory of the
JUCE repository.
CMake example projects are located in the `examples/CMake` directory.
The JUCE API itself is documented inline, but HTML docs can be generated from
the source code using the `doxygen` tool. These HTML docs can be [found
online](https://juce.com/learn/documentation), or you can generate a local copy
which can be used without an internet connection. For instructions on generating
offline docs, see below.
# Generating Offline HTML Documentation
## Dependencies
- doxygen
- python
- make
- graphviz (to generate inheritance diagrams)
Make sure that all the dependencies can be found on your PATH.
## Building
- cd into the `doxygen` directory on the command line
- run `make`
Doxygen will create a new subdirectory "doc". Open doc/index.html in your browser
to access the generated HTML documentation.

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
SHELL := /bin/bash
SOURCE_FILES := $(shell find ../../modules -type f -name "juce_*.h" -or -name "juce_*.dox" | sed 's/ /\\ /g')
.PHONY: clean
doc/index.html: build/juce_modules.dox Doxyfile
doxygen
build/juce_modules.dox: process_source_files.py $(SOURCE_FILES)
python $< ../../modules build
clean:
rm -rf build doc

View File

@ -1,2 +0,0 @@
python process_source_files.py ..\..\modules build
doxygen

View File

@ -1,180 +0,0 @@
#!/usr/bin/env python
import os
import shutil
import re
import argparse
def get_curly_brace_scope_end(string, start_pos):
"""Given a string and a starting position of an opening brace, find the
position of the closing brace.
"""
start_pos += 1
string_end = len(string)
bracket_counter = 1
while start_pos < string_end:
if string[start_pos] == "{":
bracket_counter += 1
elif string[start_pos] == "}":
bracket_counter -= 1
if bracket_counter == 0:
return start_pos
start_pos += 1
return -1
def remove_juce_namespaces(source):
"""Return a string of source code with any juce namespaces removed.
"""
namespace_regex = re.compile(r"\s+namespace\s+juce\s*{")
match = namespace_regex.search(source)
while (match is not None):
source = source[:match.start()] + source[match.end():]
end = get_curly_brace_scope_end(source, match.start() - 1)
if end != -1:
source = source[:end] + source[end + 1:]
match = namespace_regex.search(source)
continue
else:
raise ValueError("failed to find the end of the "
+ match.group(1) + " namespace")
return source
def add_doxygen_group(path, group_name):
"""Add a Doxygen group to the file at 'path'.
The addition of juce namespacing code to all of the source files breaks
backwards compatibility by changing the doc URLs, so we need to remove
the namespaces.
"""
filename = os.path.basename(path)
if re.match(r"^juce_.*\.(h|dox)", filename):
with open(path, "r") as f:
content = f.read()
with open(path, "w") as f:
f.write("\r\n/** @weakgroup " + group_name + "\r\n * @{\r\n */\r\n")
f.write(remove_juce_namespaces(content))
f.write("\r\n/** @}*/\r\n")
###############################################################################
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("source_dir",
help="the directory to search for source files")
parser.add_argument("dest_dir",
help="the directory in which to place processed files")
parser.add_argument("--subdirs",
help="if specified, only include these comma separated"
"subdirectories")
args = parser.parse_args()
try:
shutil.rmtree(args.dest_dir)
except OSError:
pass
except FileNotFoundError:
pass
# Get the list of JUCE modules to include.
if args.subdirs:
juce_modules = args.subdirs.split(",")
else:
juce_modules = []
for item in os.listdir(args.source_dir):
if os.path.isdir(os.path.join(args.source_dir, item)):
juce_modules.append(item)
# Copy the JUCE modules to the temporary directory, and process the source
# files.
module_definitions = []
for module_name in juce_modules:
# Copy the required modules.
original_module_dir = os.path.join(args.source_dir, module_name)
module_path = os.path.join(args.dest_dir, module_name)
shutil.copytree(original_module_dir, module_path)
# Parse the module header to get module information.
module_header = os.path.join(module_path, module_name + ".h")
with open(module_header, "r") as f:
content = f.read()
block_info_result = re.match(r".*BEGIN_JUCE_MODULE_DECLARATION"
"(.*)"
"END_JUCE_MODULE_DECLARATION.*",
content,
re.DOTALL)
detail_lines = []
for line in block_info_result.group(1).split("\n"):
stripped_line = line.strip()
if stripped_line:
result = re.match(r"^.*?description:\s*(.*)$", stripped_line)
if result:
short_description = result.group(1)
else:
detail_lines.append(stripped_line)
# The module header causes problems for Doxygen, so delete it.
os.remove(module_header)
# Create a Doxygen group definition for the module.
module_definiton = []
module_definiton.append("/** @defgroup {n} {n}".format(n=module_name))
module_definiton.append(" {d}".format(d=short_description))
module_definiton.append("")
for line in detail_lines:
module_definiton.append(" - {l}".format(l=line))
module_definiton.append("")
module_definiton.append(" @{")
module_definiton.append("*/")
# Create a list of the directories in the module that we can use as
# subgroups and create the Doxygen group hierarchy string.
dir_contents = os.listdir(module_path)
# Ignore "native" folders as these are excluded by doxygen.
try:
dir_contents.remove("native")
except ValueError:
pass
subdirs = []
for item in dir_contents:
if (os.path.isdir(os.path.join(module_path, item))):
subdirs.append(item)
module_groups = {}
for subdir in subdirs:
subgroup_name = "{n}-{s}".format(n=module_name, s=subdir)
module_groups[subgroup_name] = os.path.join(module_path, subdir)
module_definiton.append("")
module_definiton.append(
"/** @defgroup {tag} {n} */".format(tag=subgroup_name, n=subdir)
)
module_definiton.append("")
module_definiton.append("/** @} */")
module_definitions.append("\r\n".join(module_definiton))
# Put the top level files into the main group.
for filename in (set(dir_contents) - set(subdirs)):
add_doxygen_group(os.path.join(module_path, filename), module_name)
# Put subdirectory files into their respective groups.
for group_name in module_groups:
for dirpath, dirnames, filenames in os.walk(module_groups[group_name]):
for filename in filenames:
filepath = os.path.join(dirpath, filename)
add_doxygen_group(filepath, group_name)
# Create an extra header file containing the module hierarchy.
with open(os.path.join(args.dest_dir, "juce_modules.dox"), "w") as f:
f.write("\r\n\r\n".join(module_definitions))
# Copy markdown docs
for name in ["JUCE Module Format.md", "CMake API.md"]:
shutil.copyfile(os.path.join(args.source_dir, "..", "docs", name),
os.path.join(args.dest_dir, name))

View File

@ -1,72 +0,0 @@
/*
==============================================================================
This file is part of the JUCE examples.
Copyright (c) 2022 - Raw Material Software Limited
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
#pragma once
//==============================================================================
/* This component scrolls a continuous waveform showing the audio that's
coming into whatever audio inputs this object is connected to.
*/
class LiveScrollingAudioDisplay : public AudioVisualiserComponent,
public AudioIODeviceCallback
{
public:
LiveScrollingAudioDisplay() : AudioVisualiserComponent (1)
{
setSamplesPerBlock (256);
setBufferSize (1024);
}
//==============================================================================
void audioDeviceAboutToStart (AudioIODevice*) override
{
clear();
}
void audioDeviceStopped() override
{
clear();
}
void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels,
float** outputChannelData, int numOutputChannels,
int numberOfSamples) override
{
for (int i = 0; i < numberOfSamples; ++i)
{
float inputSample = 0;
for (int chan = 0; chan < numInputChannels; ++chan)
if (const float* inputChannel = inputChannelData[chan])
inputSample += inputChannel[i]; // find the sum of all the channels
inputSample *= 10.0f; // boost the level to make it more easily visible.
pushSample (&inputSample, 1);
}
// We need to clear the output buffers before returning, in case they're full of junk..
for (int j = 0; j < numOutputChannels; ++j)
if (float* outputChannel = outputChannelData[j])
zeromem (outputChannel, (size_t) numberOfSamples * sizeof (float));
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LiveScrollingAudioDisplay)
};

View File

@ -1,51 +0,0 @@
#ifndef AddPair_H
#define AddPair_H
class AddPair : public Test
{
public:
AddPair()
{
m_world->SetGravity(b2Vec2(0.0f,0.0f));
{
b2CircleShape shape;
shape.m_p.SetZero();
shape.m_radius = 0.1f;
float minX = -6.0f;
float maxX = 0.0f;
float minY = 4.0f;
float maxY = 6.0f;
for (int i = 0; i < 400; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = b2Vec2(RandomFloat(minX,maxX),RandomFloat(minY,maxY));
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 0.01f);
}
}
{
b2PolygonShape shape;
shape.SetAsBox(1.5f, 1.5f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-40.0f,5.0f);
bd.bullet = true;
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 1.0f);
body->SetLinearVelocity(b2Vec2(150.0f, 0.0f));
}
}
static Test* Create()
{
return new AddPair;
}
};
#endif

View File

@ -1,183 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef APPLY_FORCE_H
#define APPLY_FORCE_H
class ApplyForce : public Test
{
public:
ApplyForce()
{
m_world->SetGravity(b2Vec2(0.0f, 0.0f));
const float32 k_restitution = 0.4f;
b2Body* ground;
{
b2BodyDef bd;
bd.position.Set(0.0f, 20.0f);
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
b2FixtureDef sd;
sd.shape = &shape;
sd.density = 0.0f;
sd.restitution = k_restitution;
// Left vertical
shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(-20.0f, 20.0f));
ground->CreateFixture(&sd);
// Right vertical
shape.Set(b2Vec2(20.0f, -20.0f), b2Vec2(20.0f, 20.0f));
ground->CreateFixture(&sd);
// Top horizontal
shape.Set(b2Vec2(-20.0f, 20.0f), b2Vec2(20.0f, 20.0f));
ground->CreateFixture(&sd);
// Bottom horizontal
shape.Set(b2Vec2(-20.0f, -20.0f), b2Vec2(20.0f, -20.0f));
ground->CreateFixture(&sd);
}
{
b2Transform xf1;
xf1.q.Set(0.3524f * b2_pi);
xf1.p = xf1.q.GetXAxis();
b2Vec2 vertices[3];
vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));
vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));
vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));
b2PolygonShape poly1;
poly1.Set(vertices, 3);
b2FixtureDef sd1;
sd1.shape = &poly1;
sd1.density = 4.0f;
b2Transform xf2;
xf2.q.Set(-0.3524f * b2_pi);
xf2.p = -xf2.q.GetXAxis();
vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));
vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));
vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));
b2PolygonShape poly2;
poly2.Set(vertices, 3);
b2FixtureDef sd2;
sd2.shape = &poly2;
sd2.density = 2.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.angularDamping = 5.0f;
bd.linearDamping = 0.1f;
bd.position.Set(0.0f, 2.0f);
bd.angle = b2_pi;
bd.allowSleep = false;
m_body = m_world->CreateBody(&bd);
m_body->CreateFixture(&sd1);
m_body->CreateFixture(&sd2);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.3f;
for (int i = 0; i < 10; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 5.0f + 1.54f * i);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
float32 gravity = 10.0f;
float32 I = body->GetInertia();
float32 mass = body->GetMass();
// For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m)
float32 radius = b2Sqrt(2.0f * I / mass);
b2FrictionJointDef jd;
jd.localAnchorA.SetZero();
jd.localAnchorB.SetZero();
jd.bodyA = ground;
jd.bodyB = body;
jd.collideConnected = true;
jd.maxForce = mass * gravity;
jd.maxTorque = mass * radius * gravity;
m_world->CreateJoint(&jd);
}
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'w':
{
b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -200.0f));
b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 2.0f));
m_body->ApplyForce(f, p);
}
break;
case 'a':
{
m_body->ApplyTorque(50.0f);
}
break;
case 'd':
{
m_body->ApplyTorque(-50.0f);
}
break;
default:
break;
}
}
static Test* Create()
{
return new ApplyForce;
}
b2Body* m_body;
};
#endif

View File

@ -1,159 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BODY_TYPES_H
#define BODY_TYPES_H
class BodyTypes : public Test
{
public:
BodyTypes()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
b2FixtureDef fd;
fd.shape = &shape;
ground->CreateFixture(&fd);
}
// Define attachment
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 3.0f);
m_attachment = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.5f, 2.0f);
m_attachment->CreateFixture(&shape, 2.0f);
}
// Define platform
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-4.0f, 5.0f);
m_platform = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.5f, 4.0f, b2Vec2(4.0f, 0.0f), 0.5f * b2_pi);
b2FixtureDef fd;
fd.shape = &shape;
fd.friction = 0.6f;
fd.density = 2.0f;
m_platform->CreateFixture(&fd);
b2RevoluteJointDef rjd;
rjd.Initialize(m_attachment, m_platform, b2Vec2(0.0f, 5.0f));
rjd.maxMotorTorque = 50.0f;
rjd.enableMotor = true;
m_world->CreateJoint(&rjd);
b2PrismaticJointDef pjd;
pjd.Initialize(ground, m_platform, b2Vec2(0.0f, 5.0f), b2Vec2(1.0f, 0.0f));
pjd.maxMotorForce = 1000.0f;
pjd.enableMotor = true;
pjd.lowerTranslation = -10.0f;
pjd.upperTranslation = 10.0f;
pjd.enableLimit = true;
m_world->CreateJoint(&pjd);
m_speed = 3.0f;
}
// Create a payload
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 8.0f);
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.75f, 0.75f);
b2FixtureDef fd;
fd.shape = &shape;
fd.friction = 0.6f;
fd.density = 2.0f;
body->CreateFixture(&fd);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'd':
m_platform->SetType(b2_dynamicBody);
break;
case 's':
m_platform->SetType(b2_staticBody);
break;
case 'k':
m_platform->SetType(b2_kinematicBody);
m_platform->SetLinearVelocity(b2Vec2(-m_speed, 0.0f));
m_platform->SetAngularVelocity(0.0f);
break;
}
}
void Step(Settings* settings)
{
// Drive the kinematic body.
if (m_platform->GetType() == b2_kinematicBody)
{
b2Vec2 p = m_platform->GetTransform().p;
b2Vec2 v = m_platform->GetLinearVelocity();
if ((p.x < -10.0f && v.x < 0.0f) ||
(p.x > 10.0f && v.x > 0.0f))
{
v.x = -v.x;
m_platform->SetLinearVelocity(v);
}
}
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Keys: (d) dynamic, (s) static, (k) kinematic");
m_textLine += 15;
}
static Test* Create()
{
return new BodyTypes;
}
b2Body* m_attachment;
b2Body* m_platform;
float32 m_speed;
};
#endif

View File

@ -1,155 +0,0 @@
/*
* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BREAKABLE_TEST_H
#define BREAKABLE_TEST_H
// This is used to test sensor shapes.
class Breakable : public Test
{
public:
enum
{
e_count = 7
};
Breakable()
{
// Ground body
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Breakable dynamic body
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 40.0f);
bd.angle = 0.25f * b2_pi;
m_body1 = m_world->CreateBody(&bd);
m_shape1.SetAsBox(0.5f, 0.5f, b2Vec2(-0.5f, 0.0f), 0.0f);
m_piece1 = m_body1->CreateFixture(&m_shape1, 1.0f);
m_shape2.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, 0.0f), 0.0f);
m_piece2 = m_body1->CreateFixture(&m_shape2, 1.0f);
}
m_break = false;
m_broke = false;
}
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{
if (m_broke)
{
// The body already broke.
return;
}
// Should the body break?
int32 count = contact->GetManifold()->pointCount;
float32 maxImpulse = 0.0f;
for (int32 i = 0; i < count; ++i)
{
maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
}
if (maxImpulse > 40.0f)
{
// Flag the body for breaking.
m_break = true;
}
}
void Break()
{
// Create two bodies from one.
b2Body* body1 = m_piece1->GetBody();
b2Vec2 center = body1->GetWorldCenter();
body1->DestroyFixture(m_piece2);
m_piece2 = NULL;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = body1->GetPosition();
bd.angle = body1->GetAngle();
b2Body* body2 = m_world->CreateBody(&bd);
m_piece2 = body2->CreateFixture(&m_shape2, 1.0f);
// Compute consistent velocities for new bodies based on
// cached velocity.
b2Vec2 center1 = body1->GetWorldCenter();
b2Vec2 center2 = body2->GetWorldCenter();
b2Vec2 velocity1 = m_velocity + b2Cross(m_angularVelocity, center1 - center);
b2Vec2 velocity2 = m_velocity + b2Cross(m_angularVelocity, center2 - center);
body1->SetAngularVelocity(m_angularVelocity);
body1->SetLinearVelocity(velocity1);
body2->SetAngularVelocity(m_angularVelocity);
body2->SetLinearVelocity(velocity2);
}
void Step(Settings* settings)
{
if (m_break)
{
Break();
m_broke = true;
m_break = false;
}
// Cache velocities to improve movement on breakage.
if (m_broke == false)
{
m_velocity = m_body1->GetLinearVelocity();
m_angularVelocity = m_body1->GetAngularVelocity();
}
Test::Step(settings);
}
static Test* Create()
{
return new Breakable;
}
b2Body* m_body1;
b2Vec2 m_velocity;
float32 m_angularVelocity;
b2PolygonShape m_shape1;
b2PolygonShape m_shape2;
b2Fixture* m_piece1;
b2Fixture* m_piece2;
bool m_broke;
bool m_break;
};
#endif

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BRIDGE_H
#define BRIDGE_H
class Bridge : public Test
{
public:
enum
{
e_count = 30
};
Bridge()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 0.2f;
b2RevoluteJointDef jd;
b2Body* prevBody = ground;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-14.5f + 1.0f * i, 5.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
if (i == (e_count >> 1))
{
m_middle = body;
}
prevBody = body;
}
b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f);
jd.Initialize(prevBody, ground, anchor);
m_world->CreateJoint(&jd);
}
for (int32 i = 0; i < 2; ++i)
{
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
b2PolygonShape shape;
shape.Set(vertices, 3);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-8.0f + 8.0f * i, 12.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
for (int32 i = 0; i < 3; ++i)
{
b2CircleShape shape;
shape.m_radius = 0.5f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-6.0f + 6.0f * i, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
}
static Test* Create()
{
return new Bridge;
}
b2Body* m_middle;
};
#endif

View File

@ -1,136 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BULLET_TEST_H
#define BULLET_TEST_H
class BulletTest : public Test
{
public:
BulletTest()
{
{
b2BodyDef bd;
bd.position.Set(0.0f, 0.0f);
b2Body* body = m_world->CreateBody(&bd);
b2EdgeShape edge;
edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
body->CreateFixture(&edge, 0.0f);
b2PolygonShape shape;
shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
body->CreateFixture(&shape, 0.0f);
}
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 4.0f);
b2PolygonShape box;
box.SetAsBox(2.0f, 0.1f);
m_body = m_world->CreateBody(&bd);
m_body->CreateFixture(&box, 1.0f);
box.SetAsBox(0.25f, 0.25f);
//m_x = RandomFloat(-1.0f, 1.0f);
m_x = 0.20352793f;
bd.position.Set(m_x, 10.0f);
bd.bullet = true;
m_bullet = m_world->CreateBody(&bd);
m_bullet->CreateFixture(&box, 100.0f);
m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
}
}
void Launch()
{
m_body->SetTransform(b2Vec2(0.0f, 4.0f), 0.0f);
m_body->SetLinearVelocity(b2Vec2_zero);
m_body->SetAngularVelocity(0.0f);
m_x = RandomFloat(-1.0f, 1.0f);
m_bullet->SetTransform(b2Vec2(m_x, 10.0f), 0.0f);
m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
m_bullet->SetAngularVelocity(0.0f);
extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
extern int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
extern int32 b2_toiRootIters, b2_toiMaxRootIters;
b2_gjkCalls = 0;
b2_gjkIters = 0;
b2_gjkMaxIters = 0;
b2_toiCalls = 0;
b2_toiIters = 0;
b2_toiMaxIters = 0;
b2_toiRootIters = 0;
b2_toiMaxRootIters = 0;
}
void Step(Settings* settings)
{
Test::Step(settings);
extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
extern int32 b2_toiCalls, b2_toiIters;
extern int32 b2_toiRootIters, b2_toiMaxRootIters;
if (b2_gjkCalls > 0)
{
m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);
m_textLine += 15;
}
if (b2_toiCalls > 0)
{
m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",
b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",
b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);
m_textLine += 15;
}
if (m_stepCount % 60 == 0)
{
Launch();
}
}
static Test* Create()
{
return new BulletTest;
}
b2Body* m_body;
b2Body* m_bullet;
float32 m_x;
};
#endif

View File

@ -1,211 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CANTILEVER_H
#define CANTILEVER_H
// It is difficult to make a cantilever made of links completely rigid with weld joints.
// You will have to use a high number of iterations to make them stiff.
// So why not go ahead and use soft weld joints? They behave like a revolute
// joint with a rotational spring.
class Cantilever : public Test
{
public:
enum
{
e_count = 8
};
Cantilever()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
b2WeldJointDef jd;
b2Body* prevBody = ground;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-14.5f + 1.0f * i, 5.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
prevBody = body;
}
}
{
b2PolygonShape shape;
shape.SetAsBox(1.0f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
b2WeldJointDef jd;
jd.frequencyHz = 5.0f;
jd.dampingRatio = 0.7f;
b2Body* prevBody = ground;
for (int32 i = 0; i < 3; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-14.0f + 2.0f * i, 15.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(-15.0f + 2.0f * i, 15.0f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
prevBody = body;
}
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
b2WeldJointDef jd;
b2Body* prevBody = ground;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-4.5f + 1.0f * i, 5.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
if (i > 0)
{
b2Vec2 anchor(-5.0f + 1.0f * i, 5.0f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
}
prevBody = body;
}
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
b2WeldJointDef jd;
jd.frequencyHz = 8.0f;
jd.dampingRatio = 0.7f;
b2Body* prevBody = ground;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(5.5f + 1.0f * i, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
if (i > 0)
{
b2Vec2 anchor(5.0f + 1.0f * i, 10.0f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
}
prevBody = body;
}
}
for (int32 i = 0; i < 2; ++i)
{
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
b2PolygonShape shape;
shape.Set(vertices, 3);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-8.0f + 8.0f * i, 12.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
for (int32 i = 0; i < 2; ++i)
{
b2CircleShape shape;
shape.m_radius = 0.5f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-6.0f + 6.0f * i, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
}
static Test* Create()
{
return new Cantilever;
}
b2Body* m_middle;
};
#endif

View File

@ -1,286 +0,0 @@
/*
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CAR_H
#define CAR_H
// This is a fun demo that shows off the wheel joint
class Car : public Test
{
public:
Car()
{
m_hz = 4.0f;
m_zeta = 0.7f;
m_speed = 50.0f;
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 0.0f;
fd.friction = 0.6f;
shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
ground->CreateFixture(&fd);
float32 hs[10] = {0.25f, 1.0f, 4.0f, 0.0f, 0.0f, -1.0f, -2.0f, -2.0f, -1.25f, 0.0f};
float32 x = 20.0f, y1 = 0.0f, dx = 5.0f;
for (int32 i = 0; i < 10; ++i)
{
float32 y2 = hs[i];
shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));
ground->CreateFixture(&fd);
y1 = y2;
x += dx;
}
for (int32 i = 0; i < 10; ++i)
{
float32 y2 = hs[i];
shape.Set(b2Vec2(x, y1), b2Vec2(x + dx, y2));
ground->CreateFixture(&fd);
y1 = y2;
x += dx;
}
shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
ground->CreateFixture(&fd);
x += 80.0f;
shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
ground->CreateFixture(&fd);
x += 40.0f;
shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 10.0f, 5.0f));
ground->CreateFixture(&fd);
x += 20.0f;
shape.Set(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
ground->CreateFixture(&fd);
x += 40.0f;
shape.Set(b2Vec2(x, 0.0f), b2Vec2(x, 20.0f));
ground->CreateFixture(&fd);
}
// Teeter
{
b2BodyDef bd;
bd.position.Set(140.0f, 1.0f);
bd.type = b2_dynamicBody;
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape box;
box.SetAsBox(10.0f, 0.25f);
body->CreateFixture(&box, 1.0f);
b2RevoluteJointDef jd;
jd.Initialize(ground, body, body->GetPosition());
jd.lowerAngle = -8.0f * b2_pi / 180.0f;
jd.upperAngle = 8.0f * b2_pi / 180.0f;
jd.enableLimit = true;
m_world->CreateJoint(&jd);
body->ApplyAngularImpulse(100.0f);
}
// Bridge
{
int32 N = 20;
b2PolygonShape shape;
shape.SetAsBox(1.0f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.6f;
b2RevoluteJointDef jd;
b2Body* prevBody = ground;
for (int32 i = 0; i < N; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(161.0f + 2.0f * i, -0.125f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(160.0f + 2.0f * i, -0.125f);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
prevBody = body;
}
b2Vec2 anchor(160.0f + 2.0f * N, -0.125f);
jd.Initialize(prevBody, ground, anchor);
m_world->CreateJoint(&jd);
}
// Boxes
{
b2PolygonShape box;
box.SetAsBox(0.5f, 0.5f);
b2Body* body = NULL;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(230.0f, 0.5f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&box, 0.5f);
bd.position.Set(230.0f, 1.5f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&box, 0.5f);
bd.position.Set(230.0f, 2.5f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&box, 0.5f);
bd.position.Set(230.0f, 3.5f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&box, 0.5f);
bd.position.Set(230.0f, 4.5f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&box, 0.5f);
}
// Car
{
b2PolygonShape chassis;
b2Vec2 vertices[8];
vertices[0].Set(-1.5f, -0.5f);
vertices[1].Set(1.5f, -0.5f);
vertices[2].Set(1.5f, 0.0f);
vertices[3].Set(0.0f, 0.9f);
vertices[4].Set(-1.15f, 0.9f);
vertices[5].Set(-1.5f, 0.2f);
chassis.Set(vertices, 6);
b2CircleShape circle;
circle.m_radius = 0.4f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 1.0f);
m_car = m_world->CreateBody(&bd);
m_car->CreateFixture(&chassis, 1.0f);
b2FixtureDef fd;
fd.shape = &circle;
fd.density = 1.0f;
fd.friction = 0.9f;
bd.position.Set(-1.0f, 0.35f);
m_wheel1 = m_world->CreateBody(&bd);
m_wheel1->CreateFixture(&fd);
bd.position.Set(1.0f, 0.4f);
m_wheel2 = m_world->CreateBody(&bd);
m_wheel2->CreateFixture(&fd);
b2WheelJointDef jd;
b2Vec2 axis(0.0f, 1.0f);
jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 20.0f;
jd.enableMotor = true;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd);
jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 10.0f;
jd.enableMotor = false;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
m_spring1->SetMotorSpeed(m_speed);
break;
case 's':
m_spring1->SetMotorSpeed(0.0f);
break;
case 'd':
m_spring1->SetMotorSpeed(-m_speed);
break;
case 'q':
m_hz = b2Max(0.0f, m_hz - 1.0f);
m_spring1->SetSpringFrequencyHz(m_hz);
m_spring2->SetSpringFrequencyHz(m_hz);
break;
case 'e':
m_hz += 1.0f;
m_spring1->SetSpringFrequencyHz(m_hz);
m_spring2->SetSpringFrequencyHz(m_hz);
break;
}
}
void Step(Settings* settings)
{
m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, hz down = q, hz up = e");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "frequency = %g hz, damping ratio = %g", m_hz, m_zeta);
m_textLine += 15;
settings->viewCenter.x = m_car->GetPosition().x;
Test::Step(settings);
}
static Test* Create()
{
return new Car;
}
b2Body* m_car;
b2Body* m_wheel1;
b2Body* m_wheel2;
float32 m_hz;
float32 m_zeta;
float32 m_speed;
b2WheelJoint* m_spring1;
b2WheelJoint* m_spring2;
};
#endif

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CHAIN_H
#define CHAIN_H
class Chain : public Test
{
public:
Chain()
{
b2Body* ground = {};
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.6f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 0.2f;
b2RevoluteJointDef jd;
jd.collideConnected = false;
const float32 y = 25.0f;
b2Body* prevBody = ground;
for (int i = 0; i < 30; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.5f + i, y);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(float32(i), y);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
prevBody = body;
}
}
}
static Test* Create()
{
return new Chain;
}
};
#endif

View File

@ -1,253 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CHARACTER_COLLISION_H
#define CHARACTER_COLLISION_H
/// This is a test of typical character collision scenarios. This does not
/// show how you should implement a character in your application.
/// Instead this is used to test smooth collision on edge chains.
class CharacterCollision : public Test
{
public:
CharacterCollision()
{
// Ground body
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Collinear edges with no adjacency information.
// This shows the problematic case where a box shape can hit
// an internal vertex.
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-8.0f, 1.0f), b2Vec2(-6.0f, 1.0f));
ground->CreateFixture(&shape, 0.0f);
shape.Set(b2Vec2(-6.0f, 1.0f), b2Vec2(-4.0f, 1.0f));
ground->CreateFixture(&shape, 0.0f);
shape.Set(b2Vec2(-4.0f, 1.0f), b2Vec2(-2.0f, 1.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Chain shape
{
b2BodyDef bd;
bd.angle = 0.25f * b2_pi;
b2Body* ground = m_world->CreateBody(&bd);
b2Vec2 vs[4];
vs[0].Set(5.0f, 7.0f);
vs[1].Set(6.0f, 8.0f);
vs[2].Set(7.0f, 8.0f);
vs[3].Set(8.0f, 7.0f);
b2ChainShape shape;
shape.CreateChain(vs, 4);
ground->CreateFixture(&shape, 0.0f);
}
// Square tiles. This shows that adjacency shapes may
// have non-smooth collision. There is no solution
// to this problem.
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(1.0f, 1.0f, b2Vec2(4.0f, 3.0f), 0.0f);
ground->CreateFixture(&shape, 0.0f);
shape.SetAsBox(1.0f, 1.0f, b2Vec2(6.0f, 3.0f), 0.0f);
ground->CreateFixture(&shape, 0.0f);
shape.SetAsBox(1.0f, 1.0f, b2Vec2(8.0f, 3.0f), 0.0f);
ground->CreateFixture(&shape, 0.0f);
}
// Square made from an edge loop. Collision should be smooth.
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2Vec2 vs[4];
vs[0].Set(-1.0f, 3.0f);
vs[1].Set(1.0f, 3.0f);
vs[2].Set(1.0f, 5.0f);
vs[3].Set(-1.0f, 5.0f);
b2ChainShape shape;
shape.CreateLoop(vs, 4);
ground->CreateFixture(&shape, 0.0f);
}
// Edge loop. Collision should be smooth.
{
b2BodyDef bd;
bd.position.Set(-10.0f, 4.0f);
b2Body* ground = m_world->CreateBody(&bd);
b2Vec2 vs[10];
vs[0].Set(0.0f, 0.0f);
vs[1].Set(6.0f, 0.0f);
vs[2].Set(6.0f, 2.0f);
vs[3].Set(4.0f, 1.0f);
vs[4].Set(2.0f, 2.0f);
vs[5].Set(0.0f, 2.0f);
vs[6].Set(-2.0f, 2.0f);
vs[7].Set(-4.0f, 3.0f);
vs[8].Set(-6.0f, 2.0f);
vs[9].Set(-6.0f, 0.0f);
b2ChainShape shape;
shape.CreateLoop(vs, 10);
ground->CreateFixture(&shape, 0.0f);
}
// Square character 1
{
b2BodyDef bd;
bd.position.Set(-3.0f, 8.0f);
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
body->CreateFixture(&fd);
}
// Square character 2
{
b2BodyDef bd;
bd.position.Set(-5.0f, 5.0f);
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.25f, 0.25f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
body->CreateFixture(&fd);
}
// Hexagon character
{
b2BodyDef bd;
bd.position.Set(-5.0f, 8.0f);
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
float32 angle = 0.0f;
float32 delta = b2_pi / 3.0f;
b2Vec2 vertices[6];
for (int32 i = 0; i < 6; ++i)
{
vertices[i].Set(0.5f * cosf(angle), 0.5f * sinf(angle));
angle += delta;
}
b2PolygonShape shape;
shape.Set(vertices, 6);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
body->CreateFixture(&fd);
}
// Circle character
{
b2BodyDef bd;
bd.position.Set(3.0f, 5.0f);
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
b2CircleShape shape;
shape.m_radius = 0.5f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
body->CreateFixture(&fd);
}
// Circle character
{
b2BodyDef bd;
bd.position.Set(-7.0f, 6.0f);
bd.type = b2_dynamicBody;
bd.allowSleep = false;
m_character = m_world->CreateBody(&bd);
b2CircleShape shape;
shape.m_radius = 0.25f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 1.0f;
m_character->CreateFixture(&fd);
}
}
void Step(Settings* settings)
{
b2Vec2 v = m_character->GetLinearVelocity();
v.x = -5.0f;
m_character->SetLinearVelocity(v);
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "This tests various character collision shapes.");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Limitation: square and hexagon can snag on aligned boxes.");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Feature: edge chains have smooth collision inside and out.");
m_textLine += 15;
}
static Test* Create()
{
return new CharacterCollision;
}
b2Body* m_character;
};
#endif

View File

@ -1,176 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef COLLISION_FILTERING_H
#define COLLISION_FILTERING_H
// This is a test of collision filtering.
// There is a triangle, a box, and a circle.
// There are 6 shapes. 3 large and 3 small.
// The 3 small ones always collide.
// The 3 large ones never collide.
// The boxes don't collide with triangles (except if both are small).
const int16 k_smallGroup = 1;
const int16 k_largeGroup = -1;
const uint16 k_defaultCategory = 0x0001;
const uint16 k_triangleCategory = 0x0002;
const uint16 k_boxCategory = 0x0004;
const uint16 k_circleCategory = 0x0008;
const uint16 k_triangleMask = 0xFFFF;
const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory;
const uint16 k_circleMask = 0xFFFF;
class CollisionFiltering : public Test
{
public:
CollisionFiltering()
{
// Ground body
{
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
b2FixtureDef sd;
sd.shape = &shape;
sd.friction = 0.3f;
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&sd);
}
// Small triangle
b2Vec2 vertices[3];
vertices[0].Set(-1.0f, 0.0f);
vertices[1].Set(1.0f, 0.0f);
vertices[2].Set(0.0f, 2.0f);
b2PolygonShape polygon;
polygon.Set(vertices, 3);
b2FixtureDef triangleShapeDef;
triangleShapeDef.shape = &polygon;
triangleShapeDef.density = 1.0f;
triangleShapeDef.filter.groupIndex = k_smallGroup;
triangleShapeDef.filter.categoryBits = k_triangleCategory;
triangleShapeDef.filter.maskBits = k_triangleMask;
b2BodyDef triangleBodyDef;
triangleBodyDef.type = b2_dynamicBody;
triangleBodyDef.position.Set(-5.0f, 2.0f);
b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
body1->CreateFixture(&triangleShapeDef);
// Large triangle (recycle definitions)
vertices[0] *= 2.0f;
vertices[1] *= 2.0f;
vertices[2] *= 2.0f;
polygon.Set(vertices, 3);
triangleShapeDef.filter.groupIndex = k_largeGroup;
triangleBodyDef.position.Set(-5.0f, 6.0f);
triangleBodyDef.fixedRotation = true; // look at me!
b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
body2->CreateFixture(&triangleShapeDef);
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-5.0f, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape p;
p.SetAsBox(0.5f, 1.0f);
body->CreateFixture(&p, 1.0f);
b2PrismaticJointDef jd;
jd.bodyA = body2;
jd.bodyB = body;
jd.enableLimit = true;
jd.localAnchorA.Set(0.0f, 4.0f);
jd.localAnchorB.SetZero();
jd.localAxisA.Set(0.0f, 1.0f);
jd.lowerTranslation = -1.0f;
jd.upperTranslation = 1.0f;
m_world->CreateJoint(&jd);
}
// Small box
polygon.SetAsBox(1.0f, 0.5f);
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &polygon;
boxShapeDef.density = 1.0f;
boxShapeDef.restitution = 0.1f;
boxShapeDef.filter.groupIndex = k_smallGroup;
boxShapeDef.filter.categoryBits = k_boxCategory;
boxShapeDef.filter.maskBits = k_boxMask;
b2BodyDef boxBodyDef;
boxBodyDef.type = b2_dynamicBody;
boxBodyDef.position.Set(0.0f, 2.0f);
b2Body* body3 = m_world->CreateBody(&boxBodyDef);
body3->CreateFixture(&boxShapeDef);
// Large box (recycle definitions)
polygon.SetAsBox(2.0f, 1.0f);
boxShapeDef.filter.groupIndex = k_largeGroup;
boxBodyDef.position.Set(0.0f, 6.0f);
b2Body* body4 = m_world->CreateBody(&boxBodyDef);
body4->CreateFixture(&boxShapeDef);
// Small circle
b2CircleShape circle;
circle.m_radius = 1.0f;
b2FixtureDef circleShapeDef;
circleShapeDef.shape = &circle;
circleShapeDef.density = 1.0f;
circleShapeDef.filter.groupIndex = k_smallGroup;
circleShapeDef.filter.categoryBits = k_circleCategory;
circleShapeDef.filter.maskBits = k_circleMask;
b2BodyDef circleBodyDef;
circleBodyDef.type = b2_dynamicBody;
circleBodyDef.position.Set(5.0f, 2.0f);
b2Body* body5 = m_world->CreateBody(&circleBodyDef);
body5->CreateFixture(&circleShapeDef);
// Large circle
circle.m_radius *= 2.0f;
circleShapeDef.filter.groupIndex = k_largeGroup;
circleBodyDef.position.Set(5.0f, 6.0f);
b2Body* body6 = m_world->CreateBody(&circleBodyDef);
body6->CreateFixture(&circleShapeDef);
}
static Test* Create()
{
return new CollisionFiltering;
}
};
#endif

View File

@ -1,188 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef COLLISION_PROCESSING_H
#define COLLISION_PROCESSING_H
#include <algorithm>
// This test shows collision processing and tests
// deferred body destruction.
class CollisionProcessing : public Test
{
public:
CollisionProcessing()
{
// Ground body
{
b2EdgeShape shape;
shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
b2FixtureDef sd;
sd.shape = &shape;;
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&sd);
}
float32 xLo = -5.0f, xHi = 5.0f;
float32 yLo = 2.0f, yHi = 35.0f;
// Small triangle
b2Vec2 vertices[3];
vertices[0].Set(-1.0f, 0.0f);
vertices[1].Set(1.0f, 0.0f);
vertices[2].Set(0.0f, 2.0f);
b2PolygonShape polygon;
polygon.Set(vertices, 3);
b2FixtureDef triangleShapeDef;
triangleShapeDef.shape = &polygon;
triangleShapeDef.density = 1.0f;
b2BodyDef triangleBodyDef;
triangleBodyDef.type = b2_dynamicBody;
triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
body1->CreateFixture(&triangleShapeDef);
// Large triangle (recycle definitions)
vertices[0] *= 2.0f;
vertices[1] *= 2.0f;
vertices[2] *= 2.0f;
polygon.Set(vertices, 3);
triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
body2->CreateFixture(&triangleShapeDef);
// Small box
polygon.SetAsBox(1.0f, 0.5f);
b2FixtureDef boxShapeDef;
boxShapeDef.shape = &polygon;
boxShapeDef.density = 1.0f;
b2BodyDef boxBodyDef;
boxBodyDef.type = b2_dynamicBody;
boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body3 = m_world->CreateBody(&boxBodyDef);
body3->CreateFixture(&boxShapeDef);
// Large box (recycle definitions)
polygon.SetAsBox(2.0f, 1.0f);
boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body4 = m_world->CreateBody(&boxBodyDef);
body4->CreateFixture(&boxShapeDef);
// Small circle
b2CircleShape circle;
circle.m_radius = 1.0f;
b2FixtureDef circleShapeDef;
circleShapeDef.shape = &circle;
circleShapeDef.density = 1.0f;
b2BodyDef circleBodyDef;
circleBodyDef.type = b2_dynamicBody;
circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body5 = m_world->CreateBody(&circleBodyDef);
body5->CreateFixture(&circleShapeDef);
// Large circle
circle.m_radius *= 2.0f;
circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
b2Body* body6 = m_world->CreateBody(&circleBodyDef);
body6->CreateFixture(&circleShapeDef);
}
void Step(Settings* settings)
{
Test::Step(settings);
// We are going to destroy some bodies according to contact
// points. We must buffer the bodies that should be destroyed
// because they may belong to multiple contact points.
const int32 k_maxNuke = 6;
b2Body* nuke[k_maxNuke];
int32 nukeCount = 0;
// Traverse the contact results. Destroy bodies that
// are touching heavier bodies.
for (int32 i = 0; i < m_pointCount; ++i)
{
ContactPoint* point = m_points + i;
b2Body* body1 = point->fixtureA->GetBody();
b2Body* body2 = point->fixtureB->GetBody();
float32 mass1 = body1->GetMass();
float32 mass2 = body2->GetMass();
if (mass1 > 0.0f && mass2 > 0.0f)
{
if (mass2 > mass1)
{
nuke[nukeCount++] = body1;
}
else
{
nuke[nukeCount++] = body2;
}
if (nukeCount == k_maxNuke)
{
break;
}
}
}
// Sort the nuke array to group duplicates.
std::sort(nuke, nuke + nukeCount);
// Destroy the bodies, skipping duplicates.
int32 i = 0;
while (i < nukeCount)
{
b2Body* b = nuke[i++];
while (i < nukeCount && nuke[i] == b)
{
++i;
}
if (b != m_bomb)
{
m_world->DestroyBody(b);
}
}
}
static Test* Create()
{
return new CollisionProcessing;
}
};
#endif

View File

@ -1,143 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef COMPOUND_SHAPES_H
#define COMPOUND_SHAPES_H
// TODO_ERIN test joints on compounds.
class CompoundShapes : public Test
{
public:
CompoundShapes()
{
{
b2BodyDef bd;
bd.position.Set(0.0f, 0.0f);
b2Body* body = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
body->CreateFixture(&shape, 0.0f);
}
{
b2CircleShape circle1;
circle1.m_radius = 0.5f;
circle1.m_p.Set(-0.5f, 0.5f);
b2CircleShape circle2;
circle2.m_radius = 0.5f;
circle2.m_p.Set(0.5f, 0.5f);
for (int i = 0; i < 10; ++i)
{
float32 x = RandomFloat(-0.1f, 0.1f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(x + 5.0f, 1.05f + 2.5f * i);
bd.angle = RandomFloat(-b2_pi, b2_pi);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&circle1, 2.0f);
body->CreateFixture(&circle2, 0.0f);
}
}
{
b2PolygonShape polygon1;
polygon1.SetAsBox(0.25f, 0.5f);
b2PolygonShape polygon2;
polygon2.SetAsBox(0.25f, 0.5f, b2Vec2(0.0f, -0.5f), 0.5f * b2_pi);
for (int i = 0; i < 10; ++i)
{
float32 x = RandomFloat(-0.1f, 0.1f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(x - 5.0f, 1.05f + 2.5f * i);
bd.angle = RandomFloat(-b2_pi, b2_pi);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&polygon1, 2.0f);
body->CreateFixture(&polygon2, 2.0f);
}
}
{
b2Transform xf1;
xf1.q.Set(0.3524f * b2_pi);
xf1.p = xf1.q.GetXAxis();
b2Vec2 vertices[3];
b2PolygonShape triangle1;
vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));
vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));
vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));
triangle1.Set(vertices, 3);
b2Transform xf2;
xf2.q.Set(-0.3524f * b2_pi);
xf2.p = -xf2.q.GetXAxis();
b2PolygonShape triangle2;
vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));
vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));
vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));
triangle2.Set(vertices, 3);
for (int32 i = 0; i < 10; ++i)
{
float32 x = RandomFloat(-0.1f, 0.1f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(x, 2.05f + 2.5f * i);
bd.angle = 0.0f;
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&triangle1, 2.0f);
body->CreateFixture(&triangle2, 2.0f);
}
}
{
b2PolygonShape bottom;
bottom.SetAsBox( 1.5f, 0.15f );
b2PolygonShape left;
left.SetAsBox(0.15f, 2.7f, b2Vec2(-1.45f, 2.35f), 0.2f);
b2PolygonShape right;
right.SetAsBox(0.15f, 2.7f, b2Vec2(1.45f, 2.35f), -0.2f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set( 0.0f, 2.0f );
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&bottom, 4.0f);
body->CreateFixture(&left, 4.0f);
body->CreateFixture(&right, 4.0f);
}
}
static Test* Create()
{
return new CompoundShapes;
}
};
#endif

View File

@ -1,167 +0,0 @@
/*
* Copyright (c) 2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CONFINED_H
#define CONFINED_H
class Confined : public Test
{
public:
enum
{
e_columnCount = 0,
e_rowCount = 0
};
Confined()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
// Floor
shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
// Left wall
shape.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(-10.0f, 20.0f));
ground->CreateFixture(&shape, 0.0f);
// Right wall
shape.Set(b2Vec2(10.0f, 0.0f), b2Vec2(10.0f, 20.0f));
ground->CreateFixture(&shape, 0.0f);
// Roof
shape.Set(b2Vec2(-10.0f, 20.0f), b2Vec2(10.0f, 20.0f));
ground->CreateFixture(&shape, 0.0f);
}
float32 radius = 0.5f;
b2CircleShape shape;
shape.m_p.SetZero();
shape.m_radius = radius;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.1f;
for (int32 j = 0; j < e_columnCount; ++j)
{
for (int i = 0; i < e_rowCount; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-10.0f + (2.1f * j + 1.0f + 0.01f * i) * radius, (2.0f * i + 1.0f) * radius);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
}
m_world->SetGravity(b2Vec2(0.0f, 0.0f));
}
void CreateCircle()
{
float32 radius = 2.0f;
b2CircleShape shape;
shape.m_p.SetZero();
shape.m_radius = radius;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.0f;
b2Vec2 p(RandomFloat(), 3.0f + RandomFloat());
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = p;
//bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'c':
CreateCircle();
break;
}
}
void Step(Settings* settings)
{
bool sleeping = true;
for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetType() != b2_dynamicBody)
{
continue;
}
if (b->IsAwake())
{
sleeping = false;
}
}
if (m_stepCount == 180)
{
m_stepCount += 0;
}
//if (sleeping)
//{
// CreateCircle();
//}
Test::Step(settings);
for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetType() != b2_dynamicBody)
{
continue;
}
b2Vec2 p = b->GetPosition();
if (p.x <= -10.0f || 10.0f <= p.x || p.y <= 0.0f || 20.0f <= p.y)
{
p.x += 0.0;
}
}
m_debugDraw.DrawString(5, m_textLine, "Press 'c' to create a circle.");
m_textLine += 15;
}
static Test* Create()
{
return new Confined;
}
};
#endif

View File

@ -1,137 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CONTINUOUS_TEST_H
#define CONTINUOUS_TEST_H
class ContinuousTest : public Test
{
public:
ContinuousTest()
{
{
b2BodyDef bd;
bd.position.Set(0.0f, 0.0f);
b2Body* body = m_world->CreateBody(&bd);
b2EdgeShape edge;
edge.Set(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
body->CreateFixture(&edge, 0.0f);
b2PolygonShape shape;
shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
body->CreateFixture(&shape, 0.0f);
}
#if 1
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 20.0f);
//bd.angle = 0.1f;
b2PolygonShape shape;
shape.SetAsBox(2.0f, 0.1f);
m_body = m_world->CreateBody(&bd);
m_body->CreateFixture(&shape, 1.0f);
m_angularVelocity = RandomFloat(-50.0f, 50.0f);
//m_angularVelocity = 46.661274f;
m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
m_body->SetAngularVelocity(m_angularVelocity);
}
#else
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 2.0f);
b2Body* body = m_world->CreateBody(&bd);
b2CircleShape shape;
shape.m_p.SetZero();
shape.m_radius = 0.5f;
body->CreateFixture(&shape, 1.0f);
bd.bullet = true;
bd.position.Set(0.0f, 10.0f);
body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 1.0f);
body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
}
#endif
}
void Launch()
{
m_body->SetTransform(b2Vec2(0.0f, 20.0f), 0.0f);
m_angularVelocity = RandomFloat(-50.0f, 50.0f);
m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
m_body->SetAngularVelocity(m_angularVelocity);
}
void Step(Settings* settings)
{
if (m_stepCount == 12)
{
m_stepCount += 0;
}
Test::Step(settings);
extern int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
if (b2_gjkCalls > 0)
{
m_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
b2_gjkCalls, b2_gjkIters / float32(b2_gjkCalls), b2_gjkMaxIters);
m_textLine += 15;
}
extern int32 b2_toiCalls, b2_toiIters;
extern int32 b2_toiRootIters, b2_toiMaxRootIters;
if (b2_toiCalls > 0)
{
m_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",
b2_toiCalls, b2_toiIters / float32(b2_toiCalls), b2_toiMaxRootIters);
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",
b2_toiRootIters / float32(b2_toiCalls), b2_toiMaxRootIters);
m_textLine += 15;
}
if (m_stepCount % 60 == 0)
{
//Launch();
}
}
static Test* Create()
{
return new ContinuousTest;
}
b2Body* m_body;
float32 m_angularVelocity;
};
#endif

View File

@ -1,135 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef DISTANCE_TEST_H
#define DISTANCE_TEST_H
class DistanceTest : public Test
{
public:
DistanceTest()
{
{
m_transformA.SetIdentity();
m_transformA.p.Set(0.0f, -0.2f);
m_polygonA.SetAsBox(10.0f, 0.2f);
}
{
m_positionB.Set(12.017401f, 0.13678508f);
m_angleB = -0.0109265f;
m_transformB.Set(m_positionB, m_angleB);
m_polygonB.SetAsBox(2.0f, 0.1f);
}
}
static Test* Create()
{
return new DistanceTest;
}
void Step(Settings* settings)
{
Test::Step(settings);
b2DistanceInput input;
input.proxyA.Set(&m_polygonA, 0);
input.proxyB.Set(&m_polygonB, 0);
input.transformA = m_transformA;
input.transformB = m_transformB;
input.useRadii = true;
b2SimplexCache cache;
cache.count = 0;
b2DistanceOutput output;
b2Distance(&output, &cache, &input);
m_debugDraw.DrawString(5, m_textLine, "distance = %g", output.distance);
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "iterations = %d", output.iterations);
m_textLine += 15;
{
b2Color color(0.9f, 0.9f, 0.9f);
b2Vec2 v[b2_maxPolygonVertices];
for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i)
{
v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
}
m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color);
for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i)
{
v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color);
}
b2Vec2 x1 = output.pointA;
b2Vec2 x2 = output.pointB;
b2Color c1(1.0f, 0.0f, 0.0f);
m_debugDraw.DrawPoint(x1, 4.0f, c1);
b2Color c2(1.0f, 1.0f, 0.0f);
m_debugDraw.DrawPoint(x2, 4.0f, c2);
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
m_positionB.x -= 0.1f;
break;
case 'd':
m_positionB.x += 0.1f;
break;
case 's':
m_positionB.y -= 0.1f;
break;
case 'w':
m_positionB.y += 0.1f;
break;
case 'q':
m_angleB += 0.1f * b2_pi;
break;
case 'e':
m_angleB -= 0.1f * b2_pi;
break;
}
m_transformB.Set(m_positionB, m_angleB);
}
b2Vec2 m_positionB;
float32 m_angleB;
b2Transform m_transformA;
b2Transform m_transformB;
b2PolygonShape m_polygonA;
b2PolygonShape m_polygonB;
};
#endif

View File

@ -1,215 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef DOMINOS_H
#define DOMINOS_H
class Dominos : public Test
{
public:
Dominos()
{
b2Body* b1;
{
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
b2BodyDef bd;
b1 = m_world->CreateBody(&bd);
b1->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(6.0f, 0.25f);
b2BodyDef bd;
bd.position.Set(-1.5f, 10.0f);
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.1f, 1.0f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 0.1f;
for (int i = 0; i < 10; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-6.0f + 1.0f * i, 11.25f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
}
}
{
b2PolygonShape shape;
shape.SetAsBox(7.0f, 0.25f, b2Vec2_zero, 0.3f);
b2BodyDef bd;
bd.position.Set(1.0f, 6.0f);
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
b2Body* b2;
{
b2PolygonShape shape;
shape.SetAsBox(0.25f, 1.5f);
b2BodyDef bd;
bd.position.Set(-7.0f, 4.0f);
b2 = m_world->CreateBody(&bd);
b2->CreateFixture(&shape, 0.0f);
}
b2Body* b3;
{
b2PolygonShape shape;
shape.SetAsBox(6.0f, 0.125f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-0.9f, 1.0f);
bd.angle = -0.15f;
b3 = m_world->CreateBody(&bd);
b3->CreateFixture(&shape, 10.0f);
}
b2RevoluteJointDef jd;
b2Vec2 anchor;
anchor.Set(-2.0f, 1.0f);
jd.Initialize(b1, b3, anchor);
jd.collideConnected = true;
m_world->CreateJoint(&jd);
b2Body* b4;
{
b2PolygonShape shape;
shape.SetAsBox(0.25f, 0.25f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-10.0f, 15.0f);
b4 = m_world->CreateBody(&bd);
b4->CreateFixture(&shape, 10.0f);
}
anchor.Set(-7.0f, 15.0f);
jd.Initialize(b2, b4, anchor);
m_world->CreateJoint(&jd);
b2Body* b5;
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(6.5f, 3.0f);
b5 = m_world->CreateBody(&bd);
b2PolygonShape shape;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 10.0f;
fd.friction = 0.1f;
shape.SetAsBox(1.0f, 0.1f, b2Vec2(0.0f, -0.9f), 0.0f);
b5->CreateFixture(&fd);
shape.SetAsBox(0.1f, 1.0f, b2Vec2(-0.9f, 0.0f), 0.0f);
b5->CreateFixture(&fd);
shape.SetAsBox(0.1f, 1.0f, b2Vec2(0.9f, 0.0f), 0.0f);
b5->CreateFixture(&fd);
}
anchor.Set(6.0f, 2.0f);
jd.Initialize(b1, b5, anchor);
m_world->CreateJoint(&jd);
b2Body* b6;
{
b2PolygonShape shape;
shape.SetAsBox(1.0f, 0.1f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(6.5f, 4.1f);
b6 = m_world->CreateBody(&bd);
b6->CreateFixture(&shape, 30.0f);
}
anchor.Set(7.5f, 4.0f);
jd.Initialize(b5, b6, anchor);
m_world->CreateJoint(&jd);
b2Body* b7;
{
b2PolygonShape shape;
shape.SetAsBox(0.1f, 1.0f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(7.4f, 1.0f);
b7 = m_world->CreateBody(&bd);
b7->CreateFixture(&shape, 10.0f);
}
b2DistanceJointDef djd;
djd.bodyA = b3;
djd.bodyB = b7;
djd.localAnchorA.Set(6.0f, 0.0f);
djd.localAnchorB.Set(0.0f, -1.0f);
b2Vec2 d = djd.bodyB->GetWorldPoint(djd.localAnchorB) - djd.bodyA->GetWorldPoint(djd.localAnchorA);
djd.length = d.Length();
m_world->CreateJoint(&djd);
{
float32 radius = 0.2f;
b2CircleShape shape;
shape.m_radius = radius;
for (int i = 0; i < 4; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(5.9f + 2.0f * radius * i, 2.4f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 10.0f);
}
}
}
static Test* Create()
{
return new Dominos;
}
};
#endif

View File

@ -1,267 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef DUMP_SHELL_H
#define DUMP_SHELL_H
// This test holds worlds dumped using b2World::Dump.
class DumpShell : public Test
{
public:
DumpShell()
{
b2Vec2 g(0.000000000000000e+00f, 0.000000000000000e+00f);
m_world->SetGravity(g);
b2Body** bodies = (b2Body**)b2Alloc(3 * sizeof(b2Body*));
b2Joint** joints = (b2Joint**)b2Alloc(2 * sizeof(b2Joint*));
{
b2BodyDef bd;
bd.type = b2BodyType(2);
bd.position.Set(1.304347801208496e+01f, 2.500000000000000e+00f);
bd.angle = 0.000000000000000e+00f;
bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
bd.angularVelocity = 0.000000000000000e+00f;
bd.linearDamping = 5.000000000000000e-01f;
bd.angularDamping = 5.000000000000000e-01f;
bd.allowSleep = bool(4);
bd.awake = bool(2);
bd.fixedRotation = bool(0);
bd.bullet = bool(0);
bd.active = bool(32);
bd.gravityScale = 1.000000000000000e+00f;
bodies[0] = m_world->CreateBody(&bd);
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+00f;
fd.restitution = 5.000000000000000e-01f;
fd.density = 1.000000000000000e+01f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2PolygonShape shape;
b2Vec2 vs[8];
vs[0].Set(-6.900000095367432e+00f, -3.000000119209290e-01f);
vs[1].Set(2.000000029802322e-01f, -3.000000119209290e-01f);
vs[2].Set(2.000000029802322e-01f, 2.000000029802322e-01f);
vs[3].Set(-6.900000095367432e+00f, 2.000000029802322e-01f);
shape.Set(vs, 4);
fd.shape = &shape;
bodies[0]->CreateFixture(&fd);
}
}
{
b2BodyDef bd;
bd.type = b2BodyType(2);
bd.position.Set(8.478260636329651e-01f, 2.500000000000000e+00f);
bd.angle = 0.000000000000000e+00f;
bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
bd.angularVelocity = 0.000000000000000e+00f;
bd.linearDamping = 5.000000000000000e-01f;
bd.angularDamping = 5.000000000000000e-01f;
bd.allowSleep = bool(4);
bd.awake = bool(2);
bd.fixedRotation = bool(0);
bd.bullet = bool(0);
bd.active = bool(32);
bd.gravityScale = 1.000000000000000e+00f;
bodies[1] = m_world->CreateBody(&bd);
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+00f;
fd.restitution = 5.000000000000000e-01f;
fd.density = 1.000000000000000e+01f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2PolygonShape shape;
b2Vec2 vs[8];
vs[0].Set(-3.228000104427338e-01f, -2.957000136375427e-01f);
vs[1].Set(6.885900020599365e+00f, -3.641000092029572e-01f);
vs[2].Set(6.907599925994873e+00f, 3.271999955177307e-01f);
vs[3].Set(-3.228000104427338e-01f, 2.825999855995178e-01f);
shape.Set(vs, 4);
fd.shape = &shape;
bodies[1]->CreateFixture(&fd);
}
}
{
b2BodyDef bd;
bd.type = b2BodyType(0);
bd.position.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
bd.angle = 0.000000000000000e+00f;
bd.linearVelocity.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
bd.angularVelocity = 0.000000000000000e+00f;
bd.linearDamping = 0.000000000000000e+00f;
bd.angularDamping = 0.000000000000000e+00f;
bd.allowSleep = bool(4);
bd.awake = bool(2);
bd.fixedRotation = bool(0);
bd.bullet = bool(0);
bd.active = bool(32);
bd.gravityScale = 1.000000000000000e+00f;
bodies[2] = m_world->CreateBody(&bd);
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+01f;
fd.restitution = 0.000000000000000e+00f;
fd.density = 0.000000000000000e+00f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2EdgeShape shape;
shape.m_radius = 9.999999776482582e-03f;
shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex1.Set(4.452173995971680e+01f, 1.669565200805664e+01f);
shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f);
shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_hasVertex0 = bool(0);
shape.m_hasVertex3 = bool(0);
fd.shape = &shape;
bodies[2]->CreateFixture(&fd);
}
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+01f;
fd.restitution = 0.000000000000000e+00f;
fd.density = 0.000000000000000e+00f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2EdgeShape shape;
shape.m_radius = 9.999999776482582e-03f;
shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f);
shape.m_vertex2.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_hasVertex0 = bool(0);
shape.m_hasVertex3 = bool(0);
fd.shape = &shape;
bodies[2]->CreateFixture(&fd);
}
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+01f;
fd.restitution = 0.000000000000000e+00f;
fd.density = 0.000000000000000e+00f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2EdgeShape shape;
shape.m_radius = 9.999999776482582e-03f;
shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex1.Set(0.000000000000000e+00f, 1.669565200805664e+01f);
shape.m_vertex2.Set(4.452173995971680e+01f, 1.669565200805664e+01f);
shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_hasVertex0 = bool(0);
shape.m_hasVertex3 = bool(0);
fd.shape = &shape;
bodies[2]->CreateFixture(&fd);
}
{
b2FixtureDef fd;
fd.friction = 1.000000000000000e+01f;
fd.restitution = 0.000000000000000e+00f;
fd.density = 0.000000000000000e+00f;
fd.isSensor = bool(0);
fd.filter.categoryBits = uint16(1);
fd.filter.maskBits = uint16(65535);
fd.filter.groupIndex = int16(0);
b2EdgeShape shape;
shape.m_radius = 9.999999776482582e-03f;
shape.m_vertex0.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex1.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_vertex2.Set(4.452173995971680e+01f, 0.000000000000000e+00f);
shape.m_vertex3.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
shape.m_hasVertex0 = bool(0);
shape.m_hasVertex3 = bool(0);
fd.shape = &shape;
bodies[2]->CreateFixture(&fd);
}
}
{
b2PrismaticJointDef jd;
jd.bodyA = bodies[1];
jd.bodyB = bodies[0];
jd.collideConnected = bool(0);
jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
jd.localAnchorB.Set(-1.219565200805664e+01f, 0.000000000000000e+00f);
jd.localAxisA.Set(-1.219565200805664e+01f, 0.000000000000000e+00f);
jd.referenceAngle = 0.000000000000000e+00f;
jd.enableLimit = bool(1);
jd.lowerTranslation = -2.000000000000000e+01f;
jd.upperTranslation = 0.000000000000000e+00f;
jd.enableMotor = bool(1);
jd.motorSpeed = 0.000000000000000e+00f;
jd.maxMotorForce = 1.000000000000000e+01f;
joints[0] = m_world->CreateJoint(&jd);
}
{
b2RevoluteJointDef jd;
jd.bodyA = bodies[1];
jd.bodyB = bodies[2];
jd.collideConnected = bool(0);
jd.localAnchorA.Set(0.000000000000000e+00f, 0.000000000000000e+00f);
jd.localAnchorB.Set(8.478260636329651e-01f, 2.500000000000000e+00f);
jd.referenceAngle = 0.000000000000000e+00f;
jd.enableLimit = bool(0);
jd.lowerAngle = 0.000000000000000e+00f;
jd.upperAngle = 0.000000000000000e+00f;
jd.enableMotor = bool(0);
jd.motorSpeed = 0.000000000000000e+00f;
jd.maxMotorTorque = 0.000000000000000e+00f;
joints[1] = m_world->CreateJoint(&jd);
}
b2Free(joints);
b2Free(bodies);
joints = NULL;
bodies = NULL;
}
static Test* Create()
{
return new DumpShell;
}
};
#endif

View File

@ -1,357 +0,0 @@
/*
* Copyright (c) 2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef DYNAMIC_TREE_TEST_H
#define DYNAMIC_TREE_TEST_H
class DynamicTreeTest : public Test
{
public:
enum
{
e_actorCount = 128
};
DynamicTreeTest()
{
m_worldExtent = 15.0f;
m_proxyExtent = 0.5f;
srand(888);
for (int32 i = 0; i < e_actorCount; ++i)
{
Actor* actor = m_actors + i;
GetRandomAABB(&actor->aabb);
actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
}
m_stepCount = 0;
float32 h = m_worldExtent;
m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h);
m_queryAABB.upperBound.Set(5.0f, 6.0f + h);
m_rayCastInput.p1.Set(-5.0, 5.0f + h);
m_rayCastInput.p2.Set(7.0f, -4.0f + h);
//m_rayCastInput.p1.Set(0.0f, 2.0f + h);
//m_rayCastInput.p2.Set(0.0f, -2.0f + h);
m_rayCastInput.maxFraction = 1.0f;
m_automated = false;
}
static Test* Create()
{
return new DynamicTreeTest;
}
void Step(Settings* settings)
{
B2_NOT_USED(settings);
m_rayActor = NULL;
for (int32 i = 0; i < e_actorCount; ++i)
{
m_actors[i].fraction = 1.0f;
m_actors[i].overlap = false;
}
if (m_automated == true)
{
int32 actionCount = b2Max(1, e_actorCount >> 2);
for (int32 i = 0; i < actionCount; ++i)
{
Action();
}
}
Query();
RayCast();
for (int32 i = 0; i < e_actorCount; ++i)
{
Actor* actor = m_actors + i;
if (actor->proxyId == b2_nullNode)
continue;
b2Color c(0.9f, 0.9f, 0.9f);
if (actor == m_rayActor && actor->overlap)
{
c.Set(0.9f, 0.6f, 0.6f);
}
else if (actor == m_rayActor)
{
c.Set(0.6f, 0.9f, 0.6f);
}
else if (actor->overlap)
{
c.Set(0.6f, 0.6f, 0.9f);
}
m_debugDraw.DrawAABB(&actor->aabb, c);
}
b2Color c(0.7f, 0.7f, 0.7f);
m_debugDraw.DrawAABB(&m_queryAABB, c);
m_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c);
b2Color c1(0.2f, 0.9f, 0.2f);
b2Color c2(0.9f, 0.2f, 0.2f);
m_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1);
m_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2);
if (m_rayActor)
{
b2Color cr(0.2f, 0.2f, 0.9f);
b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1);
m_debugDraw.DrawPoint(p, 6.0f, cr);
}
{
int32 height = m_tree.GetHeight();
m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height);
m_textLine += 15;
}
++m_stepCount;
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
m_automated = !m_automated;
break;
case 'c':
CreateProxy();
break;
case 'd':
DestroyProxy();
break;
case 'm':
MoveProxy();
break;
}
}
bool QueryCallback(int32 proxyId)
{
Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb);
return true;
}
float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId)
{
Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
b2RayCastOutput output;
bool hit = actor->aabb.RayCast(&output, input);
if (hit)
{
m_rayCastOutput = output;
m_rayActor = actor;
m_rayActor->fraction = output.fraction;
return output.fraction;
}
return input.maxFraction;
}
private:
struct Actor
{
b2AABB aabb;
float32 fraction;
bool overlap;
int32 proxyId;
};
void GetRandomAABB(b2AABB* aabb)
{
b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent);
//aabb->lowerBound.x = -m_proxyExtent;
//aabb->lowerBound.y = -m_proxyExtent + m_worldExtent;
aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent);
aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent);
aabb->upperBound = aabb->lowerBound + w;
}
void MoveAABB(b2AABB* aabb)
{
b2Vec2 d;
d.x = RandomFloat(-0.5f, 0.5f);
d.y = RandomFloat(-0.5f, 0.5f);
//d.x = 2.0f;
//d.y = 0.0f;
aabb->lowerBound += d;
aabb->upperBound += d;
b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound);
b2Vec2 min; min.Set(-m_worldExtent, 0.0f);
b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent);
b2Vec2 c = b2Clamp(c0, min, max);
aabb->lowerBound += c - c0;
aabb->upperBound += c - c0;
}
void CreateProxy()
{
for (int32 i = 0; i < e_actorCount; ++i)
{
int32 j = rand() % e_actorCount;
Actor* actor = m_actors + j;
if (actor->proxyId == b2_nullNode)
{
GetRandomAABB(&actor->aabb);
actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
return;
}
}
}
void DestroyProxy()
{
for (int32 i = 0; i < e_actorCount; ++i)
{
int32 j = rand() % e_actorCount;
Actor* actor = m_actors + j;
if (actor->proxyId != b2_nullNode)
{
m_tree.DestroyProxy(actor->proxyId);
actor->proxyId = b2_nullNode;
return;
}
}
}
void MoveProxy()
{
for (int32 i = 0; i < e_actorCount; ++i)
{
int32 j = rand() % e_actorCount;
Actor* actor = m_actors + j;
if (actor->proxyId == b2_nullNode)
{
continue;
}
b2AABB aabb0 = actor->aabb;
MoveAABB(&actor->aabb);
b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter();
m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement);
return;
}
}
void Action()
{
int32 choice = rand() % 20;
switch (choice)
{
case 0:
CreateProxy();
break;
case 1:
DestroyProxy();
break;
default:
MoveProxy();
}
}
void Query()
{
m_tree.Query(this, m_queryAABB);
for (int32 i = 0; i < e_actorCount; ++i)
{
if (m_actors[i].proxyId == b2_nullNode)
{
continue;
}
bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb);
B2_NOT_USED(overlap);
b2Assert(overlap == m_actors[i].overlap);
}
}
void RayCast()
{
m_rayActor = NULL;
b2RayCastInput input = m_rayCastInput;
// Ray cast against the dynamic tree.
m_tree.RayCast(this, input);
// Brute force ray cast.
Actor* bruteActor = NULL;
b2RayCastOutput bruteOutput;
for (int32 i = 0; i < e_actorCount; ++i)
{
if (m_actors[i].proxyId == b2_nullNode)
{
continue;
}
b2RayCastOutput output;
bool hit = m_actors[i].aabb.RayCast(&output, input);
if (hit)
{
bruteActor = m_actors + i;
bruteOutput = output;
input.maxFraction = output.fraction;
}
}
if (bruteActor != NULL)
{
b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction);
}
}
float32 m_worldExtent;
float32 m_proxyExtent;
b2DynamicTree m_tree;
b2AABB m_queryAABB;
b2RayCastInput m_rayCastInput;
b2RayCastOutput m_rayCastOutput;
Actor* m_rayActor;
Actor m_actors[e_actorCount];
int32 m_stepCount;
bool m_automated;
};
#endif

View File

@ -1,249 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef EDGE_SHAPES_H
#define EDGE_SHAPES_H
class EdgeShapesCallback : public b2RayCastCallback
{
public:
EdgeShapesCallback()
{
m_fixture = NULL;
}
float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction)
{
m_fixture = fixture;
m_point = point;
m_normal = normal;
return fraction;
}
b2Fixture* m_fixture;
b2Vec2 m_point;
b2Vec2 m_normal;
};
class EdgeShapes : public Test
{
public:
enum
{
e_maxBodies = 256
};
EdgeShapes()
{
// Ground body
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
float32 x1 = -20.0f;
float32 y1 = 2.0f * cosf(x1 / 10.0f * b2_pi);
for (int32 i = 0; i < 80; ++i)
{
float32 x2 = x1 + 0.5f;
float32 y2 = 2.0f * cosf(x2 / 10.0f * b2_pi);
b2EdgeShape shape;
shape.Set(b2Vec2(x1, y1), b2Vec2(x2, y2));
ground->CreateFixture(&shape, 0.0f);
x1 = x2;
y1 = y2;
}
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[0].Set(vertices, 3);
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.1f, 0.0f);
vertices[1].Set(0.1f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[1].Set(vertices, 3);
}
{
float32 w = 1.0f;
float32 b = w / (2.0f + b2Sqrt(2.0f));
float32 s = b2Sqrt(2.0f) * b;
b2Vec2 vertices[8];
vertices[0].Set(0.5f * s, 0.0f);
vertices[1].Set(0.5f * w, b);
vertices[2].Set(0.5f * w, b + s);
vertices[3].Set(0.5f * s, w);
vertices[4].Set(-0.5f * s, w);
vertices[5].Set(-0.5f * w, b + s);
vertices[6].Set(-0.5f * w, b);
vertices[7].Set(-0.5f * s, 0.0f);
m_polygons[2].Set(vertices, 8);
}
{
m_polygons[3].SetAsBox(0.5f, 0.5f);
}
{
m_circle.m_radius = 0.5f;
}
m_bodyIndex = 0;
memset(m_bodies, 0, sizeof(m_bodies));
m_angle = 0.0f;
}
void Create(int32 index)
{
if (m_bodies[m_bodyIndex] != NULL)
{
m_world->DestroyBody(m_bodies[m_bodyIndex]);
m_bodies[m_bodyIndex] = NULL;
}
b2BodyDef bd;
float32 x = RandomFloat(-10.0f, 10.0f);
float32 y = RandomFloat(10.0f, 20.0f);
bd.position.Set(x, y);
bd.angle = RandomFloat(-b2_pi, b2_pi);
bd.type = b2_dynamicBody;
if (index == 4)
{
bd.angularDamping = 0.02f;
}
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
if (index < 4)
{
b2FixtureDef fd;
fd.shape = m_polygons + index;
fd.friction = 0.3f;
fd.density = 20.0f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
else
{
b2FixtureDef fd;
fd.shape = &m_circle;
fd.friction = 0.3f;
fd.density = 20.0f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
}
void DestroyBody()
{
for (int32 i = 0; i < e_maxBodies; ++i)
{
if (m_bodies[i] != NULL)
{
m_world->DestroyBody(m_bodies[i]);
m_bodies[i] = NULL;
return;
}
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case '1':
case '2':
case '3':
case '4':
case '5':
Create(key - '1');
break;
case 'd':
DestroyBody();
break;
}
}
void Step(Settings* settings)
{
bool advanceRay = settings->pause == 0 || settings->singleStep;
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
m_textLine += 15;
float32 L = 25.0f;
b2Vec2 point1(0.0f, 10.0f);
b2Vec2 d(L * cosf(m_angle), -L * b2Abs(sinf(m_angle)));
b2Vec2 point2 = point1 + d;
EdgeShapesCallback callback;
m_world->RayCast(&callback, point1, point2);
if (callback.m_fixture)
{
m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
}
else
{
m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
}
if (advanceRay)
{
m_angle += 0.25f * b2_pi / 180.0f;
}
}
static Test* Create()
{
return new EdgeShapes;
}
int32 m_bodyIndex;
b2Body* m_bodies[e_maxBodies];
b2PolygonShape m_polygons[4];
b2CircleShape m_circle;
float32 m_angle;
};
#endif

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef EDGE_TEST_H
#define EDGE_TEST_H
class EdgeTest : public Test
{
public:
EdgeTest()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2Vec2 v1(-10.0f, 0.0f), v2(-7.0f, -2.0f), v3(-4.0f, 0.0f);
b2Vec2 v4(0.0f, 0.0f), v5(4.0f, 0.0f), v6(7.0f, 2.0f), v7(10.0f, 0.0f);
b2EdgeShape shape;
shape.Set(v1, v2);
shape.m_hasVertex3 = true;
shape.m_vertex3 = v3;
ground->CreateFixture(&shape, 0.0f);
shape.Set(v2, v3);
shape.m_hasVertex0 = true;
shape.m_hasVertex3 = true;
shape.m_vertex0 = v1;
shape.m_vertex3 = v4;
ground->CreateFixture(&shape, 0.0f);
shape.Set(v3, v4);
shape.m_hasVertex0 = true;
shape.m_hasVertex3 = true;
shape.m_vertex0 = v2;
shape.m_vertex3 = v5;
ground->CreateFixture(&shape, 0.0f);
shape.Set(v4, v5);
shape.m_hasVertex0 = true;
shape.m_hasVertex3 = true;
shape.m_vertex0 = v3;
shape.m_vertex3 = v6;
ground->CreateFixture(&shape, 0.0f);
shape.Set(v5, v6);
shape.m_hasVertex0 = true;
shape.m_hasVertex3 = true;
shape.m_vertex0 = v4;
shape.m_vertex3 = v7;
ground->CreateFixture(&shape, 0.0f);
shape.Set(v6, v7);
shape.m_hasVertex0 = true;
shape.m_vertex0 = v5;
ground->CreateFixture(&shape, 0.0f);
}
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-0.5f, 0.6f);
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
b2CircleShape shape;
shape.m_radius = 0.5f;
body->CreateFixture(&shape, 1.0f);
}
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(1.0f, 0.6f);
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
body->CreateFixture(&shape, 1.0f);
}
}
static Test* Create()
{
return new EdgeTest;
}
};
#endif

View File

@ -1,187 +0,0 @@
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef GEARS_H
#define GEARS_H
class Gears : public Test
{
public:
Gears()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Gears co
{
b2CircleShape circle1;
circle1.m_radius = 1.0f;
b2PolygonShape box;
box.SetAsBox(0.5f, 5.0f);
b2CircleShape circle2;
circle2.m_radius = 2.0f;
b2BodyDef bd1;
bd1.type = b2_staticBody;
bd1.position.Set(10.0f, 9.0f);
b2Body* body1 = m_world->CreateBody(&bd1);
body1->CreateFixture(&circle1, 0.0f);
b2BodyDef bd2;
bd2.type = b2_dynamicBody;
bd2.position.Set(10.0f, 8.0f);
b2Body* body2 = m_world->CreateBody(&bd2);
body2->CreateFixture(&box, 5.0f);
b2BodyDef bd3;
bd3.type = b2_dynamicBody;
bd3.position.Set(10.0f, 6.0f);
b2Body* body3 = m_world->CreateBody(&bd3);
body3->CreateFixture(&circle2, 5.0f);
b2RevoluteJointDef jd1;
jd1.Initialize(body2, body1, bd1.position);
b2Joint* joint1 = m_world->CreateJoint(&jd1);
b2RevoluteJointDef jd2;
jd2.Initialize(body2, body3, bd3.position);
b2Joint* joint2 = m_world->CreateJoint(&jd2);
b2GearJointDef jd4;
jd4.bodyA = body1;
jd4.bodyB = body3;
jd4.joint1 = joint1;
jd4.joint2 = joint2;
jd4.ratio = circle2.m_radius / circle1.m_radius;
m_world->CreateJoint(&jd4);
}
{
b2CircleShape circle1;
circle1.m_radius = 1.0f;
b2CircleShape circle2;
circle2.m_radius = 2.0f;
b2PolygonShape box;
box.SetAsBox(0.5f, 5.0f);
b2BodyDef bd1;
bd1.type = b2_dynamicBody;
bd1.position.Set(-3.0f, 12.0f);
b2Body* body1 = m_world->CreateBody(&bd1);
body1->CreateFixture(&circle1, 5.0f);
b2RevoluteJointDef jd1;
jd1.bodyA = ground;
jd1.bodyB = body1;
jd1.localAnchorA = ground->GetLocalPoint(bd1.position);
jd1.localAnchorB = body1->GetLocalPoint(bd1.position);
jd1.referenceAngle = body1->GetAngle() - ground->GetAngle();
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1);
b2BodyDef bd2;
bd2.type = b2_dynamicBody;
bd2.position.Set(0.0f, 12.0f);
b2Body* body2 = m_world->CreateBody(&bd2);
body2->CreateFixture(&circle2, 5.0f);
b2RevoluteJointDef jd2;
jd2.Initialize(ground, body2, bd2.position);
m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2);
b2BodyDef bd3;
bd3.type = b2_dynamicBody;
bd3.position.Set(2.5f, 12.0f);
b2Body* body3 = m_world->CreateBody(&bd3);
body3->CreateFixture(&box, 5.0f);
b2PrismaticJointDef jd3;
jd3.Initialize(ground, body3, bd3.position, b2Vec2(0.0f, 1.0f));
jd3.lowerTranslation = -5.0f;
jd3.upperTranslation = 5.0f;
jd3.enableLimit = true;
m_joint3 = (b2PrismaticJoint*)m_world->CreateJoint(&jd3);
b2GearJointDef jd4;
jd4.bodyA = body1;
jd4.bodyB = body2;
jd4.joint1 = m_joint1;
jd4.joint2 = m_joint2;
jd4.ratio = circle2.m_radius / circle1.m_radius;
m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4);
b2GearJointDef jd5;
jd5.bodyA = body2;
jd5.bodyB = body3;
jd5.joint1 = m_joint2;
jd5.joint2 = m_joint3;
jd5.ratio = -1.0f / circle2.m_radius;
m_joint5 = (b2GearJoint*)m_world->CreateJoint(&jd5);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 0:
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
float32 ratio, value;
ratio = m_joint4->GetRatio();
value = m_joint1->GetJointAngle() + ratio * m_joint2->GetJointAngle();
m_debugDraw.DrawString(5, m_textLine, "theta1 + %4.2f * theta2 = %4.2f", (float) ratio, (float) value);
m_textLine += 15;
ratio = m_joint5->GetRatio();
value = m_joint2->GetJointAngle() + ratio * m_joint3->GetJointTranslation();
m_debugDraw.DrawString(5, m_textLine, "theta2 + %4.2f * delta = %4.2f", (float) ratio, (float) value);
m_textLine += 15;
}
static Test* Create()
{
return new Gears;
}
b2RevoluteJoint* m_joint1;
b2RevoluteJoint* m_joint2;
b2PrismaticJoint* m_joint3;
b2GearJoint* m_joint4;
b2GearJoint* m_joint5;
};
#endif

View File

@ -1,120 +0,0 @@
/*
* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ONE_SIDED_PLATFORM_H
#define ONE_SIDED_PLATFORM_H
class OneSidedPlatform : public Test
{
public:
enum State
{
e_unknown,
e_above,
e_below
};
OneSidedPlatform()
{
// Ground
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Platform
{
b2BodyDef bd;
bd.position.Set(0.0f, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(3.0f, 0.5f);
m_platform = body->CreateFixture(&shape, 0.0f);
m_bottom = 10.0f - 0.5f;
m_top = 10.0f + 0.5f;
}
// Actor
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 12.0f);
b2Body* body = m_world->CreateBody(&bd);
m_radius = 0.5f;
b2CircleShape shape;
shape.m_radius = m_radius;
m_character = body->CreateFixture(&shape, 20.0f);
body->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
m_state = e_unknown;
}
}
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
{
Test::PreSolve(contact, oldManifold);
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
if (fixtureA != m_platform && fixtureA != m_character)
{
return;
}
if (fixtureB != m_platform && fixtureB != m_character)
{
return;
}
b2Vec2 position = m_character->GetBody()->GetPosition();
if (position.y < m_top + m_radius - 3.0f * b2_linearSlop)
{
contact->SetEnabled(false);
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");
m_textLine += 15;
}
static Test* Create()
{
return new OneSidedPlatform;
}
float32 m_radius, m_top, m_bottom;
State m_state;
b2Fixture* m_platform;
b2Fixture* m_character;
};
#endif

View File

@ -1,169 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef PINBALL_H
#define PINBALL_H
/// This tests bullet collision and provides an example of a gameplay scenario.
/// This also uses a loop shape.
class Pinball : public Test
{
public:
Pinball()
{
// Ground body
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2Vec2 vs[5];
vs[0].Set(0.0f, -2.0f);
vs[1].Set(8.0f, 6.0f);
vs[2].Set(8.0f, 20.0f);
vs[3].Set(-8.0f, 20.0f);
vs[4].Set(-8.0f, 6.0f);
b2ChainShape loop;
loop.CreateLoop(vs, 5);
b2FixtureDef fd;
fd.shape = &loop;
fd.density = 0.0f;
ground->CreateFixture(&fd);
}
// Flippers
{
b2Vec2 p1(-2.0f, 0.0f), p2(2.0f, 0.0f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = p1;
b2Body* leftFlipper = m_world->CreateBody(&bd);
bd.position = p2;
b2Body* rightFlipper = m_world->CreateBody(&bd);
b2PolygonShape box;
box.SetAsBox(1.75f, 0.1f);
b2FixtureDef fd;
fd.shape = &box;
fd.density = 1.0f;
leftFlipper->CreateFixture(&fd);
rightFlipper->CreateFixture(&fd);
b2RevoluteJointDef jd;
jd.bodyA = ground;
jd.localAnchorB.SetZero();
jd.enableMotor = true;
jd.maxMotorTorque = 1000.0f;
jd.enableLimit = true;
jd.motorSpeed = 0.0f;
jd.localAnchorA = p1;
jd.bodyB = leftFlipper;
jd.lowerAngle = -30.0f * b2_pi / 180.0f;
jd.upperAngle = 5.0f * b2_pi / 180.0f;
m_leftJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
jd.motorSpeed = 0.0f;
jd.localAnchorA = p2;
jd.bodyB = rightFlipper;
jd.lowerAngle = -5.0f * b2_pi / 180.0f;
jd.upperAngle = 30.0f * b2_pi / 180.0f;
m_rightJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
}
// Circle character
{
b2BodyDef bd;
bd.position.Set(1.0f, 15.0f);
bd.type = b2_dynamicBody;
bd.bullet = true;
m_ball = m_world->CreateBody(&bd);
b2CircleShape shape;
shape.m_radius = 0.2f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
m_ball->CreateFixture(&fd);
}
m_button = false;
}
void Step()
{
if (m_button)
{
m_leftJoint->SetMotorSpeed(20.0f);
m_rightJoint->SetMotorSpeed(-20.0f);
}
else
{
m_leftJoint->SetMotorSpeed(-10.0f);
m_rightJoint->SetMotorSpeed(10.0f);
}
// Test::Step(settings);
//
// m_debugDraw.DrawString(5, m_textLine, "Press 'a' to control the flippers");
// m_textLine += 15;
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
case 'A':
m_button = true;
break;
}
}
void KeyboardUp(unsigned char key)
{
switch (key)
{
case 'a':
case 'A':
m_button = false;
break;
}
}
static Test* Create()
{
return new Pinball;
}
b2RevoluteJoint* m_leftJoint;
b2RevoluteJoint* m_rightJoint;
b2Body* m_ball;
bool m_button;
};
#endif

View File

@ -1,122 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef POLYCOLLISION_H
#define POLYCOLLISION_H
class PolyCollision : public Test
{
public:
PolyCollision()
{
{
m_polygonA.SetAsBox(0.2f, 0.4f);
m_transformA.Set(b2Vec2(0.0f, 0.0f), 0.0f);
}
{
m_polygonB.SetAsBox(0.5f, 0.5f);
m_positionB.Set(19.345284f, 1.5632932f);
m_angleB = 1.9160721f;
m_transformB.Set(m_positionB, m_angleB);
}
}
static Test* Create()
{
return new PolyCollision;
}
void Step(Settings* settings)
{
B2_NOT_USED(settings);
b2Manifold manifold;
b2CollidePolygons(&manifold, &m_polygonA, m_transformA, &m_polygonB, m_transformB);
b2WorldManifold worldManifold;
worldManifold.Initialize(&manifold, m_transformA, m_polygonA.m_radius, m_transformB, m_polygonB.m_radius);
m_debugDraw.DrawString(5, m_textLine, "point count = %d", manifold.pointCount);
m_textLine += 15;
{
b2Color color(0.9f, 0.9f, 0.9f);
b2Vec2 v[b2_maxPolygonVertices];
for (int32 i = 0; i < m_polygonA.m_vertexCount; ++i)
{
v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
}
m_debugDraw.DrawPolygon(v, m_polygonA.m_vertexCount, color);
for (int32 i = 0; i < m_polygonB.m_vertexCount; ++i)
{
v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(v, m_polygonB.m_vertexCount, color);
}
for (int32 i = 0; i < manifold.pointCount; ++i)
{
m_debugDraw.DrawPoint(worldManifold.points[i], 4.0f, b2Color(0.9f, 0.3f, 0.3f));
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
m_positionB.x -= 0.1f;
break;
case 'd':
m_positionB.x += 0.1f;
break;
case 's':
m_positionB.y -= 0.1f;
break;
case 'w':
m_positionB.y += 0.1f;
break;
case 'q':
m_angleB += 0.1f * b2_pi;
break;
case 'e':
m_angleB -= 0.1f * b2_pi;
break;
}
m_transformB.Set(m_positionB, m_angleB);
}
b2PolygonShape m_polygonA;
b2PolygonShape m_polygonB;
b2Transform m_transformA;
b2Transform m_transformB;
b2Vec2 m_positionB;
float32 m_angleB;
};
#endif

View File

@ -1,295 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef POLY_SHAPES_H
#define POLY_SHAPES_H
/// This tests stacking. It also shows how to use b2World::Query
/// and b2TestOverlap.
const int32 k_maxBodies = 256;
/// This callback is called by b2World::QueryAABB. We find all the fixtures
/// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures
/// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border.
class PolyShapesCallback : public b2QueryCallback
{
public:
enum
{
e_maxCount = 4
};
PolyShapesCallback()
{
m_count = 0;
}
void DrawFixture(b2Fixture* fixture)
{
b2Color color(0.95f, 0.95f, 0.6f);
const b2Transform& xf = fixture->GetBody()->GetTransform();
switch (fixture->GetType())
{
case b2Shape::e_circle:
{
b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
b2Vec2 center = b2Mul(xf, circle->m_p);
float32 radius = circle->m_radius;
m_debugDraw->DrawCircle(center, radius, color);
}
break;
case b2Shape::e_polygon:
{
b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
int32 vertexCount = poly->m_vertexCount;
b2Assert(vertexCount <= b2_maxPolygonVertices);
b2Vec2 vertices[b2_maxPolygonVertices];
for (int32 i = 0; i < vertexCount; ++i)
{
vertices[i] = b2Mul(xf, poly->m_vertices[i]);
}
m_debugDraw->DrawPolygon(vertices, vertexCount, color);
}
break;
default:
break;
}
}
/// Called for each fixture found in the query AABB.
/// @return false to terminate the query.
bool ReportFixture(b2Fixture* fixture)
{
if (m_count == e_maxCount)
{
return false;
}
b2Body* body = fixture->GetBody();
b2Shape* shape = fixture->GetShape();
bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform);
if (overlap)
{
DrawFixture(fixture);
++m_count;
}
return true;
}
b2CircleShape m_circle;
b2Transform m_transform;
b2Draw* m_debugDraw;
int32 m_count;
};
class PolyShapes : public Test
{
public:
PolyShapes()
{
// Ground body
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[0].Set(vertices, 3);
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.1f, 0.0f);
vertices[1].Set(0.1f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[1].Set(vertices, 3);
}
{
float32 w = 1.0f;
float32 b = w / (2.0f + b2Sqrt(2.0f));
float32 s = b2Sqrt(2.0f) * b;
b2Vec2 vertices[8];
vertices[0].Set(0.5f * s, 0.0f);
vertices[1].Set(0.5f * w, b);
vertices[2].Set(0.5f * w, b + s);
vertices[3].Set(0.5f * s, w);
vertices[4].Set(-0.5f * s, w);
vertices[5].Set(-0.5f * w, b + s);
vertices[6].Set(-0.5f * w, b);
vertices[7].Set(-0.5f * s, 0.0f);
m_polygons[2].Set(vertices, 8);
}
{
m_polygons[3].SetAsBox(0.5f, 0.5f);
}
{
m_circle.m_radius = 0.5f;
}
m_bodyIndex = 0;
memset(m_bodies, 0, sizeof(m_bodies));
}
void Create(int32 index)
{
if (m_bodies[m_bodyIndex] != NULL)
{
m_world->DestroyBody(m_bodies[m_bodyIndex]);
m_bodies[m_bodyIndex] = NULL;
}
b2BodyDef bd;
bd.type = b2_dynamicBody;
float32 x = RandomFloat(-2.0f, 2.0f);
bd.position.Set(x, 10.0f);
bd.angle = RandomFloat(-b2_pi, b2_pi);
if (index == 4)
{
bd.angularDamping = 0.02f;
}
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
if (index < 4)
{
b2FixtureDef fd;
fd.shape = m_polygons + index;
fd.density = 1.0f;
fd.friction = 0.3f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
else
{
b2FixtureDef fd;
fd.shape = &m_circle;
fd.density = 1.0f;
fd.friction = 0.3f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
m_bodyIndex = (m_bodyIndex + 1) % k_maxBodies;
}
void DestroyBody()
{
for (int32 i = 0; i < k_maxBodies; ++i)
{
if (m_bodies[i] != NULL)
{
m_world->DestroyBody(m_bodies[i]);
m_bodies[i] = NULL;
return;
}
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case '1':
case '2':
case '3':
case '4':
case '5':
Create(key - '1');
break;
case 'a':
for (int32 i = 0; i < k_maxBodies; i += 2)
{
if (m_bodies[i])
{
bool active = m_bodies[i]->IsActive();
m_bodies[i]->SetActive(!active);
}
}
break;
case 'd':
DestroyBody();
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
PolyShapesCallback callback;
callback.m_circle.m_radius = 2.0f;
callback.m_circle.m_p.Set(0.0f, 1.1f);
callback.m_transform.SetIdentity();
callback.m_debugDraw = &m_debugDraw;
b2AABB aabb;
callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0);
m_world->QueryAABB(&callback, aabb);
b2Color color(0.4f, 0.7f, 0.8f);
m_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color);
m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Press 'a' to (de)activate some bodies");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body");
m_textLine += 15;
}
static Test* Create()
{
return new PolyShapes;
}
int32 m_bodyIndex;
b2Body* m_bodies[k_maxBodies];
b2PolygonShape m_polygons[4];
b2CircleShape m_circle;
};
#endif

View File

@ -1,107 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef PRISMATIC_H
#define PRISMATIC_H
// The motor in this test gets smoother with higher velocity iterations.
class Prismatic : public Test
{
public:
Prismatic()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(2.0f, 0.5f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-10.0f, 10.0f);
bd.angle = 0.5f * b2_pi;
bd.allowSleep = false;
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 5.0f);
b2PrismaticJointDef pjd;
// Bouncy limit
b2Vec2 axis(2.0f, 1.0f);
axis.Normalize();
pjd.Initialize(ground, body, b2Vec2(0.0f, 0.0f), axis);
// Non-bouncy limit
//pjd.Initialize(ground, body, b2Vec2(-10.0f, 10.0f), b2Vec2(1.0f, 0.0f));
pjd.motorSpeed = 10.0f;
pjd.maxMotorForce = 10000.0f;
pjd.enableMotor = true;
pjd.lowerTranslation = 0.0f;
pjd.upperTranslation = 20.0f;
pjd.enableLimit = true;
m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'l':
m_joint->EnableLimit(!m_joint->IsLimitEnabled());
break;
case 'm':
m_joint->EnableMotor(!m_joint->IsMotorEnabled());
break;
case 's':
m_joint->SetMotorSpeed(-m_joint->GetMotorSpeed());
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motors, (s) speed");
m_textLine += 15;
float32 force = m_joint->GetMotorForce(settings->hz);
m_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", (float) force);
m_textLine += 15;
}
static Test* Create()
{
return new Prismatic;
}
b2PrismaticJoint* m_joint;
};
#endif

View File

@ -1,106 +0,0 @@
/*
* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef PULLEYS_H
#define PULLEYS_H
class Pulleys : public Test
{
public:
Pulleys()
{
float32 y = 16.0f;
float32 L = 12.0f;
float32 a = 1.0f;
float32 b = 2.0f;
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape edge;
edge.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
//ground->CreateFixture(&shape, 0.0f);
b2CircleShape circle;
circle.m_radius = 2.0f;
circle.m_p.Set(-10.0f, y + b + L);
ground->CreateFixture(&circle, 0.0f);
circle.m_p.Set(10.0f, y + b + L);
ground->CreateFixture(&circle, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(a, b);
b2BodyDef bd;
bd.type = b2_dynamicBody;
//bd.fixedRotation = true;
bd.position.Set(-10.0f, y);
b2Body* body1 = m_world->CreateBody(&bd);
body1->CreateFixture(&shape, 5.0f);
bd.position.Set(10.0f, y);
b2Body* body2 = m_world->CreateBody(&bd);
body2->CreateFixture(&shape, 5.0f);
b2PulleyJointDef pulleyDef;
b2Vec2 anchor1(-10.0f, y + b);
b2Vec2 anchor2(10.0f, y + b);
b2Vec2 groundAnchor1(-10.0f, y + b + L);
b2Vec2 groundAnchor2(10.0f, y + b + L);
pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5f);
m_joint1 = (b2PulleyJoint*)m_world->CreateJoint(&pulleyDef);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 0:
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
float32 ratio = m_joint1->GetRatio();
float32 L = m_joint1->GetLengthA() + ratio * m_joint1->GetLengthB();
m_debugDraw.DrawString(5, m_textLine, "L1 + %4.2f * L2 = %4.2f", (float) ratio, (float) L);
m_textLine += 15;
}
static Test* Create()
{
return new Pulleys;
}
b2PulleyJoint* m_joint1;
};
#endif

View File

@ -1,89 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef PYRAMID_H
#define PYRAMID_H
class Pyramid : public Test
{
public:
enum
{
e_count = 20
};
Pyramid()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
float32 a = 0.5f;
b2PolygonShape shape;
shape.SetAsBox(a, a);
b2Vec2 x(-7.0f, 0.75f);
b2Vec2 y;
b2Vec2 deltaX(0.5625f, 1.25f);
b2Vec2 deltaY(1.125f, 0.0f);
for (int32 i = 0; i < e_count; ++i)
{
y = x;
for (int32 j = i; j < e_count; ++j)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = y;
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 5.0f);
y += deltaY;
}
x += deltaX;
}
}
}
void Step(Settings* settings)
{
Test::Step(settings);
//b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
//if (m_stepCount == 400)
//{
// tree->RebuildBottomUp();
//}
}
static Test* Create()
{
return new Pyramid;
}
};
#endif

View File

@ -1,440 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef RAY_CAST_H
#define RAY_CAST_H
// This test demonstrates how to use the world ray-cast feature.
// NOTE: we are intentionally filtering one of the polygons, therefore
// the ray will always miss one type of polygon.
// This callback finds the closest hit. Polygon 0 is filtered.
class RayCastClosestCallback : public b2RayCastCallback
{
public:
RayCastClosestCallback()
{
m_hit = false;
}
float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction)
{
b2Body* body = fixture->GetBody();
void* userData = body->GetUserData();
if (userData)
{
int32 index = *(int32*)userData;
if (index == 0)
{
// filter
return -1.0f;
}
}
m_hit = true;
m_point = point;
m_normal = normal;
return fraction;
}
bool m_hit;
b2Vec2 m_point;
b2Vec2 m_normal;
};
// This callback finds any hit. Polygon 0 is filtered.
class RayCastAnyCallback : public b2RayCastCallback
{
public:
RayCastAnyCallback()
{
m_hit = false;
}
float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction)
{
b2Body* body = fixture->GetBody();
void* userData = body->GetUserData();
if (userData)
{
int32 index = *(int32*)userData;
if (index == 0)
{
// filter
return -1.0f;
}
}
m_hit = true;
m_point = point;
m_normal = normal;
return 0.0f;
}
bool m_hit;
b2Vec2 m_point;
b2Vec2 m_normal;
};
// This ray cast collects multiple hits along the ray. Polygon 0 is filtered.
class RayCastMultipleCallback : public b2RayCastCallback
{
public:
enum
{
e_maxCount = 3
};
RayCastMultipleCallback()
{
m_count = 0;
}
float32 ReportFixture( b2Fixture* fixture, const b2Vec2& point,
const b2Vec2& normal, float32 fraction)
{
b2Body* body = fixture->GetBody();
void* userData = body->GetUserData();
if (userData)
{
int32 index = *(int32*)userData;
if (index == 0)
{
// filter
return -1.0f;
}
}
b2Assert(m_count < e_maxCount);
m_points[m_count] = point;
m_normals[m_count] = normal;
++m_count;
if (m_count == e_maxCount)
{
return 0.0f;
}
return 1.0f;
}
b2Vec2 m_points[e_maxCount];
b2Vec2 m_normals[e_maxCount];
int32 m_count;
};
class RayCast : public Test
{
public:
enum
{
e_maxBodies = 256
};
enum Mode
{
e_closest,
e_any,
e_multiple
};
RayCast()
{
// Ground body
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.5f, 0.0f);
vertices[1].Set(0.5f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[0].Set(vertices, 3);
}
{
b2Vec2 vertices[3];
vertices[0].Set(-0.1f, 0.0f);
vertices[1].Set(0.1f, 0.0f);
vertices[2].Set(0.0f, 1.5f);
m_polygons[1].Set(vertices, 3);
}
{
float32 w = 1.0f;
float32 b = w / (2.0f + b2Sqrt(2.0f));
float32 s = b2Sqrt(2.0f) * b;
b2Vec2 vertices[8];
vertices[0].Set(0.5f * s, 0.0f);
vertices[1].Set(0.5f * w, b);
vertices[2].Set(0.5f * w, b + s);
vertices[3].Set(0.5f * s, w);
vertices[4].Set(-0.5f * s, w);
vertices[5].Set(-0.5f * w, b + s);
vertices[6].Set(-0.5f * w, b);
vertices[7].Set(-0.5f * s, 0.0f);
m_polygons[2].Set(vertices, 8);
}
{
m_polygons[3].SetAsBox(0.5f, 0.5f);
}
{
m_circle.m_radius = 0.5f;
}
m_bodyIndex = 0;
memset(m_bodies, 0, sizeof(m_bodies));
m_angle = 0.0f;
m_mode = e_closest;
}
void Create(int32 index)
{
if (m_bodies[m_bodyIndex] != NULL)
{
m_world->DestroyBody(m_bodies[m_bodyIndex]);
m_bodies[m_bodyIndex] = NULL;
}
b2BodyDef bd;
float32 x = RandomFloat(-10.0f, 10.0f);
float32 y = RandomFloat(0.0f, 20.0f);
bd.position.Set(x, y);
bd.angle = RandomFloat(-b2_pi, b2_pi);
m_userData[m_bodyIndex] = index;
bd.userData = m_userData + m_bodyIndex;
if (index == 4)
{
bd.angularDamping = 0.02f;
}
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
if (index < 4)
{
b2FixtureDef fd;
fd.shape = m_polygons + index;
fd.friction = 0.3f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
else
{
b2FixtureDef fd;
fd.shape = &m_circle;
fd.friction = 0.3f;
m_bodies[m_bodyIndex]->CreateFixture(&fd);
}
m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
}
void DestroyBody()
{
for (int32 i = 0; i < e_maxBodies; ++i)
{
if (m_bodies[i] != NULL)
{
m_world->DestroyBody(m_bodies[i]);
m_bodies[i] = NULL;
return;
}
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case '1':
case '2':
case '3':
case '4':
case '5':
Create(key - '1');
break;
case 'd':
DestroyBody();
break;
case 'm':
if (m_mode == e_closest)
{
m_mode = e_any;
}
else if (m_mode == e_any)
{
m_mode = e_multiple;
}
else if (m_mode == e_multiple)
{
m_mode = e_closest;
}
}
}
void Step(Settings* settings)
{
bool advanceRay = settings->pause == 0 || settings->singleStep;
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, m to change the mode");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Mode = %d", m_mode);
m_textLine += 15;
float32 L = 11.0f;
b2Vec2 point1(0.0f, 10.0f);
b2Vec2 d(L * cosf(m_angle), L * sinf(m_angle));
b2Vec2 point2 = point1 + d;
if (m_mode == e_closest)
{
RayCastClosestCallback callback;
m_world->RayCast(&callback, point1, point2);
if (callback.m_hit)
{
m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
}
else
{
m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
}
}
else if (m_mode == e_any)
{
RayCastAnyCallback callback;
m_world->RayCast(&callback, point1, point2);
if (callback.m_hit)
{
m_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
m_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
m_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
}
else
{
m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
}
}
else if (m_mode == e_multiple)
{
RayCastMultipleCallback callback;
m_world->RayCast(&callback, point1, point2);
m_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
for (int32 i = 0; i < callback.m_count; ++i)
{
b2Vec2 p = callback.m_points[i];
b2Vec2 n = callback.m_normals[i];
m_debugDraw.DrawPoint(p, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
m_debugDraw.DrawSegment(point1, p, b2Color(0.8f, 0.8f, 0.8f));
b2Vec2 head = p + 0.5f * n;
m_debugDraw.DrawSegment(p, head, b2Color(0.9f, 0.9f, 0.4f));
}
}
if (advanceRay)
{
m_angle += 0.25f * b2_pi / 180.0f;
}
#if 0
// This case was failing.
{
b2Vec2 vertices[4];
//vertices[0].Set(-22.875f, -3.0f);
//vertices[1].Set(22.875f, -3.0f);
//vertices[2].Set(22.875f, 3.0f);
//vertices[3].Set(-22.875f, 3.0f);
b2PolygonShape shape;
//shape.Set(vertices, 4);
shape.SetAsBox(22.875f, 3.0f);
b2RayCastInput input;
input.p1.Set(10.2725f,1.71372f);
input.p2.Set(10.2353f,2.21807f);
//input.maxFraction = 0.567623f;
input.maxFraction = 0.56762173f;
b2Transform xf;
xf.SetIdentity();
xf.position.Set(23.0f, 5.0f);
b2RayCastOutput output;
bool hit;
hit = shape.RayCast(&output, input, xf);
hit = false;
b2Color color(1.0f, 1.0f, 1.0f);
b2Vec2 vs[4];
for (int32 i = 0; i < 4; ++i)
{
vs[i] = b2Mul(xf, shape.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vs, 4, color);
m_debugDraw.DrawSegment(input.p1, input.p2, color);
}
#endif
}
static Test* Create()
{
return new RayCast;
}
int32 m_bodyIndex;
b2Body* m_bodies[e_maxBodies];
int32 m_userData[e_maxBodies];
b2PolygonShape m_polygons[4];
b2CircleShape m_circle;
float32 m_angle;
Mode m_mode;
};
#endif

View File

@ -1,166 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef REVOLUTE_H
#define REVOLUTE_H
class Revolute : public Test
{
public:
Revolute()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
b2FixtureDef fd;
fd.shape = &shape;
//fd.filter.categoryBits = 2;
ground->CreateFixture(&fd);
}
{
b2CircleShape shape;
shape.m_radius = 0.5f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
b2RevoluteJointDef rjd;
bd.position.Set(-10.0f, 20.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 5.0f);
float32 w = 100.0f;
body->SetAngularVelocity(w);
body->SetLinearVelocity(b2Vec2(-8.0f * w, 0.0f));
rjd.Initialize(ground, body, b2Vec2(-10.0f, 12.0f));
rjd.motorSpeed = 1.0f * b2_pi;
rjd.maxMotorTorque = 10000.0f;
rjd.enableMotor = false;
rjd.lowerAngle = -0.25f * b2_pi;
rjd.upperAngle = 0.5f * b2_pi;
rjd.enableLimit = true;
rjd.collideConnected = true;
m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);
}
{
b2CircleShape circle_shape;
circle_shape.m_radius = 3.0f;
b2BodyDef circle_bd;
circle_bd.type = b2_dynamicBody;
circle_bd.position.Set(5.0f, 30.0f);
b2FixtureDef fd;
fd.density = 5.0f;
fd.filter.maskBits = 1;
fd.shape = &circle_shape;
m_ball = m_world->CreateBody(&circle_bd);
m_ball->CreateFixture(&fd);
b2PolygonShape polygon_shape;
polygon_shape.SetAsBox(10.0f, 0.2f, b2Vec2 (-10.0f, 0.0f), 0.0f);
b2BodyDef polygon_bd;
polygon_bd.position.Set(20.0f, 10.0f);
polygon_bd.type = b2_dynamicBody;
polygon_bd.bullet = true;
b2Body* polygon_body = m_world->CreateBody(&polygon_bd);
polygon_body->CreateFixture(&polygon_shape, 2.0f);
b2RevoluteJointDef rjd;
rjd.Initialize(ground, polygon_body, b2Vec2(20.0f, 10.0f));
rjd.lowerAngle = -0.25f * b2_pi;
rjd.upperAngle = 0.0f * b2_pi;
rjd.enableLimit = true;
m_world->CreateJoint(&rjd);
}
// Tests mass computation of a small object far from the origin
{
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
b2Body* body = m_world->CreateBody(&bodyDef);
b2PolygonShape polyShape;
b2Vec2 verts[3];
verts[0].Set( 17.63f, 36.31f );
verts[1].Set( 17.52f, 36.69f );
verts[2].Set( 17.19f, 36.36f );
polyShape.Set(verts, 3);
b2FixtureDef polyFixtureDef;
polyFixtureDef.shape = &polyShape;
polyFixtureDef.density = 1;
body->CreateFixture(&polyFixtureDef); //assertion hits inside here
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'l':
m_joint->EnableLimit(!m_joint->IsLimitEnabled());
break;
case 'm':
m_joint->EnableMotor(!m_joint->IsMotorEnabled());
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Keys: (l) limits, (m) motor");
m_textLine += 15;
//if (m_stepCount == 360)
//{
// m_ball->SetTransform(b2Vec2(0.0f, 0.5f), 0.0f);
//}
//float32 torque1 = m_joint1->GetMotorTorque();
//m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %4.0f, %4.0f : Motor Force = %4.0f", (float) torque1, (float) torque2, (float) force3);
//m_textLine += 15;
}
static Test* Create()
{
return new Revolute;
}
b2Body* m_ball;
b2RevoluteJoint* m_joint;
};
#endif

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ROPE_H
#define ROPE_H
///
class Rope : public Test
{
public:
Rope()
{
const int32 N = 40;
b2Vec2 vertices[N];
float32 masses[N];
for (int32 i = 0; i < N; ++i)
{
vertices[i].Set(0.0f, 20.0f - 0.25f * i);
masses[i] = 1.0f;
}
masses[0] = 0.0f;
masses[1] = 0.0f;
b2RopeDef def;
def.vertices = vertices;
def.count = N;
def.gravity.Set(0.0f, -10.0f);
def.masses = masses;
def.damping = 0.1f;
def.k2 = 1.0f;
def.k3 = 0.5f;
m_rope.Initialize(&def);
m_angle = 0.0f;
m_rope.SetAngle(m_angle);
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'q':
m_angle = b2Max(-b2_pi, m_angle - 0.05f * b2_pi);
m_rope.SetAngle(m_angle);
break;
case 'e':
m_angle = b2Min(b2_pi, m_angle + 0.05f * b2_pi);
m_rope.SetAngle(m_angle);
break;
}
}
void Step(Settings* settings)
{
float32 dt = settings->hz > 0.0f ? 1.0f / settings->hz : 0.0f;
if (settings->pause == 1 && settings->singleStep == 0)
{
dt = 0.0f;
}
m_rope.Step(dt, 1);
Test::Step(settings);
m_rope.Draw(&m_debugDraw);
m_debugDraw.DrawString(5, m_textLine, "Press (q,e) to adjust target angle");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Target angle = %g degrees", m_angle * 180.0f / b2_pi);
m_textLine += 15;
}
static Test* Create()
{
return new Rope;
}
b2Rope m_rope;
float32 m_angle;
};
#endif

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef ROPE_JOINT_H
#define ROPE_JOINT_H
/// This test shows how a rope joint can be used to stabilize a chain of
/// bodies with a heavy payload. Notice that the rope joint just prevents
/// excessive stretching and has no other effect.
/// By disabling the rope joint you can see that the Box2D solver has trouble
/// supporting heavy bodies with light bodies. Try playing around with the
/// densities, time step, and iterations to see how they affect stability.
/// This test also shows how to use contact filtering. Filtering is configured
/// so that the payload does not collide with the chain.
class RopeJoint : public Test
{
public:
RopeJoint()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.125f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.friction = 0.2f;
fd.filter.categoryBits = 0x0001;
fd.filter.maskBits = 0xFFFF & ~0x0002;
b2RevoluteJointDef jd;
jd.collideConnected = false;
const int32 N = 10;
const float32 y = 15.0f;
m_ropeDef.localAnchorA.Set(0.0f, y);
b2Body* prevBody = ground;
for (int32 i = 0; i < N; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.5f + 1.0f * i, y);
if (i == N - 1)
{
shape.SetAsBox(1.5f, 1.5f);
fd.density = 100.0f;
fd.filter.categoryBits = 0x0002;
bd.position.Set(1.0f * i, y);
bd.angularDamping = 0.4f;
}
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&fd);
b2Vec2 anchor(float32(i), y);
jd.Initialize(prevBody, body, anchor);
m_world->CreateJoint(&jd);
prevBody = body;
}
m_ropeDef.localAnchorB.SetZero();
float32 extraLength = 0.01f;
m_ropeDef.maxLength = N - 1.0f + extraLength;
m_ropeDef.bodyB = prevBody;
}
{
m_ropeDef.bodyA = ground;
m_rope = m_world->CreateJoint(&m_ropeDef);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'j':
if (m_rope)
{
m_world->DestroyJoint(m_rope);
m_rope = NULL;
}
else
{
m_rope = m_world->CreateJoint(&m_ropeDef);
}
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press (j) to toggle the rope joint.");
m_textLine += 15;
if (m_rope)
{
m_debugDraw.DrawString(5, m_textLine, "Rope ON");
}
else
{
m_debugDraw.DrawString(5, m_textLine, "Rope OFF");
}
m_textLine += 15;
}
static Test* Create()
{
return new RopeJoint;
}
b2RopeJointDef m_ropeDef;
b2Joint* m_rope;
};
#endif

View File

@ -1,181 +0,0 @@
/*
* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SENSOR_TEST_H
#define SENSOR_TEST_H
// This is used to test sensor shapes.
class SensorTest : public Test
{
public:
enum
{
e_count = 7
};
SensorTest()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
{
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
#if 0
{
b2FixtureDef sd;
sd.SetAsBox(10.0f, 2.0f, b2Vec2(0.0f, 20.0f), 0.0f);
sd.isSensor = true;
m_sensor = ground->CreateFixture(&sd);
}
#else
{
b2CircleShape shape;
shape.m_radius = 5.0f;
shape.m_p.Set(0.0f, 10.0f);
b2FixtureDef fd;
fd.shape = &shape;
fd.isSensor = true;
m_sensor = ground->CreateFixture(&fd);
}
#endif
}
{
b2CircleShape shape;
shape.m_radius = 1.0f;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-10.0f + 3.0f * i, 20.0f);
bd.userData = m_touching + i;
m_touching[i] = false;
m_bodies[i] = m_world->CreateBody(&bd);
m_bodies[i]->CreateFixture(&shape, 1.0f);
}
}
}
// Implement contact listener.
void BeginContact(b2Contact* contact)
{
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
if (fixtureA == m_sensor)
{
void* userData = fixtureB->GetBody()->GetUserData();
if (userData)
{
bool* touching = (bool*)userData;
*touching = true;
}
}
if (fixtureB == m_sensor)
{
void* userData = fixtureA->GetBody()->GetUserData();
if (userData)
{
bool* touching = (bool*)userData;
*touching = true;
}
}
}
// Implement contact listener.
void EndContact(b2Contact* contact)
{
b2Fixture* fixtureA = contact->GetFixtureA();
b2Fixture* fixtureB = contact->GetFixtureB();
if (fixtureA == m_sensor)
{
void* userData = fixtureB->GetBody()->GetUserData();
if (userData)
{
bool* touching = (bool*)userData;
*touching = false;
}
}
if (fixtureB == m_sensor)
{
void* userData = fixtureA->GetBody()->GetUserData();
if (userData)
{
bool* touching = (bool*)userData;
*touching = false;
}
}
}
void Step(Settings* settings)
{
Test::Step(settings);
// Traverse the contact results. Apply a force on shapes
// that overlap the sensor.
for (int32 i = 0; i < e_count; ++i)
{
if (m_touching[i] == false)
{
continue;
}
b2Body* body = m_bodies[i];
b2Body* ground = m_sensor->GetBody();
b2CircleShape* circle = (b2CircleShape*)m_sensor->GetShape();
b2Vec2 center = ground->GetWorldPoint(circle->m_p);
b2Vec2 position = body->GetPosition();
b2Vec2 d = center - position;
if (d.LengthSquared() < FLT_EPSILON * FLT_EPSILON)
{
continue;
}
d.Normalize();
b2Vec2 F = 100.0f * d;
body->ApplyForce(F, position);
}
}
static Test* Create()
{
return new SensorTest;
}
b2Fixture* m_sensor;
b2Body* m_bodies[e_count];
bool m_touching[e_count];
};
#endif

View File

@ -1,105 +0,0 @@
/*
* Copyright (c) 2008-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SHAPE_EDITING_H
#define SHAPE_EDITING_H
class ShapeEditing : public Test
{
public:
ShapeEditing()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 10.0f);
m_body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(4.0f, 4.0f, b2Vec2(0.0f, 0.0f), 0.0f);
m_fixture1 = m_body->CreateFixture(&shape, 10.0f);
m_fixture2 = NULL;
m_sensor = false;
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'c':
if (m_fixture2 == NULL)
{
b2CircleShape shape;
shape.m_radius = 3.0f;
shape.m_p.Set(0.5f, -4.0f);
m_fixture2 = m_body->CreateFixture(&shape, 10.0f);
m_body->SetAwake(true);
}
break;
case 'd':
if (m_fixture2 != NULL)
{
m_body->DestroyFixture(m_fixture2);
m_fixture2 = NULL;
m_body->SetAwake(true);
}
break;
case 's':
if (m_fixture2 != NULL)
{
m_sensor = !m_sensor;
m_fixture2->SetSensor(m_sensor);
}
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "sensor = %d", m_sensor);
m_textLine += 15;
}
static Test* Create()
{
return new ShapeEditing;
}
b2Body* m_body;
b2Fixture* m_fixture1;
b2Fixture* m_fixture2;
bool m_sensor;
};
#endif

View File

@ -1,156 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SLIDER_CRANK_H
#define SLIDER_CRANK_H
// A motor driven slider crank with joint friction.
class SliderCrank : public Test
{
public:
SliderCrank()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2Body* prevBody = ground;
// Define crank.
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 2.0f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 7.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 2.0f);
b2RevoluteJointDef rjd;
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 5.0f));
rjd.motorSpeed = 1.0f * b2_pi;
rjd.maxMotorTorque = 10000.0f;
rjd.enableMotor = true;
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);
prevBody = body;
}
// Define follower.
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 4.0f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 13.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 2.0f);
b2RevoluteJointDef rjd;
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 9.0f));
rjd.enableMotor = false;
m_world->CreateJoint(&rjd);
prevBody = body;
}
// Define piston
{
b2PolygonShape shape;
shape.SetAsBox(1.5f, 1.5f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.fixedRotation = true;
bd.position.Set(0.0f, 17.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 2.0f);
b2RevoluteJointDef rjd;
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 17.0f));
m_world->CreateJoint(&rjd);
b2PrismaticJointDef pjd;
pjd.Initialize(ground, body, b2Vec2(0.0f, 17.0f), b2Vec2(0.0f, 1.0f));
pjd.maxMotorForce = 1000.0f;
pjd.enableMotor = true;
m_joint2 = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
}
// Create a payload
{
b2PolygonShape shape;
shape.SetAsBox(1.5f, 1.5f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 23.0f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 2.0f);
}
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'f':
m_joint2->EnableMotor(!m_joint2->IsMotorEnabled());
m_joint2->GetBodyB()->SetAwake(true);
break;
case 'm':
m_joint1->EnableMotor(!m_joint1->IsMotorEnabled());
m_joint1->GetBodyB()->SetAwake(true);
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Keys: (f) toggle friction, (m) toggle motor");
m_textLine += 15;
float32 torque = m_joint1->GetMotorTorque(settings->hz);
m_debugDraw.DrawString(5, m_textLine, "Motor Torque = %5.0f", (float) torque);
m_textLine += 15;
}
static Test* Create()
{
return new SliderCrank;
}
b2RevoluteJoint* m_joint1;
b2PrismaticJoint* m_joint2;
};
#endif

View File

@ -1,86 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SPHERE_STACK_H
#define SPHERE_STACK_H
class SphereStack : public Test
{
public:
enum
{
e_count = 10
};
SphereStack()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2CircleShape shape;
shape.m_radius = 1.0f;
for (int32 i = 0; i < e_count; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0, 4.0f + 3.0f * i);
m_bodies[i] = m_world->CreateBody(&bd);
m_bodies[i]->CreateFixture(&shape, 1.0f);
m_bodies[i]->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
}
}
}
void Step(Settings* settings)
{
Test::Step(settings);
//for (int32 i = 0; i < e_count; ++i)
//{
// printf("%g ", m_bodies[i]->GetWorldCenter().y);
//}
//for (int32 i = 0; i < e_count; ++i)
//{
// printf("%g ", m_bodies[i]->GetLinearVelocity().y);
//}
//printf("\n");
}
static Test* Create()
{
return new SphereStack;
}
b2Body* m_bodies[e_count];
};
#endif

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "../Framework/Test.h"
#include "../Framework/Render.h"
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include "freeglut/freeglut.h"
#endif
#include <cstring>
using namespace std;
#include "AddPair.h"
#include "ApplyForce.h"
#include "BodyTypes.h"
#include "Breakable.h"
#include "Bridge.h"
#include "BulletTest.h"
#include "Cantilever.h"
#include "Car.h"
#include "ContinuousTest.h"
#include "Chain.h"
#include "CharacterCollision.h"
#include "CollisionFiltering.h"
#include "CollisionProcessing.h"
#include "CompoundShapes.h"
#include "Confined.h"
#include "DistanceTest.h"
#include "Dominos.h"
#include "DumpShell.h"
#include "DynamicTreeTest.h"
#include "EdgeShapes.h"
#include "EdgeTest.h"
#include "Gears.h"
#include "OneSidedPlatform.h"
#include "Pinball.h"
#include "PolyCollision.h"
#include "PolyShapes.h"
#include "Prismatic.h"
#include "Pulleys.h"
#include "Pyramid.h"
#include "RayCast.h"
#include "Revolute.h"
//#include "Rope.h"
#include "RopeJoint.h"
#include "SensorTest.h"
#include "ShapeEditing.h"
#include "SliderCrank.h"
#include "SphereStack.h"
#include "TheoJansen.h"
#include "Tiles.h"
#include "TimeOfImpact.h"
#include "Tumbler.h"
#include "VaryingFriction.h"
#include "VaryingRestitution.h"
#include "VerticalStack.h"
#include "Web.h"
TestEntry g_testEntries[] =
{
{"Tumbler", Tumbler::Create},
{"Tiles", Tiles::Create},
{"Dump Shell", DumpShell::Create},
{"Gears", Gears::Create},
{"Cantilever", Cantilever::Create},
{"Varying Restitution", VaryingRestitution::Create},
{"Character Collision", CharacterCollision::Create},
{"Edge Test", EdgeTest::Create},
{"Body Types", BodyTypes::Create},
{"Shape Editing", ShapeEditing::Create},
{"Car", Car::Create},
{"Apply Force", ApplyForce::Create},
{"Prismatic", Prismatic::Create},
{"Vertical Stack", VerticalStack::Create},
{"SphereStack", SphereStack::Create},
{"Revolute", Revolute::Create},
{"Pulleys", Pulleys::Create},
{"Polygon Shapes", PolyShapes::Create},
//{"Rope", Rope::Create},
{"Web", Web::Create},
{"RopeJoint", RopeJoint::Create},
{"One-Sided Platform", OneSidedPlatform::Create},
{"Pinball", Pinball::Create},
{"Bullet Test", BulletTest::Create},
{"Continuous Test", ContinuousTest::Create},
{"Time of Impact", TimeOfImpact::Create},
{"Ray-Cast", RayCast::Create},
{"Confined", Confined::Create},
{"Pyramid", Pyramid::Create},
{"Theo Jansen's Walker", TheoJansen::Create},
{"Edge Shapes", EdgeShapes::Create},
{"PolyCollision", PolyCollision::Create},
{"Bridge", Bridge::Create},
{"Breakable", Breakable::Create},
{"Chain", Chain::Create},
{"Collision Filtering", CollisionFiltering::Create},
{"Collision Processing", CollisionProcessing::Create},
{"Compound Shapes", CompoundShapes::Create},
{"Distance Test", DistanceTest::Create},
{"Dominos", Dominos::Create},
{"Dynamic Tree", DynamicTreeTest::Create},
{"Sensor Test", SensorTest::Create},
{"Slider Crank", SliderCrank::Create},
{"Varying Friction", VaryingFriction::Create},
{"Add Pair Stress Test", AddPair::Create},
{NULL, NULL}
};

View File

@ -1,256 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
// Inspired by a contribution by roman_m
// Dimensions scooped from APE (http://www.cove.org/ape/index.htm)
#ifndef THEO_JANSEN_H
#define THEO_JANSEN_H
class TheoJansen : public Test
{
public:
void CreateLeg(float32 s, const b2Vec2& wheelAnchor)
{
b2Vec2 p1(5.4f * s, -6.1f);
b2Vec2 p2(7.2f * s, -1.2f);
b2Vec2 p3(4.3f * s, -1.9f);
b2Vec2 p4(3.1f * s, 0.8f);
b2Vec2 p5(6.0f * s, 1.5f);
b2Vec2 p6(2.5f * s, 3.7f);
b2FixtureDef fd1, fd2;
fd1.filter.groupIndex = -1;
fd2.filter.groupIndex = -1;
fd1.density = 1.0f;
fd2.density = 1.0f;
b2PolygonShape poly1, poly2;
if (s > 0.0f)
{
b2Vec2 vertices[3];
vertices[0] = p1;
vertices[1] = p2;
vertices[2] = p3;
poly1.Set(vertices, 3);
vertices[0] = b2Vec2_zero;
vertices[1] = p5 - p4;
vertices[2] = p6 - p4;
poly2.Set(vertices, 3);
}
else
{
b2Vec2 vertices[3];
vertices[0] = p1;
vertices[1] = p3;
vertices[2] = p2;
poly1.Set(vertices, 3);
vertices[0] = b2Vec2_zero;
vertices[1] = p6 - p4;
vertices[2] = p5 - p4;
poly2.Set(vertices, 3);
}
fd1.shape = &poly1;
fd2.shape = &poly2;
b2BodyDef bd1, bd2;
bd1.type = b2_dynamicBody;
bd2.type = b2_dynamicBody;
bd1.position = m_offset;
bd2.position = p4 + m_offset;
bd1.angularDamping = 10.0f;
bd2.angularDamping = 10.0f;
b2Body* body1 = m_world->CreateBody(&bd1);
b2Body* body2 = m_world->CreateBody(&bd2);
body1->CreateFixture(&fd1);
body2->CreateFixture(&fd2);
b2DistanceJointDef djd;
// Using a soft distance constraint can reduce some jitter.
// It also makes the structure seem a bit more fluid by
// acting like a suspension system.
djd.dampingRatio = 0.5f;
djd.frequencyHz = 10.0f;
djd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset);
m_world->CreateJoint(&djd);
djd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset);
m_world->CreateJoint(&djd);
djd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset);
m_world->CreateJoint(&djd);
djd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset);
m_world->CreateJoint(&djd);
b2RevoluteJointDef rjd;
rjd.Initialize(body2, m_chassis, p4 + m_offset);
m_world->CreateJoint(&rjd);
}
TheoJansen()
{
m_offset.Set(0.0f, 8.0f);
m_motorSpeed = 2.0f;
m_motorOn = true;
b2Vec2 pivot(0.0f, 0.8f);
// Ground
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
shape.Set(b2Vec2(-50.0f, 0.0f), b2Vec2(-50.0f, 10.0f));
ground->CreateFixture(&shape, 0.0f);
shape.Set(b2Vec2(50.0f, 0.0f), b2Vec2(50.0f, 10.0f));
ground->CreateFixture(&shape, 0.0f);
}
// Balls
for (int32 i = 0; i < 40; ++i)
{
b2CircleShape shape;
shape.m_radius = 0.25f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-40.0f + 2.0f * i, 0.5f);
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 1.0f);
}
// Chassis
{
b2PolygonShape shape;
shape.SetAsBox(2.5f, 1.0f);
b2FixtureDef sd;
sd.density = 1.0f;
sd.shape = &shape;
sd.filter.groupIndex = -1;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = pivot + m_offset;
m_chassis = m_world->CreateBody(&bd);
m_chassis->CreateFixture(&sd);
}
{
b2CircleShape shape;
shape.m_radius = 1.6f;
b2FixtureDef sd;
sd.density = 1.0f;
sd.shape = &shape;
sd.filter.groupIndex = -1;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = pivot + m_offset;
m_wheel = m_world->CreateBody(&bd);
m_wheel->CreateFixture(&sd);
}
{
b2RevoluteJointDef jd;
jd.Initialize(m_wheel, m_chassis, pivot + m_offset);
jd.collideConnected = false;
jd.motorSpeed = m_motorSpeed;
jd.maxMotorTorque = 400.0f;
jd.enableMotor = m_motorOn;
m_motorJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
}
b2Vec2 wheelAnchor;
wheelAnchor = pivot + b2Vec2(0.0f, -0.8f);
CreateLeg(-1.0f, wheelAnchor);
CreateLeg(1.0f, wheelAnchor);
m_wheel->SetTransform(m_wheel->GetPosition(), 120.0f * b2_pi / 180.0f);
CreateLeg(-1.0f, wheelAnchor);
CreateLeg(1.0f, wheelAnchor);
m_wheel->SetTransform(m_wheel->GetPosition(), -120.0f * b2_pi / 180.0f);
CreateLeg(-1.0f, wheelAnchor);
CreateLeg(1.0f, wheelAnchor);
}
void Step(Settings* settings)
{
m_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, toggle motor = m");
m_textLine += 15;
Test::Step(settings);
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'a':
m_motorJoint->SetMotorSpeed(-m_motorSpeed);
break;
case 's':
m_motorJoint->SetMotorSpeed(0.0f);
break;
case 'd':
m_motorJoint->SetMotorSpeed(m_motorSpeed);
break;
case 'm':
m_motorJoint->EnableMotor(!m_motorJoint->IsMotorEnabled());
break;
}
}
static Test* Create()
{
return new TheoJansen;
}
b2Vec2 m_offset;
b2Body* m_chassis;
b2Body* m_wheel;
b2RevoluteJoint* m_motorJoint;
bool m_motorOn;
float32 m_motorSpeed;
};
#endif // THEO_JANSEN_H

View File

@ -1,156 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TILES_H
#define TILES_H
/// This stress tests the dynamic tree broad-phase. This also shows that tile
/// based collision is _not_ smooth due to Box2D not knowing about adjacency.
class Tiles : public Test
{
public:
enum
{
e_count = 20
};
Tiles()
{
m_fixtureCount = 0;
b2Timer timer;
{
float32 a = 0.5f;
b2BodyDef bd;
bd.position.y = -a;
b2Body* ground = m_world->CreateBody(&bd);
#if 1
int32 N = 200;
int32 M = 10;
b2Vec2 position;
position.y = 0.0f;
for (int32 j = 0; j < M; ++j)
{
position.x = -N * a;
for (int32 i = 0; i < N; ++i)
{
b2PolygonShape shape;
shape.SetAsBox(a, a, position, 0.0f);
ground->CreateFixture(&shape, 0.0f);
++m_fixtureCount;
position.x += 2.0f * a;
}
position.y -= 2.0f * a;
}
#else
int32 N = 200;
int32 M = 10;
b2Vec2 position;
position.x = -N * a;
for (int32 i = 0; i < N; ++i)
{
position.y = 0.0f;
for (int32 j = 0; j < M; ++j)
{
b2PolygonShape shape;
shape.SetAsBox(a, a, position, 0.0f);
ground->CreateFixture(&shape, 0.0f);
position.y -= 2.0f * a;
}
position.x += 2.0f * a;
}
#endif
}
{
float32 a = 0.5f;
b2PolygonShape shape;
shape.SetAsBox(a, a);
b2Vec2 x(-7.0f, 0.75f);
b2Vec2 y;
b2Vec2 deltaX(0.5625f, 1.25f);
b2Vec2 deltaY(1.125f, 0.0f);
for (int32 i = 0; i < e_count; ++i)
{
y = x;
for (int32 j = i; j < e_count; ++j)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = y;
//if (i == 0 && j == 0)
//{
// bd.allowSleep = false;
//}
//else
//{
// bd.allowSleep = true;
//}
b2Body* body = m_world->CreateBody(&bd);
body->CreateFixture(&shape, 5.0f);
++m_fixtureCount;
y += deltaY;
}
x += deltaX;
}
}
m_createTime = timer.GetMilliseconds();
}
void Step(Settings* settings)
{
const b2ContactManager& cm = m_world->GetContactManager();
int32 height = cm.m_broadPhase.GetTreeHeight();
int32 leafCount = cm.m_broadPhase.GetProxyCount();
int32 minimumNodeCount = 2 * leafCount - 1;
float32 minimumHeight = ceilf(logf(float32(minimumNodeCount)) / logf(2.0f));
m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight));
m_textLine += 15;
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d",
m_createTime, m_fixtureCount);
m_textLine += 15;
//b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
//if (m_stepCount == 400)
//{
// tree->RebuildBottomUp();
//}
}
static Test* Create()
{
return new Tiles;
}
int32 m_fixtureCount;
float32 m_createTime;
};
#endif

View File

@ -1,131 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TIME_OF_IMPACT_H
#define TIME_OF_IMPACT_H
class TimeOfImpact : public Test
{
public:
TimeOfImpact()
{
m_shapeA.SetAsBox(25.0f, 5.0f);
m_shapeB.SetAsBox(2.5f, 2.5f);
}
static Test* Create()
{
return new TimeOfImpact;
}
void Step(Settings* settings)
{
Test::Step(settings);
b2Sweep sweepA;
sweepA.c0.Set(24.0f, -60.0f);
sweepA.a0 = 2.95f;
sweepA.c = sweepA.c0;
sweepA.a = sweepA.a0;
sweepA.localCenter.SetZero();
b2Sweep sweepB;
sweepB.c0.Set(53.474274f, -50.252514f);
sweepB.a0 = 513.36676f; // - 162.0f * b2_pi;
sweepB.c.Set(54.595478f, -51.083473f);
sweepB.a = 513.62781f; // - 162.0f * b2_pi;
sweepB.localCenter.SetZero();
//sweepB.a0 -= 300.0f * b2_pi;
//sweepB.a -= 300.0f * b2_pi;
b2TOIInput input;
input.proxyA.Set(&m_shapeA, 0);
input.proxyB.Set(&m_shapeB, 0);
input.sweepA = sweepA;
input.sweepB = sweepB;
input.tMax = 1.0f;
b2TOIOutput output;
b2TimeOfImpact(&output, &input);
m_debugDraw.DrawString(5, m_textLine, "toi = %g", output.t);
m_textLine += 15;
extern int32 b2_toiMaxIters, b2_toiMaxRootIters;
m_debugDraw.DrawString(5, m_textLine, "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters);
m_textLine += 15;
b2Vec2 vertices[b2_maxPolygonVertices];
b2Transform transformA;
sweepA.GetTransform(&transformA, 0.0f);
for (int32 i = 0; i < m_shapeA.m_vertexCount; ++i)
{
vertices[i] = b2Mul(transformA, m_shapeA.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vertices, m_shapeA.m_vertexCount, b2Color(0.9f, 0.9f, 0.9f));
b2Transform transformB;
sweepB.GetTransform(&transformB, 0.0f);
b2Vec2 localPoint(2.0f, -0.1f);
b2Vec2 rB = b2Mul(transformB, localPoint) - sweepB.c0;
float32 wB = sweepB.a - sweepB.a0;
b2Vec2 vB = sweepB.c - sweepB.c0;
b2Vec2 v = vB + b2Cross(wB, rB);
for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
{
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.9f, 0.5f));
sweepB.GetTransform(&transformB, output.t);
for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
{
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.5f, 0.7f, 0.9f));
sweepB.GetTransform(&transformB, 1.0f);
for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
{
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));
#if 0
for (float32 t = 0.0f; t < 1.0f; t += 0.1f)
{
sweepB.GetTransform(&transformB, t);
for (int32 i = 0; i < m_shapeB.m_vertexCount; ++i)
{
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
}
m_debugDraw.DrawPolygon(vertices, m_shapeB.m_vertexCount, b2Color(0.9f, 0.5f, 0.5f));
}
#endif
}
b2PolygonShape m_shapeA;
b2PolygonShape m_shapeB;
};
#endif

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TUMBLER_H
#define TUMBLER_H
class Tumbler : public Test
{
public:
enum
{
e_count = 800
};
Tumbler()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
}
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.allowSleep = false;
bd.position.Set(0.0f, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.5f, 10.0f, b2Vec2( 10.0f, 0.0f), 0.0);
body->CreateFixture(&shape, 5.0f);
shape.SetAsBox(0.5f, 10.0f, b2Vec2(-10.0f, 0.0f), 0.0);
body->CreateFixture(&shape, 5.0f);
shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, 10.0f), 0.0);
body->CreateFixture(&shape, 5.0f);
shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, -10.0f), 0.0);
body->CreateFixture(&shape, 5.0f);
b2RevoluteJointDef jd;
jd.bodyA = ground;
jd.bodyB = body;
jd.localAnchorA.Set(0.0f, 10.0f);
jd.localAnchorB.Set(0.0f, 0.0f);
jd.referenceAngle = 0.0f;
jd.motorSpeed = 0.05f * b2_pi;
jd.maxMotorTorque = 1e8f;
jd.enableMotor = true;
m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
}
m_count = 0;
}
void Step(Settings* settings)
{
Test::Step(settings);
if (m_count < e_count)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(0.0f, 10.0f);
b2Body* body = m_world->CreateBody(&bd);
b2PolygonShape shape;
shape.SetAsBox(0.125f, 0.125f);
body->CreateFixture(&shape, 1.0f);
++m_count;
}
}
static Test* Create()
{
return new Tumbler;
}
b2RevoluteJoint* m_joint;
int32 m_count;
};
#endif

View File

@ -1,124 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef VARYING_FRICTION_H
#define VARYING_FRICTION_H
class VaryingFriction : public Test
{
public:
VaryingFriction()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(13.0f, 0.25f);
b2BodyDef bd;
bd.position.Set(-4.0f, 22.0f);
bd.angle = -0.25f;
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.25f, 1.0f);
b2BodyDef bd;
bd.position.Set(10.5f, 19.0f);
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(13.0f, 0.25f);
b2BodyDef bd;
bd.position.Set(4.0f, 14.0f);
bd.angle = 0.25f;
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.25f, 1.0f);
b2BodyDef bd;
bd.position.Set(-10.5f, 11.0f);
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(13.0f, 0.25f);
b2BodyDef bd;
bd.position.Set(-4.0f, 6.0f);
bd.angle = -0.25f;
b2Body* ground = m_world->CreateBody(&bd);
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 25.0f;
float friction[5] = {0.75f, 0.5f, 0.35f, 0.1f, 0.0f};
for (int i = 0; i < 5; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-15.0f + 4.0f * i, 28.0f);
b2Body* body = m_world->CreateBody(&bd);
fd.friction = friction[i];
body->CreateFixture(&fd);
}
}
}
static Test* Create()
{
return new VaryingFriction;
}
};
#endif

View File

@ -1,69 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef VARYING_RESTITUTION_H
#define VARYING_RESTITUTION_H
// Note: even with a restitution of 1.0, there is some energy change
// due to position correction.
class VaryingRestitution : public Test
{
public:
VaryingRestitution()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2CircleShape shape;
shape.m_radius = 1.0f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
float32 restitution[7] = {0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f};
for (int32 i = 0; i < 7; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-10.0f + 3.0f * i, 20.0f);
b2Body* body = m_world->CreateBody(&bd);
fd.restitution = restitution[i];
body->CreateFixture(&fd);
}
}
}
static Test* Create()
{
return new VaryingRestitution;
}
};
#endif

View File

@ -1,165 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef VERTICAL_STACK_H
#define VERTICAL_STACK_H
class VerticalStack : public Test
{
public:
enum
{
e_columnCount = 5,
e_rowCount = 16
//e_columnCount = 1,
//e_rowCount = 1
};
VerticalStack()
{
{
b2BodyDef bd;
b2Body* ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
shape.Set(b2Vec2(20.0f, 0.0f), b2Vec2(20.0f, 20.0f));
ground->CreateFixture(&shape, 0.0f);
}
float32 xs[5] = {0.0f, -10.0f, -5.0f, 5.0f, 10.0f};
for (int32 j = 0; j < e_columnCount; ++j)
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
fd.friction = 0.3f;
for (int i = 0; i < e_rowCount; ++i)
{
b2BodyDef bd;
bd.type = b2_dynamicBody;
int32 n = j * e_rowCount + i;
b2Assert(n < e_rowCount * e_columnCount);
m_indices[n] = n;
bd.userData = m_indices + n;
float32 x = 0.0f;
//float32 x = RandomFloat(-0.02f, 0.02f);
//float32 x = i % 2 == 0 ? -0.025f : 0.025f;
bd.position.Set(xs[j] + x, 0.752f + 1.54f * i);
b2Body* body = m_world->CreateBody(&bd);
m_bodies[n] = body;
body->CreateFixture(&fd);
}
}
m_bullet = NULL;
}
void Keyboard(unsigned char key)
{
switch (key)
{
case ',':
if (m_bullet != NULL)
{
m_world->DestroyBody(m_bullet);
m_bullet = NULL;
}
{
b2CircleShape shape;
shape.m_radius = 0.25f;
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 20.0f;
fd.restitution = 0.05f;
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.bullet = true;
bd.position.Set(-31.0f, 5.0f);
m_bullet = m_world->CreateBody(&bd);
m_bullet->CreateFixture(&fd);
m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
}
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "Press: (,) to launch a bullet.");
m_textLine += 15;
//if (m_stepCount == 300)
//{
// if (m_bullet != NULL)
// {
// m_world->DestroyBody(m_bullet);
// m_bullet = NULL;
// }
// {
// b2CircleShape shape;
// shape.m_radius = 0.25f;
// b2FixtureDef fd;
// fd.shape = &shape;
// fd.density = 20.0f;
// fd.restitution = 0.05f;
// b2BodyDef bd;
// bd.type = b2_dynamicBody;
// bd.bullet = true;
// bd.position.Set(-31.0f, 5.0f);
// m_bullet = m_world->CreateBody(&bd);
// m_bullet->CreateFixture(&fd);
// m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
// }
//}
}
static Test* Create()
{
return new VerticalStack;
}
b2Body* m_bullet;
b2Body* m_bodies[e_rowCount * e_columnCount];
int32 m_indices[e_rowCount * e_columnCount];
};
#endif

View File

@ -1,209 +0,0 @@
/*
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef WEB_H
#define WEB_H
// This tests distance joints, body destruction, and joint destruction.
class Web : public Test
{
public:
Web()
{
b2Body* ground = NULL;
{
b2BodyDef bd;
ground = m_world->CreateBody(&bd);
b2EdgeShape shape;
shape.Set(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
ground->CreateFixture(&shape, 0.0f);
}
{
b2PolygonShape shape;
shape.SetAsBox(0.5f, 0.5f);
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position.Set(-5.0f, 5.0f);
m_bodies[0] = m_world->CreateBody(&bd);
m_bodies[0]->CreateFixture(&shape, 5.0f);
bd.position.Set(5.0f, 5.0f);
m_bodies[1] = m_world->CreateBody(&bd);
m_bodies[1]->CreateFixture(&shape, 5.0f);
bd.position.Set(5.0f, 15.0f);
m_bodies[2] = m_world->CreateBody(&bd);
m_bodies[2]->CreateFixture(&shape, 5.0f);
bd.position.Set(-5.0f, 15.0f);
m_bodies[3] = m_world->CreateBody(&bd);
m_bodies[3]->CreateFixture(&shape, 5.0f);
b2DistanceJointDef jd;
b2Vec2 p1, p2, d;
jd.frequencyHz = 2.0f;
jd.dampingRatio = 0.0f;
jd.bodyA = ground;
jd.bodyB = m_bodies[0];
jd.localAnchorA.Set(-10.0f, 0.0f);
jd.localAnchorB.Set(-0.5f, -0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[0] = m_world->CreateJoint(&jd);
jd.bodyA = ground;
jd.bodyB = m_bodies[1];
jd.localAnchorA.Set(10.0f, 0.0f);
jd.localAnchorB.Set(0.5f, -0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[1] = m_world->CreateJoint(&jd);
jd.bodyA = ground;
jd.bodyB = m_bodies[2];
jd.localAnchorA.Set(10.0f, 20.0f);
jd.localAnchorB.Set(0.5f, 0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[2] = m_world->CreateJoint(&jd);
jd.bodyA = ground;
jd.bodyB = m_bodies[3];
jd.localAnchorA.Set(-10.0f, 20.0f);
jd.localAnchorB.Set(-0.5f, 0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[3] = m_world->CreateJoint(&jd);
jd.bodyA = m_bodies[0];
jd.bodyB = m_bodies[1];
jd.localAnchorA.Set(0.5f, 0.0f);
jd.localAnchorB.Set(-0.5f, 0.0f);;
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[4] = m_world->CreateJoint(&jd);
jd.bodyA = m_bodies[1];
jd.bodyB = m_bodies[2];
jd.localAnchorA.Set(0.0f, 0.5f);
jd.localAnchorB.Set(0.0f, -0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[5] = m_world->CreateJoint(&jd);
jd.bodyA = m_bodies[2];
jd.bodyB = m_bodies[3];
jd.localAnchorA.Set(-0.5f, 0.0f);
jd.localAnchorB.Set(0.5f, 0.0f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[6] = m_world->CreateJoint(&jd);
jd.bodyA = m_bodies[3];
jd.bodyB = m_bodies[0];
jd.localAnchorA.Set(0.0f, -0.5f);
jd.localAnchorB.Set(0.0f, 0.5f);
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
d = p2 - p1;
jd.length = d.Length();
m_joints[7] = m_world->CreateJoint(&jd);
}
}
void Keyboard(unsigned char key)
{
switch (key)
{
case 'b':
for (int32 i = 0; i < 4; ++i)
{
if (m_bodies[i])
{
m_world->DestroyBody(m_bodies[i]);
m_bodies[i] = NULL;
break;
}
}
break;
case 'j':
for (int32 i = 0; i < 8; ++i)
{
if (m_joints[i])
{
m_world->DestroyJoint(m_joints[i]);
m_joints[i] = NULL;
break;
}
}
break;
}
}
void Step(Settings* settings)
{
Test::Step(settings);
m_debugDraw.DrawString(5, m_textLine, "This demonstrates a soft distance joint.");
m_textLine += 15;
m_debugDraw.DrawString(5, m_textLine, "Press: (b) to delete a body, (j) to delete a joint");
m_textLine += 15;
}
void JointDestroyed(b2Joint* joint)
{
for (int32 i = 0; i < 8; ++i)
{
if (m_joints[i] == joint)
{
m_joints[i] = NULL;
break;
}
}
}
static Test* Create()
{
return new Web;
}
b2Body* m_bodies[4];
b2Joint* m_joints[8];
};
#endif

View File

@ -1,695 +0,0 @@
/*
==============================================================================
This file is part of the JUCE examples.
Copyright (c) 2022 - Raw Material Software Limited
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
#pragma once
using namespace dsp;
//==============================================================================
struct DSPDemoParameterBase : public ChangeBroadcaster
{
DSPDemoParameterBase (const String& labelName) : name (labelName) {}
virtual ~DSPDemoParameterBase() {}
virtual Component* getComponent() = 0;
virtual int getPreferredHeight() = 0;
virtual int getPreferredWidth() = 0;
String name;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DSPDemoParameterBase)
};
//==============================================================================
struct SliderParameter : public DSPDemoParameterBase
{
SliderParameter (Range<double> range, double skew, double initialValue,
const String& labelName, const String& suffix = {})
: DSPDemoParameterBase (labelName)
{
slider.setRange (range.getStart(), range.getEnd(), 0.01);
slider.setSkewFactor (skew);
slider.setValue (initialValue);
if (suffix.isNotEmpty())
slider.setTextValueSuffix (suffix);
slider.onValueChange = [this] { sendChangeMessage(); };
}
Component* getComponent() override { return &slider; }
int getPreferredHeight() override { return 40; }
int getPreferredWidth() override { return 500; }
double getCurrentValue() const { return slider.getValue(); }
private:
Slider slider;
};
//==============================================================================
struct ChoiceParameter : public DSPDemoParameterBase
{
ChoiceParameter (const StringArray& options, int initialId, const String& labelName)
: DSPDemoParameterBase (labelName)
{
parameterBox.addItemList (options, 1);
parameterBox.onChange = [this] { sendChangeMessage(); };
parameterBox.setSelectedId (initialId);
}
Component* getComponent() override { return &parameterBox; }
int getPreferredHeight() override { return 25; }
int getPreferredWidth() override { return 250; }
int getCurrentSelectedID() const { return parameterBox.getSelectedId(); }
private:
ComboBox parameterBox;
};
//==============================================================================
class AudioThumbnailComponent : public Component,
public FileDragAndDropTarget,
public ChangeBroadcaster,
private ChangeListener,
private Timer
{
public:
AudioThumbnailComponent (AudioDeviceManager& adm, AudioFormatManager& afm)
: audioDeviceManager (adm),
thumbnailCache (5),
thumbnail (128, afm, thumbnailCache)
{
thumbnail.addChangeListener (this);
}
~AudioThumbnailComponent() override
{
thumbnail.removeChangeListener (this);
}
void paint (Graphics& g) override
{
g.fillAll (Colour (0xff495358));
g.setColour (Colours::white);
if (thumbnail.getTotalLength() > 0.0)
{
thumbnail.drawChannels (g, getLocalBounds().reduced (2),
0.0, thumbnail.getTotalLength(), 1.0f);
g.setColour (Colours::black);
g.fillRect (static_cast<float> (currentPosition * getWidth()), 0.0f,
1.0f, static_cast<float> (getHeight()));
}
else
{
g.drawFittedText ("No audio file loaded.\nDrop a file here or click the \"Load File...\" button.", getLocalBounds(),
Justification::centred, 2);
}
}
bool isInterestedInFileDrag (const StringArray&) override { return true; }
void filesDropped (const StringArray& files, int, int) override { loadURL (URL (File (files[0])), true); }
void setCurrentURL (const URL& u)
{
if (currentURL == u)
return;
loadURL (u);
}
URL getCurrentURL() { return currentURL; }
void setTransportSource (AudioTransportSource* newSource)
{
transportSource = newSource;
struct ResetCallback : public CallbackMessage
{
ResetCallback (AudioThumbnailComponent& o) : owner (o) {}
void messageCallback() override { owner.reset(); }
AudioThumbnailComponent& owner;
};
(new ResetCallback (*this))->post();
}
private:
AudioDeviceManager& audioDeviceManager;
AudioThumbnailCache thumbnailCache;
AudioThumbnail thumbnail;
AudioTransportSource* transportSource = nullptr;
URL currentURL;
double currentPosition = 0.0;
//==============================================================================
void changeListenerCallback (ChangeBroadcaster*) override { repaint(); }
void reset()
{
currentPosition = 0.0;
repaint();
if (transportSource == nullptr)
stopTimer();
else
startTimerHz (25);
}
void loadURL (const URL& u, bool notify = false)
{
if (currentURL == u)
return;
currentURL = u;
InputSource* inputSource = nullptr;
#if ! JUCE_IOS
if (u.isLocalFile())
{
inputSource = new FileInputSource (u.getLocalFile());
}
else
#endif
{
if (inputSource == nullptr)
inputSource = new URLInputSource (u);
}
thumbnail.setSource (inputSource);
if (notify)
sendChangeMessage();
}
void timerCallback() override
{
if (transportSource != nullptr)
{
currentPosition = transportSource->getCurrentPosition() / thumbnail.getTotalLength();
repaint();
}
}
void mouseDrag (const MouseEvent& e) override
{
if (transportSource != nullptr)
{
const ScopedLock sl (audioDeviceManager.getAudioCallbackLock());
transportSource->setPosition ((jmax (static_cast<double> (e.x), 0.0) / getWidth())
* thumbnail.getTotalLength());
}
}
};
//==============================================================================
class DemoParametersComponent : public Component
{
public:
DemoParametersComponent (const std::vector<DSPDemoParameterBase*>& demoParams)
{
parameters = demoParams;
for (auto demoParameter : parameters)
{
addAndMakeVisible (demoParameter->getComponent());
auto* paramLabel = new Label ({}, demoParameter->name);
paramLabel->attachToComponent (demoParameter->getComponent(), true);
paramLabel->setJustificationType (Justification::centredLeft);
addAndMakeVisible (paramLabel);
labels.add (paramLabel);
}
}
void resized() override
{
auto bounds = getLocalBounds();
bounds.removeFromLeft (100);
for (auto* p : parameters)
{
auto* comp = p->getComponent();
comp->setSize (jmin (bounds.getWidth(), p->getPreferredWidth()), p->getPreferredHeight());
auto compBounds = bounds.removeFromTop (p->getPreferredHeight());
comp->setCentrePosition (compBounds.getCentre());
}
}
int getHeightNeeded()
{
auto height = 0;
for (auto* p : parameters)
height += p->getPreferredHeight();
return height + 10;
}
private:
std::vector<DSPDemoParameterBase*> parameters;
OwnedArray<Label> labels;
};
//==============================================================================
template <class DemoType>
struct DSPDemo : public AudioSource,
public ProcessorWrapper<DemoType>,
private ChangeListener
{
DSPDemo (AudioSource& input)
: inputSource (&input)
{
for (auto* p : getParameters())
p->addChangeListener (this);
}
void prepareToPlay (int blockSize, double sampleRate) override
{
inputSource->prepareToPlay (blockSize, sampleRate);
this->prepare ({ sampleRate, (uint32) blockSize, 2 });
}
void releaseResources() override
{
inputSource->releaseResources();
}
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
{
if (bufferToFill.buffer == nullptr)
{
jassertfalse;
return;
}
inputSource->getNextAudioBlock (bufferToFill);
AudioBlock<float> block (*bufferToFill.buffer,
(size_t) bufferToFill.startSample);
ScopedLock audioLock (audioCallbackLock);
this->process (ProcessContextReplacing<float> (block));
}
const std::vector<DSPDemoParameterBase*>& getParameters()
{
return this->processor.parameters;
}
void changeListenerCallback (ChangeBroadcaster*) override
{
ScopedLock audioLock (audioCallbackLock);
static_cast<DemoType&> (this->processor).updateParameters();
}
CriticalSection audioCallbackLock;
AudioSource* inputSource;
};
//==============================================================================
template <class DemoType>
class AudioFileReaderComponent : public Component,
private TimeSliceThread,
private Value::Listener,
private ChangeListener
{
public:
//==============================================================================
AudioFileReaderComponent()
: TimeSliceThread ("Audio File Reader Thread"),
header (audioDeviceManager, formatManager, *this)
{
loopState.addListener (this);
formatManager.registerBasicFormats();
audioDeviceManager.addAudioCallback (&audioSourcePlayer);
#ifndef JUCE_DEMO_RUNNER
audioDeviceManager.initialiseWithDefaultDevices (0, 2);
#endif
init();
startThread();
setOpaque (true);
addAndMakeVisible (header);
setSize (800, 250);
}
~AudioFileReaderComponent() override
{
signalThreadShouldExit();
stop();
audioDeviceManager.removeAudioCallback (&audioSourcePlayer);
waitForThreadToExit (10000);
}
void paint (Graphics& g) override
{
g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
g.fillRect (getLocalBounds());
}
void resized() override
{
auto r = getLocalBounds();
header.setBounds (r.removeFromTop (120));
r.removeFromTop (20);
if (parametersComponent.get() != nullptr)
parametersComponent->setBounds (r.removeFromTop (parametersComponent->getHeightNeeded()).reduced (20, 0));
}
//==============================================================================
bool loadURL (const URL& fileToPlay)
{
stop();
audioSourcePlayer.setSource (nullptr);
getThumbnailComponent().setTransportSource (nullptr);
transportSource.reset();
readerSource.reset();
AudioFormatReader* newReader = nullptr;
#if ! JUCE_IOS
if (fileToPlay.isLocalFile())
{
newReader = formatManager.createReaderFor (fileToPlay.getLocalFile());
}
else
#endif
{
if (newReader == nullptr)
newReader = formatManager.createReaderFor (fileToPlay.createInputStream (URL::InputStreamOptions (URL::ParameterHandling::inAddress)));
}
reader.reset (newReader);
if (reader.get() != nullptr)
{
readerSource.reset (new AudioFormatReaderSource (reader.get(), false));
readerSource->setLooping (loopState.getValue());
init();
return true;
}
return false;
}
void togglePlay()
{
if (playState.getValue())
stop();
else
play();
}
void stop()
{
playState = false;
if (transportSource.get() != nullptr)
{
transportSource->stop();
transportSource->setPosition (0);
}
}
void init()
{
if (transportSource.get() == nullptr)
{
transportSource.reset (new AudioTransportSource());
transportSource->addChangeListener (this);
if (readerSource.get() != nullptr)
{
if (auto* device = audioDeviceManager.getCurrentAudioDevice())
{
transportSource->setSource (readerSource.get(), roundToInt (device->getCurrentSampleRate()), this, reader->sampleRate);
getThumbnailComponent().setTransportSource (transportSource.get());
}
}
}
audioSourcePlayer.setSource (nullptr);
currentDemo.reset();
if (currentDemo.get() == nullptr)
currentDemo.reset (new DSPDemo<DemoType> (*transportSource));
audioSourcePlayer.setSource (currentDemo.get());
initParameters();
}
void play()
{
if (readerSource.get() == nullptr)
return;
if (transportSource->getCurrentPosition() >= transportSource->getLengthInSeconds()
|| transportSource->getCurrentPosition() < 0)
transportSource->setPosition (0);
transportSource->start();
playState = true;
}
void setLooping (bool shouldLoop)
{
if (readerSource.get() != nullptr)
readerSource->setLooping (shouldLoop);
}
AudioThumbnailComponent& getThumbnailComponent() { return header.thumbnailComp; }
void initParameters()
{
auto& parameters = currentDemo->getParameters();
parametersComponent.reset();
if (parameters.size() > 0)
{
parametersComponent.reset (new DemoParametersComponent (parameters));
addAndMakeVisible (parametersComponent.get());
}
resized();
}
private:
//==============================================================================
class AudioPlayerHeader : public Component,
private ChangeListener,
private Value::Listener
{
public:
AudioPlayerHeader (AudioDeviceManager& adm,
AudioFormatManager& afm,
AudioFileReaderComponent& afr)
: thumbnailComp (adm, afm),
audioFileReader (afr)
{
setOpaque (true);
addAndMakeVisible (loadButton);
addAndMakeVisible (playButton);
addAndMakeVisible (loopButton);
playButton.setColour (TextButton::buttonColourId, Colour (0xff79ed7f));
playButton.setColour (TextButton::textColourOffId, Colours::black);
loadButton.setColour (TextButton::buttonColourId, Colour (0xff797fed));
loadButton.setColour (TextButton::textColourOffId, Colours::black);
loadButton.onClick = [this] { openFile(); };
playButton.onClick = [this] { audioFileReader.togglePlay(); };
addAndMakeVisible (thumbnailComp);
thumbnailComp.addChangeListener (this);
audioFileReader.playState.addListener (this);
loopButton.getToggleStateValue().referTo (audioFileReader.loopState);
}
~AudioPlayerHeader() override
{
audioFileReader.playState.removeListener (this);
}
void paint (Graphics& g) override
{
g.setColour (getLookAndFeel().findColour (ResizableWindow::backgroundColourId).darker());
g.fillRect (getLocalBounds());
}
void resized() override
{
auto bounds = getLocalBounds();
auto buttonBounds = bounds.removeFromLeft (jmin (250, bounds.getWidth() / 4));
auto loopBounds = buttonBounds.removeFromBottom (30);
loadButton.setBounds (buttonBounds.removeFromTop (buttonBounds.getHeight() / 2));
playButton.setBounds (buttonBounds);
loopButton.setSize (0, 25);
loopButton.changeWidthToFitText();
loopButton.setCentrePosition (loopBounds.getCentre());
thumbnailComp.setBounds (bounds);
}
AudioThumbnailComponent thumbnailComp;
private:
//==============================================================================
void openFile()
{
audioFileReader.stop();
if (fileChooser != nullptr)
return;
if (! RuntimePermissions::isGranted (RuntimePermissions::readExternalStorage))
{
SafePointer<AudioPlayerHeader> safeThis (this);
RuntimePermissions::request (RuntimePermissions::readExternalStorage,
[safeThis] (bool granted) mutable
{
if (safeThis != nullptr && granted)
safeThis->openFile();
});
return;
}
fileChooser.reset (new FileChooser ("Select an audio file...", File(), "*.wav;*.mp3;*.aif"));
fileChooser->launchAsync (FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles,
[this] (const FileChooser& fc) mutable
{
if (fc.getURLResults().size() > 0)
{
auto u = fc.getURLResult();
if (! audioFileReader.loadURL (u))
NativeMessageBox::showAsync (MessageBoxOptions()
.withIconType (MessageBoxIconType::WarningIcon)
.withTitle ("Error loading file")
.withMessage ("Unable to load audio file"),
nullptr);
else
thumbnailComp.setCurrentURL (u);
}
fileChooser = nullptr;
}, nullptr);
}
void changeListenerCallback (ChangeBroadcaster*) override
{
if (audioFileReader.playState.getValue())
audioFileReader.stop();
audioFileReader.loadURL (thumbnailComp.getCurrentURL());
}
void valueChanged (Value& v) override
{
playButton.setButtonText (v.getValue() ? "Stop" : "Play");
playButton.setColour (TextButton::buttonColourId, v.getValue() ? Colour (0xffed797f) : Colour (0xff79ed7f));
}
//==============================================================================
TextButton loadButton { "Load File..." }, playButton { "Play" };
ToggleButton loopButton { "Loop File" };
AudioFileReaderComponent& audioFileReader;
std::unique_ptr<FileChooser> fileChooser;
};
//==============================================================================
void valueChanged (Value& v) override
{
if (readerSource.get() != nullptr)
readerSource->setLooping (v.getValue());
}
void changeListenerCallback (ChangeBroadcaster*) override
{
if (playState.getValue() && ! transportSource->isPlaying())
stop();
}
//==============================================================================
// if this PIP is running inside the demo runner, we'll use the shared device manager instead
#ifndef JUCE_DEMO_RUNNER
AudioDeviceManager audioDeviceManager;
#else
AudioDeviceManager& audioDeviceManager { getSharedAudioDeviceManager (0, 2) };
#endif
AudioFormatManager formatManager;
Value playState { var (false) };
Value loopState { var (false) };
double currentSampleRate = 44100.0;
uint32 currentBlockSize = 512;
uint32 currentNumChannels = 2;
std::unique_ptr<AudioFormatReader> reader;
std::unique_ptr<AudioFormatReaderSource> readerSource;
std::unique_ptr<AudioTransportSource> transportSource;
std::unique_ptr<DSPDemo<DemoType>> currentDemo;
AudioSourcePlayer audioSourcePlayer;
AudioPlayerHeader header;
AudioBuffer<float> fileReadBuffer;
std::unique_ptr<DemoParametersComponent> parametersComponent;
};

View File

@ -1,245 +0,0 @@
/*
==============================================================================
This file is part of the JUCE examples.
Copyright (c) 2022 - Raw Material Software Limited
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES,
WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR
PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
#ifndef PIP_DEMO_UTILITIES_INCLUDED
#define PIP_DEMO_UTILITIES_INCLUDED 1
#include <JuceHeader.h>
//==============================================================================
/*
This file contains a bunch of miscellaneous utilities that are
used by the various demos.
*/
//==============================================================================
inline Colour getRandomColour (float brightness) noexcept
{
return Colour::fromHSV (Random::getSystemRandom().nextFloat(), 0.5f, brightness, 1.0f);
}
inline Colour getRandomBrightColour() noexcept { return getRandomColour (0.8f); }
inline Colour getRandomDarkColour() noexcept { return getRandomColour (0.3f); }
inline Colour getUIColourIfAvailable (LookAndFeel_V4::ColourScheme::UIColour uiColour, Colour fallback = Colour (0xff4d4d4d)) noexcept
{
if (auto* v4 = dynamic_cast<LookAndFeel_V4*> (&LookAndFeel::getDefaultLookAndFeel()))
return v4->getCurrentColourScheme().getUIColour (uiColour);
return fallback;
}
inline File getExamplesDirectory() noexcept
{
#ifdef PIP_JUCE_EXAMPLES_DIRECTORY
MemoryOutputStream mo;
auto success = Base64::convertFromBase64 (mo, JUCE_STRINGIFY (PIP_JUCE_EXAMPLES_DIRECTORY));
ignoreUnused (success);
jassert (success);
return mo.toString();
#elif defined PIP_JUCE_EXAMPLES_DIRECTORY_STRING
return File { CharPointer_UTF8 { PIP_JUCE_EXAMPLES_DIRECTORY_STRING } };
#else
auto currentFile = File::getSpecialLocation (File::SpecialLocationType::currentApplicationFile);
auto exampleDir = currentFile.getParentDirectory().getChildFile ("examples");
if (exampleDir.exists())
return exampleDir;
// keep track of the number of parent directories so we don't go on endlessly
for (int numTries = 0; numTries < 15; ++numTries)
{
if (currentFile.getFileName() == "examples")
return currentFile;
const auto sibling = currentFile.getSiblingFile ("examples");
if (sibling.exists())
return sibling;
currentFile = currentFile.getParentDirectory();
}
return currentFile;
#endif
}
inline std::unique_ptr<InputStream> createAssetInputStream (const char* resourcePath)
{
#if JUCE_ANDROID
ZipFile apkZip (File::getSpecialLocation (File::invokedExecutableFile));
return std::unique_ptr<InputStream> (apkZip.createStreamForEntry (apkZip.getIndexOfFileName ("assets/" + String (resourcePath))));
#else
#if JUCE_IOS
auto assetsDir = File::getSpecialLocation (File::currentExecutableFile)
.getParentDirectory().getChildFile ("Assets");
#elif JUCE_MAC
auto assetsDir = File::getSpecialLocation (File::currentExecutableFile)
.getParentDirectory().getParentDirectory().getChildFile ("Resources").getChildFile ("Assets");
if (! assetsDir.exists())
assetsDir = getExamplesDirectory().getChildFile ("Assets");
#else
auto assetsDir = getExamplesDirectory().getChildFile ("Assets");
#endif
auto resourceFile = assetsDir.getChildFile (resourcePath);
jassert (resourceFile.existsAsFile());
return resourceFile.createInputStream();
#endif
}
inline Image getImageFromAssets (const char* assetName)
{
auto hashCode = (String (assetName) + "@juce_demo_assets").hashCode64();
auto img = ImageCache::getFromHashCode (hashCode);
if (img.isNull())
{
std::unique_ptr<InputStream> juceIconStream (createAssetInputStream (assetName));
if (juceIconStream == nullptr)
return {};
img = ImageFileFormat::loadFrom (*juceIconStream);
ImageCache::addImageToCache (img, hashCode);
}
return img;
}
inline String loadEntireAssetIntoString (const char* assetName)
{
std::unique_ptr<InputStream> input (createAssetInputStream (assetName));
if (input == nullptr)
return {};
return input->readString();
}
//==============================================================================
inline Path getJUCELogoPath()
{
return Drawable::parseSVGPath (
"M72.87 84.28A42.36 42.36 0 0130.4 42.14a42.48 42.48 0 0184.95 0 42.36 42.36 0 01-42.48 42.14zm0-78.67A36.74 36.74 0 0036 42.14a36.88 36.88 0 0073.75 0A36.75 36.75 0 0072.87 5.61z"
"M77.62 49.59a177.77 177.77 0 008.74 18.93A4.38 4.38 0 0092.69 70a34.5 34.5 0 008.84-9 4.3 4.3 0 00-2.38-6.49A176.73 176.73 0 0180 47.32a1.78 1.78 0 00-2.38 2.27zM81.05 44.27a169.68 169.68 0 0020.13 7.41 4.39 4.39 0 005.52-3.41 34.42 34.42 0 00.55-6.13 33.81 33.81 0 00-.67-6.72 4.37 4.37 0 00-6.31-3A192.32 192.32 0 0181.1 41a1.76 1.76 0 00-.05 3.27zM74.47 50.44a1.78 1.78 0 00-3.29 0 165.54 165.54 0 00-7.46 19.89 4.33 4.33 0 003.47 5.48 35.49 35.49 0 005.68.46 34.44 34.44 0 007.13-.79 4.32 4.32 0 003-6.25 187.83 187.83 0 01-8.53-18.79zM71.59 34.12a1.78 1.78 0 003.29.05 163.9 163.9 0 007.52-20.11A4.34 4.34 0 0079 8.59a35.15 35.15 0 00-13.06.17 4.32 4.32 0 00-3 6.26 188.41 188.41 0 018.65 19.1zM46.32 30.3a176.2 176.2 0 0120 7.48 1.78 1.78 0 002.37-2.28 180.72 180.72 0 00-9.13-19.84 4.38 4.38 0 00-6.33-1.47 34.27 34.27 0 00-9.32 9.65 4.31 4.31 0 002.41 6.46zM68.17 49.18a1.77 1.77 0 00-2.29-2.34 181.71 181.71 0 00-19.51 8.82A4.3 4.3 0 0044.91 62a34.36 34.36 0 009.42 8.88 4.36 4.36 0 006.5-2.38 175.11 175.11 0 017.34-19.32zM77.79 35.59a1.78 1.78 0 002.3 2.35 182.51 182.51 0 0019.6-8.88 4.3 4.3 0 001.5-6.25 34.4 34.4 0 00-9.41-9.14A4.36 4.36 0 0085.24 16a174.51 174.51 0 01-7.45 19.59zM64.69 40.6a167.72 167.72 0 00-20.22-7.44A4.36 4.36 0 0039 36.6a33.68 33.68 0 00-.45 5.54 34 34 0 00.81 7.4 4.36 4.36 0 006.28 2.84 189.19 189.19 0 0119-8.52 1.76 1.76 0 00.05-3.26zM20 129.315c0 5-2.72 8.16-7.11 8.16-2.37 0-4.17-1-6.2-3.56l-.69-.78-6 5 .57.76c3.25 4.36 7.16 6.39 12.31 6.39 9 0 15.34-6.57 15.34-16v-28.1H20zM61.69 126.505c0 6.66-3.76 11-9.57 11-5.81 0-9.56-4.31-9.56-11v-25.32h-8.23v25.69c0 10.66 7.4 18.4 17.6 18.4 10 0 17.61-7.72 18-18.4v-25.69h-8.24zM106.83 134.095c-3.58 2.43-6.18 3.38-9.25 3.38a14.53 14.53 0 010-29c3.24 0 5.66.88 9.25 3.38l.76.53 4.78-6-.75-.62a22.18 22.18 0 00-14.22-5.1 22.33 22.33 0 100 44.65 21.53 21.53 0 0014.39-5.08l.81-.64-5-6zM145.75 137.285h-19.06v-10.72h18.3v-7.61h-18.3v-10.16h19.06v-7.61h-27.28v43.53h27.28z"
"M68.015 83.917c-7.723-.902-15.472-4.123-21.566-8.966-8.475-6.736-14.172-16.823-15.574-27.575C29.303 35.31 33.538 22.7 42.21 13.631 49.154 6.368 58.07 1.902 68.042.695c2.15-.26 7.524-.26 9.675 0 12.488 1.512 23.464 8.25 30.437 18.686 8.332 12.471 9.318 28.123 2.605 41.368-2.28 4.5-4.337 7.359-7.85 10.909A42.273 42.273 0 0177.613 83.92c-2.027.227-7.644.225-9.598-.003zm7.823-5.596c8.435-.415 17.446-4.678 23.683-11.205 5.976-6.254 9.35-13.723 10.181-22.537.632-6.705-1.346-14.948-5.065-21.108C98.88 13.935 89.397 7.602 78.34 5.906c-2.541-.39-8.398-.386-10.96.006C53.54 8.034 42.185 17.542 37.81 30.67c-2.807 8.426-2.421 17.267 1.11 25.444 4.877 11.297 14.959 19.41 26.977 21.709 2.136.408 6.1.755 7.377.645.325-.028 1.48-.094 2.564-.147z"
);
}
//==============================================================================
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
inline CodeEditorComponent::ColourScheme getDarkCodeEditorColourScheme()
{
struct Type
{
const char* name;
juce::uint32 colour;
};
const Type types[] =
{
{ "Error", 0xffe60000 },
{ "Comment", 0xff72d20c },
{ "Keyword", 0xffee6f6f },
{ "Operator", 0xffc4eb19 },
{ "Identifier", 0xffcfcfcf },
{ "Integer", 0xff42c8c4 },
{ "Float", 0xff885500 },
{ "String", 0xffbc45dd },
{ "Bracket", 0xff058202 },
{ "Punctuation", 0xffcfbeff },
{ "Preprocessor Text", 0xfff8f631 }
};
CodeEditorComponent::ColourScheme cs;
for (auto& t : types)
cs.set (t.name, Colour (t.colour));
return cs;
}
inline CodeEditorComponent::ColourScheme getLightCodeEditorColourScheme()
{
struct Type
{
const char* name;
juce::uint32 colour;
};
const Type types[] =
{
{ "Error", 0xffcc0000 },
{ "Comment", 0xff00aa00 },
{ "Keyword", 0xff0000cc },
{ "Operator", 0xff225500 },
{ "Identifier", 0xff000000 },
{ "Integer", 0xff880000 },
{ "Float", 0xff885500 },
{ "String", 0xff990099 },
{ "Bracket", 0xff000055 },
{ "Punctuation", 0xff004400 },
{ "Preprocessor Text", 0xff660000 }
};
CodeEditorComponent::ColourScheme cs;
for (auto& t : types)
cs.set (t.name, Colour (t.colour));
return cs;
}
#endif
//==============================================================================
// This is basically a sawtooth wave generator - maps a value that bounces between
// 0.0 and 1.0 at a random speed
struct BouncingNumber
{
BouncingNumber()
: speed (0.0004 + 0.0007 * Random::getSystemRandom().nextDouble()),
phase (Random::getSystemRandom().nextDouble())
{
}
float getValue() const
{
double v = fmod (phase + speed * Time::getMillisecondCounterHiRes(), 2.0);
return (float) (v >= 1.0 ? (2.0 - v) : v);
}
protected:
double speed, phase;
};
struct SlowerBouncingNumber : public BouncingNumber
{
SlowerBouncingNumber()
{
speed *= 0.3;
}
};
#endif // PIP_DEMO_UTILITIES_INCLUDED

Some files were not shown because too many files have changed in this diff Show More