Преглед изворни кода

Merge pull request #1655 from malcolmhoward/custom_modules_in_cpp_extended_example

Added example for binding to external C++ libary #513
Rémi Verschelde пре 6 година
родитељ
комит
1c24ed7d7a

+ 1 - 1
README.md

@@ -18,7 +18,7 @@ To edit an existing page, locate its .rst source file and open it in your favori
 
 To add a new page, create a .rst file with a meaningful name in the section you want to add a file to, e.g. `tutorials/3d/light_baking.rst`. Write its content like you would do for any other file, and make sure to define a reference name for Sphinx at the beginning of the file (check other files for the syntax), based on the file name with a "doc_" prefix (e.g. `.. _doc_light_baking:`).
 
-You should then add your page to the relevant "toctree" (table of contents). By convention, the files used to define the various levels of toctree are prefixed with an underscore, so in the above example the file should be referenced in `tutorials/3d/_3d_graphics.rst`. Add your new filename to the list on a new line, using a relative path and no extension, e.g. here `light_baking`.
+You should then add your page to the relevant "toctree" (table of contents, e.g. `tutorials/3d/index.rst`). By convention, the files used to define the various levels of toctree are prefixed with an underscore, so in the above example the file should be referenced in `tutorials/3d/_3d_graphics.rst`. Add your new filename to the list on a new line, using a relative path and no extension, e.g. here `light_baking`.
 
 ### Sphinx and reStructuredText syntax
 

+ 204 - 0
development/cpp/binding_to_external_libraries.rst

@@ -0,0 +1,204 @@
+.. _doc_binding_to_external_libraries:
+
+Binding to external libraries
+=============================
+
+Modules
+-------
+
+The Summator example in :ref:`_doc_custom_modules_in_c++` is great for small, custom modules, but
+what if you want to use a larger, external library?  Let's look at an example
+using Festival, a speech synthesis (text-to-speech) library written in C++.
+
+To bind to an external library, set up a module directory similar to the Summator example:
+
+::
+
+    godot/modules/tts/
+
+Next, you will create a header file with a simple TTS class:
+
+.. code:: cpp
+
+    /* tts.h */
+    #ifndef GODOT_TTS_H
+    #define GODOT_TTS_H
+
+    #include <reference.h>
+
+    class TTS : public Reference {
+        GDCLASS(TTS, Reference);
+
+    protected:
+        static void _bind_methods();
+
+    public:
+        bool say_text(String txt);
+
+        TTS();
+    };
+
+    #endif // GODOT_TTS_H
+
+And then you'll add the cpp file.
+
+.. code:: cpp
+
+    /* tts.cpp */
+
+    #include "tts.h"
+    #include "festival/src/include/festival.h"
+
+    bool TTS::say_text(String txt) {
+
+        //convert Godot String to Godot CharString to C string
+        return festival_say_text(txt.ascii().get_data());
+    }
+
+    void TTS::_bind_methods() {
+
+        ClassDB::bind_method(D_METHOD("say_text", "txt"), &TTS::say_text);
+    }
+
+    TTS::TTS() {
+        festival_initialize(true, 210000); //not the best way to do it as this should only ever be called once.
+    }
+
+Just as before, the new class needs to be registered somehow, so two more files
+need to be created:
+
+::
+
+    register_types.h
+    register_types.cpp
+
+With the following contents:
+
+.. code:: cpp
+
+    /* register_types.h */
+
+    void register_tts_types();
+    void unregister_tts_types();
+    /* yes, the word in the middle must be the same as the module folder name */
+
+.. code:: cpp
+
+    /* register_types.cpp */
+
+    #include "register_types.h"
+
+    #include "class_db.h"
+
+    #include "tts.h"
+
+    void register_tts_types() {
+        ClassDB::register_class<TTS>();
+    }
+
+    void unregister_tts_types() {
+       //nothing to do here
+    }
+
+Next, you need to create a ``SCsub`` file so the build system compiles
+this module:
+
+.. code:: python
+
+    # SCsub
+    Import('env')
+
+    env_tts = env
+    env_tts.add_source_files(env.modules_sources,"*.cpp") # Add all cpp files to the build
+
+You'll need to install the external library on your machine to get the .a library files.  See the library's official
+documentation for specific instructions on how to do this for your operation system.  We've included the
+installation commands for Linux below, for reference.
+
+::
+    sudo apt-get install festival festival-dev <-- Installs festival and speech_tools libraries
+    apt-cache search festvox-* <-- Displays list of voice packages
+    sudo apt-get install festvox-don festvox-rablpc16k festvox-kallpc16k festvox-kdlpc16k <-- Installs voices
+
+.. note::
+    **Important** The voices that Festival uses (and any other potential external/3rd-party
+    resource) all have varying licenses and terms of use; some (if not most) of them may be
+    be problematic with Godot, even if the Festival Library itself is MIT License compatible.
+    Please be sure to check the licenses and terms of use.
+
+The external library will also need to be installed inside your module to make the source
+files accessible to the compiler, while also keeping the module code self-contained.  The
+festival and speech_tools libraries can be installed from the modules/tts/ directory via
+git using the following commands:
+
+::
+    git clone https://github.com/festvox/festival
+    git clone https://github.com/festvox/speech_tools
+
+If you don't want the external repository source files committed to your repository, you
+can link to them instead by adding them as submodules (from within the modules/tts/ directory), as seen below:
+
+::
+    git submodule add https://github.com/festvox/festival
+    git submodule add https://github.com/festvox/speech_tools
+
+.. note::
+    **Important** Please note that Git submodules are not used in the Godot repository.  If
+    you are developing a module to be merged into the main Godot repository, you should not
+    use submodules.  If your module doesn't get merged in, you can always try to implement
+    the external library as a GDNative C++ plugin.
+
+To add include directories for the compiler to look at you can append it to the
+environment's paths:
+
+.. code:: python
+
+    env_tts.Append(CPPPATH="speech_tools/include", "festival/src/include") # this is a path relative to /modules/tts/
+    # http://www.cstr.ed.ac.uk/projects/festival/manual/festival_28.html#SEC132 <-- Festival library documentation
+    env_tts.Append(LIBPATH=['libpath']) # this is a path relative to /modules/tts/ where your .a library files reside
+    # You should check with the documentation of the external library to see which library files should be included/linked
+    env_tts.Append(LIBS=['Festival', 'estools', 'estbase', 'eststring'])
+
+If you want to add custom compiler flags when building your module, you need to clone
+`env` first, so it won't add those flags to whole Godot build (which can cause errors).
+Example `SCsub` with custom flags:
+
+.. code:: python
+
+    # SCsub
+    Import('env')
+
+    env_tts = env
+    env_tts.add_source_files(env.modules_sources,"*.cpp")
+    env_tts.Append(CXXFLAGS=['-O2', '-std=c++11'])
+
+The final module should look like this:
+
+::
+
+    godot/modules/tts/festival/
+    godot/modules/tts/libpath/libestbase.a
+    godot/modules/tts/libpath/libestools.a
+    godot/modules/tts/libpath/libeststring.a
+    godot/modules/tts/libpath/libFestival.a
+    godot/modules/tts/speech_tools/
+    godot/modules/tts/config.py
+    godot/modules/tts/tts.h
+    godot/modules/tts/tts.cpp
+    godot/modules/tts/register_types.h
+    godot/modules/tts/register_types.cpp
+    godot/modules/tts/SCsub
+
+Using the module
+----------------
+
+You can now use your newly created module from any script:
+
+::
+
+    var t = TTS.new()
+	var script = "Hello world.  This is a test!"
+	var is_spoken = t.say_text(script)
+	print('is_spoken: ', is_spoken)
+
+And the output will be ``is_spoken: True`` if the text is spoken.

+ 5 - 1
development/cpp/custom_modules_in_cpp.rst

@@ -168,7 +168,7 @@ string list:
     src_list = ["summator.cpp", "other.cpp", "etc.cpp"]
     env.add_source_files(env.modules_sources, src_list)
 
-This allows for powerful possibilities using Python to contruct the file list
+This allows for powerful possibilities using Python to construct the file list
 using loops and logic statements. Look at some of the other modules that ship
 with Godot by default for examples.
 
@@ -241,6 +241,10 @@ You can now use your newly created module from any script:
 
 And the output will be ``60``.
 
+.. seealso:: The previous Summator example is great for small, custom modules, but
+             what if you want to use a larger, external library?  Refer to :ref:`_doc_binding_to_external_libraries`
+             for details about binding to external libraries.
+
 Improving the build system for development
 ------------------------------------------
 

+ 1 - 0
development/cpp/index.rst

@@ -12,6 +12,7 @@ Engine development
    object_class
    inheritance_class_tree
    custom_modules_in_cpp
+   binding_to_external_libraries
    custom_resource_format_loaders
    custom_audiostreams
    custom_godot_servers