SmartBody : Building SmartBody for the web with Javascript

Build SmartBody From Source

  • Install Emscripten
  • Build Supporting Libraries
  • Build SmartBody
  • Rendering using WebGL friendly subset of OpenGL
  • Useful links

Install Emscripten

SmartBody JavaScript uses Emscripten to port SmartBody and its external supporting libraries from C/C++ into highly optimizable Javascript code in asm.js format. This section briefly introduce how to install Emscripten under Windows and Linux and notes about the installation. For more information please refer to Emscripten Installation.

  • Emscripten Setup in Linux
    1. Check Environment

    python --version # Check for Python
    nodejs --version # Check for node.js on Linux
    git --version # Check for git
    java -version # Check for Java
    gcc --version # Check for gcc / g++
    g++
    cmake --version # Check for cmake#If anything above is missing apt-get it:sudo apt-get install build-essential cmake python2.7 nodejs default-jre git-core

    2. Emcripten download and installation:

    1) Download the portable version of Emscripeten emsdk-portable.tar.gz
    2) Unzip it and into folder of emsdk_portable
    3) Open a command prompt inside the SDK directory and run the following commands

    # Fetch the latest registry of available tools.
    ./emsdk update
    # Download and install the latest SDK tools.
    ./emsdk install latest
    # Make the "latest" SDK "active"
    ./emsdk activate latest
    # Set the current Emscripten path on Linux/Mac OS X
    source ./emsdk_env.sh
    Icon

    Note:
    1) Whenever you change the location of the Portable SDK (e.g. take it to another computer), re-run the ./emsdk activate latest command and source ./emsdk_env.sh for Linux.
    2) Everytime you open a new terminal you need to source ./emsdk_env.sh to set the system path

    4) Type emcc -v to check the installation, if you encounter the following error message, edit the ~/.emscripten change the line NODE_JS = 'node' to NODE_JS = 'nodejs' save and close.

    Icon

    WARNING root: (Emscripten: settings file has changed, clearing cache)

    WARNING root: cannot check node version: [Errno 2] No such file or directory

    INFO root: (Emscripten: Running sanity checks)

    Checking JS engine ['node'] failed. Check ~/.emscripten. Details: [Errno 2] No such file or directory

    CRITICAL root: The JavaScript shell used for compiling (['node']) does not seem to work, check the paths in ~/.emscripten

    5) Check the emcc -v again, you should be able to see the version of emcc as follows:

    Icon

    WARNING root: (Emscripten: settings file has changed, clearing cache)
    INFO root: (Emscripten: Running sanity checks)
    emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 1.32.0
    clang version 3.6.0 (https://github.com/kripken/emscripten-fastcomp-clang/ ba2eba3c4548c27b82bf945e8eba37bf630585a8) (https://github.com/kripken/emscripten-fastcomp/ bdf2fc7e758ee9a4594bed666d0a7a86e6e787b1)
    Target: x86_64-unknown-linux-gnu
    Thread model: posix
    Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/4.8
    Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/4.8.2
    Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/4.9
    Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/4.9.1
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.7
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.7.3
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8.2
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
    Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.1
    Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8
    Candidate multilib: .;@m64
    Selected multilib: .;@m64
    INFO root: (Emscripten: Running sanity checks)

  • Emscripten Setup in Windows with Visual Studio 2010

    1. Download the Windows version of Emscripten: Emscripten SDK Offline Installer
    2. Run the installer and follow the instruction to install Emscripten
    3. After the installation, check it with the command line: C:\Program Files\Emscripten>emcc -v you should be able to see the version of Emscripten.

    Icon

    emcc (Emscripten GCC-like replacement + linker emulating GNU ld ) 1.30.0

    clang version 3.5.0

    Target: x86_64-pc-windows-msvc

    Thread model: posix

    INFO root: (Emscripten: Running sanity checks)

    4. Visual Studio Setup

    1) Open SmartBodu VS 2010 project

    2) Open: Toolbar->Build->Configuration Manager

    3) Active Solution Platform drop-down , you should be able to see Emscripten Selection and copy settings from Win32

  • Make sure the version is the same under Windows and Linux
    If you need to build some libraries in Linux and others in Windows, please make sure the version of Emscripten is uniformed. This is very important, cause using different version of Emscripten may result in the failure of linking static libraries. If the versions are different, you need unify them. For example, if the version under Windows is 1.30.0 with Clang 3.5, but the version under Linux is 1.33.0 and Clang 3.7, you need to either upgrade Windows version or downgrade Linux version. From my experience, downgrade Linux version is easier.
    Downgrade Linux version of Emscripten
    1. Using ./emsdk list to see what has been installed of Emscripten:

    Icon

    The following individual tools exist:

      clang-incoming-32bit

      clang-incoming-64bit

      clang-master-32bit

      clang-master-64bit    INSTALLED

      emscripten-1.29.0

      *   emscripten-1.30.0    INSTALLED

      emscripten-incoming-32bit

      emscripten-master-32bit

      emscripten-incoming-64bit

      emscripten-master-64bit    INSTALLED

    The following Emscripten SDK versions are available:

      sdk-incoming-32bit

      sdk-incoming-64bit

      sdk-master-32bit

      sdk-master-64bit    INSTALLED

    Items marked with * are activated for the current user.

    To access the historical archived versions, type 'emsdk list --old'

    2. Install emscripten:

    Suppose we need to install emscripten-1.30.0, then we using cmd: ./emsdk install emscripten-1.30.0. After a while it will be installed, use ./emsdk list to check the installation. Also remember to activate it using emsdk activate emscripten-1.30.0
    Also please note as indicated in the reference page, you should use the same branch (incoming, or master) for building all three repositories.

    Icon

    Mixing incoming and master branches may result in errors when building the three repositories.

    Therefore, we need also change LLVM and Clang version.
    You can find the right version of LLVM and Clang version on the following repo, distinguished by tags:
    https://github.com/kripken/emscripten-fastcomp
    https://github.com/kripken/emscripten-fastcomp-clang
    Please follow the instruction in the reference link to build Fastcomp, there is only one thing worth mentioning, when you checkout the git repo, make sure you checkout the right tags:
    The following git commands helps you checkout the right version:

    git clone <repo-address>
    git tag -l
    git checkout <tag-name>
    git branch -D master
    git checkout -b master

    3. Use emcc -v again to check the version of Emscripten and Clang.

    Icon

    1) Useful command: Sometimes, after you installed the latest version of Emscirpten, you need to clean the cache by: emcc --clear-cache --clear-ports

    2) When write this document, the Emscripten has been updated to 1.34.0 both under Windows and Linux. Our Smartbody compilation used Emscripten 1.30.0, we will test the update soon

Build Supporting Libraries

Smartbody/Javascript relies on many supporting libraries such as Boost, Xerces, VHCL and more. We first need to compile those libraries from C/C++ from LLVM bitcode. 

  • Xerces-c
    Version: 3.1.2
    Platform: Linux
    1. Download package and unzip
    2. Run command: $ emconfigure ./configure --disable-threads
    3. Run command: $ emmake make
    4. Location: ./src/.libs/libxerces-c.a
    5. Don't delete .c files in xerces-c\include\xercesc\util

  • Boost
    Version: 1.58.0
    Platform: Linux
    Credit to Ariel Malka's Github project
    1. Clone the repository into your local directory from https://github.com/ZengruiWang/chronotext-boost
    2. Run: bash setup.sh which downloads the boost_1_58_0 package and some patches
    3. Edit 'build-emscripten.sh'
      1) Specify EMSCRIPTEN_BIN = '/your/path/to/emsdk_portable/emscripten/1.30.0' (where your Emscripten SDK locates)
      2) Specify the libraries to build: --without-python --without-coroutine --without-context
    4. Run: bash build-emscripten.sh
    5. All compiled libs is under ./chronotext-boost/lib/emscripten/

  • ODE
    Version: 0.11.1
    Platform: Linux
    1. Download package and unzip
    2. Run command: $emconfigure ./configure --disable-demos --without-x --enable-double-precision
    3. Run command: $emmake make
    4. Complied libs location:  
        ./ode/src/joints/.libs/libjoints.a
        ./ode/src/.libs/libode.a    
        ./ode/src/.libs/libfast.a    
        ./OPCODE/.libs/libOPCODE.a    
       ./OPCODE/Ice/.libs/libIce.a

  • Protobuf
    Version: protobuf-2.5.0
    Platform: Windows Visual Studio 2010
    Instruction:
    1. Modify protobuf-2.5.0\src\google\protobuf\stubs\hash.h line 42: append at the end " && !defined(EMSCRIPTEN) "
    2. Open vsprojects/protobuf.sln in Microsoft Visual Studio.
    3. For project "libprotobuf" 
        1) Change the extension of all source files from .cc to .cpp 
        2) Replace and add the following files in patch directory to the folder: ..\src\google\protobuf\stubs
    atomicops.h
    atomicops_internals_emscripten.h
    platform_macros.h
    common.cpp
        3) Also delete the Additional Options in the project properties->Clang C/C++->Command Line
        4) Compile the project, DONE
    4. For project "libprotoc"
        1) Change the extension of all source files from .cc to .cpp 
        2) Also in the header folder, there is also a .cc file java_doc_comment.cc change its extension to .cpp too
        3) Also delete the Additional Options in the project properties->Clang C/C++->Command Line
        4) Compile the project, DONE  
    5. Modify the extract_includes.bat file: add "copy ..\src\google\protobuf\stubs\atomicops_internals_emscripten.h include\google\protobuf\stubs\atomicops_internals_emscripten.h
    6. Run the extract_includes.bat to generate the include directory

    Icon

    Note: we haven't tested its functionality, we just want to resolve those unresolved symbols during the linking phase

  • FreeALUT
    Version: unknown(under emscripten/1.30.0/test/freealut)
    Platform: Linux
    1. Run command: $ emconfigure ./configure --disable-threads
    2. Run command: $ emmake make
    3. Location: emsdk_portable/emscripten/1.30.0/tests/freealut

  • LibSNDFile
    Version: 1.0.25
    Platform: Linux
    1) Download package and unzip
    2) Run command: $emconfigure ./configure
    3) Copy and Paste config.h and sndfile.h to ./src
    4) Eddit sndfile.c in the function SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo)   Comment out the assert(sizeof(sf_count_t) == 8);
    5) Run command: $emmake make
    6) Complied libs location:    
        ./src/.libs/libcommon.a    
        ./src/.libs/libsndfile.a

  • OpenAL
    Out of box support

    #if defined(EMSCRIPTEN_BUILD)
    #include <AL/al.h> 
    #include <AL/alc.h>
    #include <AL/alut.h>
    #endif
  • Zlib
    Replace deflate.c and zconf.h with the following ones: deflate.c and zconf.h in core\smartbody\SmartBody\src\external\zlib-1.2.5

  • Eigen
    This is a new library for Smartbody/Javascript to replace the Boost Numeric Bindings LAPACK/BLAS
    Version: 3.2.6
    Platform: Windows
    1) Download package and unzip
    2) No need to compile it

  • VHCL

    Platform: Visual Studio 2010
    1. Configuration project properties
        1) vhcl->Properties->Configureation Properties->General->Configureation Type->Static LLVM Bitcode Library(.bc)
        2) vhcl->Properties->Clang C/C++->Command Line->Additional Options #Delete "/MP"
        3) Additional Include Directories(-I)

    include
    ..\..\javascript\lib\vhcl\libsndfile\include
    ..\..\javascript\lib\vhcl\freealut\include

        4) Delete WIN32 and NDEBUG in Preprocessor
        5) Exclude nocturnal from poject
    2. Source code modification
    1) In vhcl_platform.h, add Emscripten platform

    //We first need to undef _WIN32, because it is explicitly and errantly defined at somewhere, we will look into it later. For now we just undefined it.
    #if defined(EMSCRIPTEN)
    #undef _WIN32
    #endif
     
    // Platform identification.
    #if defined(_WIN32)
    ....
    #elif defined(EMSCRIPTEN)
       #define EMSCRIPTEN_BUILD 1
    #else
       #define UNKNOWN_BUILD 1
    #endif

    Also modify the build type part(Line 116)

    #else
       #if defined(LINUX_BUILD) || defined(MAC_BUILD) || defined(IPHONE_BUILD) || defined(ANDROID_BUILD) || defined(FLASH_BUILD) || defined(EMSCRIPTEN_BUILD)
          #define RELEASE_BUILD 1
       #else
          #define UNKNOWN_BUILD 1
       #endif
    #endif

    2) In vhcl_audio.cpp include OpenAL and FreeAlut header files the same as LINUX_BUILD

    #elif defined(LINUX_BUILD) || defined(EMSCRIPTEN_BUILD)
    #include <AL/al.h> 
    #include <AL/alc.h>
    #include <AL/alut.h>
    Icon

    As stated before, OpenAL is supported by Emscripten, so we only need to use angle brackets to include al.h and alc.h. The alut.h is located at ..\..\javascript\lib\vhcl\freealut\include\AL

    3) In vhcl_assert.h, modified the following part by adding EMSCRIPTEN_BUILD

    #if defined(VHCL_ASSERTS_ENABLED)
       #define POW2_ASSERTS_ENABLED
    #elif defined(VHCL_ASSERTS_DISABLED)
    #else
       #if defined(DEBUG_BUILD) && !defined(EMSCRIPTEN_BUILD)
          #define POW2_ASSERTS_ENABLED
       #elif defined(RELEASE_BUILD)
          //#define POW2_ASSERTS_ENABLED
       #endif
    #endif

    4) In vhcl_log.cpp

    void LOG( const char * message, ... )
    {
    #if defined(VHCL_LOG_FUNCTION_ENABLED)
    #if defined(EMSCRIPTEN)
        va_list argList;
        char buf[BUFSIZ];
        va_start( argList, message );
        vsprintf ( buf, message, argList );
        printf ( "%s\n", buf );
        va_end ( argList );
    #else
        va_list argList;
        va_start( argList, message );
        vhcl::Log::g_log.vLog( message, argList );
        va_end( argList );
    #endif
    #endif
    }

    5) In vhcl_string.cpp

    #if defined(MAC_BUILD) || defined(ANDROID_BUILD) || defined(EMSCRIPTEN_BUILD)
    #include <sys/select.h>
    #endif
    Icon

    Delete folder libsndfile and openal, they are in ./javascript/lib/vhcl

  • SteerLib
    1. Configuration project properties
        1) steerlib->Properties->Configuration Properties->General->Configureation Type->Static LLVM Bitcode Library(.bc)
        2) steerlib->Properties->Clang C/C++->Command Line->Additional Options #Delete "/MP"
        3) steerlib->Properties->Configuration Properties->General->Output Directory: ..\..\..\build\Emscripten\$(Configuration)\
        4) Delete all preprocessor
        5) Additional Include Directories(-I)

    ..\..\include
    ..\..\..\external
    ..\..\..\external\tinyxml
    ..\..\..\pprAI\include

    2. Source code modification
    1) In util/HighResCounter.h

    #define __UTIL_HIGH_RES_COUNTER_H__
    #if defined(EMSCRIPTEN)
    #undef _WIN32
    #endif
    Icon

    We first need to undef _WIN32, because it is explicitly and errantly defined at somewhere, we will look into it later. For now we just undefined it.

    static inline unsigned long long getHighResCounterValue()
    #elif defined (BUILD_ANDROID) || defined (EMSCRIPTEN)
       timespec timeInfo;
       clock_gettime(CLOCK_REALTIME, &timeInfo);
       unsigned long long int nanosecs = ((unsigned long long)timeInfo.tv_sec)*1000000000  +  ((unsigned long long)timeInfo.tv_nsec);
       return nanosecs;
    Icon

    I am not so sure about how Emscripten provides the high resolution counter value, for now, we will use the same way as Android uses, more information about Emscripten counter could be found here

    2) In simulation/SimulationEngine.cpp add Emscripten platform support, since it uses static library

    #if defined(SB_IPHONE) || defined(__ANDROID__) || defined(__FLASHPLAYER__) || defined(EMSCRIPTEN)
    #include "PPRAIModule.h"
    #endif 
     
    ...
    //(around line 671)
    #if defined(SB_IPHONE) || defined(__ANDROID__) || defined(EMSCRIPTEN)
        newModule = new PPRAIModule;
    #else
  • pprAI

    1. Configuration project properties

    1) pprAI->Properties->Configureation Properties->General->Configureation Type->Static LLVM Bitcode Library(.bc)
    2) pprAI->Properties->Configuration Properties->General->Output Directory: ..\..\..\build\Emscripten\$(Configuration)\3) Delete all preprocessor
    4) Additional Include Directories(-I)

    ..\..\include
    ..\..\..\steerlib\include
    ..\..\..\external
    Icon

    Where to put those libraries?

    We created a folder in the top directory level for example: 
    SmartBody-Javascript/javascript/lib/boost
    SmartBody-Javascript/javascript/lib/ode
    SmartBody-Javascript/javascript/lib/protobuf
    SmartBody-Javascript/javascript/lib/xerces-c SmartBody-Javascript/javascript/lib/eigen

    For libsndfile and freealut, they are in the subdirectory of vhcl
    SmartBody-Javascript/javascript/lib/vhcl/freealut
    SmartBody-Javascript/javascript/lib/vhcl/libsndfile

Build SmartBody

  • Configuration project properties
    1. SmartBody->Properties->Configuration Properties->General->Output Directory: $(Configuration)\
    2. SmartBody->Properties->Configureation Properties->General->Configureation Type->Static LLVM Bitcode Library(.bc)
    3. Additional Include Directories(-I)

    .\src
    ..\..\..\javascript\lib\protobuf\include
    ..\..\..\javascript\lib\xerces-c\include
    ..\..\..\javascript\lib\boost
    ..\..\..\javascript\lib\ode\include
    ..\..\..\javascript\lib\eigen
    ..\..\..\lib\vhcl\include
    ..\..\..\core\smartbody\steersuite-1.3\steerlib\include
    ..\..\..\core\smartbody\steersuite-1.3\pprAI\include
    ..\..\..\core\smartbody\steersuite-1.3\external

    4. Preprocessor

    SB_NO_ASSIMP
    SB_NO_PYTHON
    SB_NO_BONEBUS
    SB_NO_VHMSG
    SB_EXPORTS
    dDOUBLE
    _WINDOWS
    _USRDLL
    _CRT_SECURE_NO_WARNINGS
    _SCL_SECURE_NO_WARNINGS
    BOOST_ALL_NO_LIB
    BOOST_TYPEOF_SILENT

    5. Clang C/C++->Command Line->Additional Options: delete /MP and add: --bind, which compiles the source code using the Embind bindings to connect C/C++ and JavaScript.
    6. Open SmartBody.vcxproj, search /bigobj ,delete the following line:

    <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Emscripten'">/bigobj %(AdditionalOptions)</AdditionalOptions>
    <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Emscripten'">/bigobj %(AdditionalOptions)</AdditionalOptions>

    7. Project Property->Configuration Properties->Configure Type, switch to Browser Application(.html), and click apply, then go to Emcc Linker->Input, delete all of Additional Dependencies. Finally, switch back to Static LLVM Bitcode(.bc)
    8. Clear all Build Events

  • Source code modification

    1. In controllers/me_ct_motion_example.cpp, we don't need those debug information.

    #if defined(_DEBUG) && !defined(EMSCRIPTEN)
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
    #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
    #define new DEBUG_NEW
    #endif

    In controllers/me_ct_motion_example.hpp, delete

    #ifndef EMSCRIPTEN
    #include "controllers/me_ct_ublas.hpp"
    #endif

    and leave it as #include "controllers/me_ct_ublas.hpp"

    2. In controllers/me_ct_physics_controller.cpp, we need to pass a pointer to handleEvent or it will cause pointer delete exception when bind to Javascript using Embind

    bool MeCtPhysicsController::controller_evaluate(double t, MeFrameData& frame)
            if (colRecords.size() > 0 && !hasGaze)
            {
               	...
    			//around line 97
    			std::string cmd = eventMsg;
    #if !defined(EMSCRIPTEN)
              	...
    #else
                SmartBody::SBMotionEvent* motionEvent = new SmartBody::SBMotionEvent();
                std::string eventType = "collision";
                motionEvent->setType(eventType);            
                motionEvent->setParameters(cmd);
                SmartBody::SBEventManager* manager = SmartBody::SBScene::getScene()->getEventManager();        
                manager->handleEvent(motionEvent,t);
    #endif
             ...
            }
            else if (hasGaze && t > fadeOutTime)
            {
               ...
    		 	//around line 124
    		   std::string cmd = eventMsg;
    #if !defined(EMSCRIPTEN)
             ...
    		
    #else
                SmartBody::SBMotionEvent *motionEvent = new SmartBody::SBMotionEvent();
                std::string eventType = "collision";
                motionEvent->setType(eventType);                        
                motionEvent->setParameters(cmd);
                SmartBody::SBEventManager* manager = SmartBody::SBScene::getScene()->getEventManager();    
                manager->handleEvent(motionEvent,t);
    #endif
    		}
    
    

    3. In controllers/me_ct_ublas.cpp

    #if defined(EMSCRIPTEN)
    #include <Eigen/Dense>
    #include <Eigen/SVD>
    #endif
    using namespace Eigen;
    void MeCtUBLAS::matrixMatMult(const dMatrix& mat1, const dMatrix& mat2, dMatrix& mat3)
    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    	blas::gemm(mat1,mat2,mat3);	
    #endif
    #if defined(EMSCRIPTEN)
    	MatrixXd m1(mat1.size1(), mat1.size2()), m2(mat2.size1(),mat2.size2()), m3(mat3.size1(), mat3.size2());
    	for(unsigned int i = 0; i < mat1.size1(); ++i)
    		for(unsigned int j = 0; j < mat1.size2(); ++j)
    			m1(i, j) = mat1(i, j);
    	for(unsigned int i = 0; i < mat2.size1(); ++i)
    		for(unsigned int j = 0; j < mat2.size2(); ++j)
    			m2(i, j) = mat2(i, j);
    	m3 = m1 * m2;
    	//copy result to mat3
    	for(unsigned int i = 0; i < mat3.size1(); ++i)
    		for(unsigned int j = 0; j < mat3.size2(); ++j)
    			mat3(i, j) = m3(i, j);
    #endif
    void MeCtUBLAS::matrixVecMult(const dMatrix& mat1, const dVector& vin, dVector& vout)
    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    	blas::gemv('N',1.0,mat1,vin,0.0,vout);	
    #endif
    #if defined(EMSCRIPTEN)
    	MatrixXd m1(mat1.size1(), mat1.size2());
    	for(size_t i = 0; i < mat1.size1(); ++i)
    		for(size_t j = 0; j < mat1.size2(); ++j)
    			m1(i, j) = mat1(i, j);
    	VectorXd vIn(vin.size()), vOut;
    	for(size_t i = 0; i < vin.size(); ++i)
    		vIn(i) = vin(i);
    	vOut = m1 * vIn;
    	for(size_t i = 0; i < vout.size(); ++i)
    		vout(i) = vOut(i);
    #endif
    bool MeCtUBLAS::inverseMatrix( const dMatrix& mat, dMatrix& inv )
    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    	lapack::gesv(A,inv);
    #endif
    #if defined(EMSCRIPTEN)
    	MatrixXd m(mat.size1(), mat.size2()), mInv;
    	for(size_t i = 0; i < mat.size1(); ++i)
    		for(size_t j = 0; j < mat.size2(); ++j)
    			m(i, j) = mat(i, j);
    	mInv = m.inverse();
    	for(size_t i = 0; i < inv.size1(); ++i)
    		for(size_t j = 0; j < inv.size2(); ++j)
    			inv(i, j) = mInv(i, j);
    #endif
    bool MeCtUBLAS::matrixSVD( const dMatrix& A, dVector& S, dMatrix& U, dMatrix& V )
    #if !defined(__ANDROID__) && !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    	dMatrix M(A);
    	lapack::gesvd(M,S,U,V);
    #endif
    #if defined(EMSCRIPTEN)
    	MatrixXd mA;
    	for(size_t i = 0; i < A.size1(); ++i)
    		for(size_t j = 0; j < A.size2(); ++j)
    			mA(i, j) = A(i, j);
    	JacobiSVD<MatrixXd> svd(mA, ComputeThinU | ComputeThinV);
    	VectorXd s = svd.singularValues();
    	MatrixXd mU = svd.matrixU();
    	MatrixXd mV = svd.matrixV();
    	for(int i = 0; i < s.size(); ++i)
    		S(i) = s(i);
    	for(int i = 0; i < mU.innerSize(); ++i)
    		for(int j = 0; j < mU.outerSize(); ++j)
    			U(i, j) = mU(i, j);
    	for(int i = 0; i < mV.innerSize(); ++i)
    		for(int j = 0; j < mV.outerSize(); ++j)
    			V(i, j) = mV(i, j);
    #endif
    Icon

    Numeric Library Bindings for Boost is not ported well, so we use Eigen instead.

    4. In controllers/MeCtBodyReachState.cpp, we need to pass a pointer to handleEvent or it will cause pointer delete exception when bind to Javascript using Embind

    void ReachHandAction::sendReachEvent(const std::string& etype, const std::string& cmd, float time /*= 0.0*/ )
    {
    #if defined(EMSCRIPTEN)
        std::string eventType = etype;        
        SmartBody::SBMotionEvent* motionEvent = new SmartBody::SBMotionEvent();
        motionEvent->setType(eventType);            
        motionEvent->setParameters(cmd);
        SmartBody::SBEventManager* manager = SmartBody::SBScene::getScene()->getEventManager();        
        manager->handleEvent(motionEvent,time);
        
    #else
      ...
    #endif
    }

    5. In external/faceshift/fsbinarystream.cpp find all lines of #if _MSC_VER == 1500 and replace with #if _MSC_VER == 1500 || defined(EMSCRIPTEN)
    6. In external/faceshift/fsbinarystream.h find #if _MSC_VER == 1500 and replace with #if _MSC_VER == 1500 || defined(EMSCRIPTEN)
    7. In SOIL/SOIL.c, we use OpenGL ES 2.0

    #elif defined(__FLASHPLAYER__)
        #include <GL/gl.h>
    #elif defined(EMSCRIPTEN)
        #include <GLES2/gl2.h>
        #include <GLES2/gl2ext.h>

    Modify the following part, since some openGL commands in desktop are not supported in OpenGL ES 2.0

    //around line 99
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
    #define GL_CLAMP GL_CLAMP_TO_EDGE;
    #endif
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    typedef void (APIENTRY* P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);
    P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;
    #endif
    unsigned int SOIL_internal_create_OGL_texture
    //around line 1020
    {    
    	/*    variables    */
        unsigned char* img;
        unsigned int tex_id;
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    	...
    #endif
        return tex_id;
    }
    
    unsigned int SOIL_direct_load_DDS_from_memory
    //around line 1774
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
       soilGlCompressedTexImage2D(cf_target, 0, S3TC_type, width, height, 0, DDS_main_size, DDS_data );
    #endif
    ...
    //around line 1085
    #if !defined(__ANDROID__) && !defined(EMSCRIPTEN)
         mip_size = ((w+3)/4)*((h+3)/4)*block_size;
         soilGlCompressedTexImage2D(cf_target, i,S3TC_type, w, h, 0,mip_size, &DDS_data[byte_offset] );
    #endif
    ...
    //around 1850
    #if defined(EMSCRIPTEN)
    	unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;
    #else
    	unsigned int clamp_mode = GL_CLAMP;
    #endif
    int query_DXT_capability( void )
    //around line 2007
    /*    and find the address of the extension function    */
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    	P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;
    #else
    	void* ext_addr = NULL;
    #endif
    ...
    //around line 2044
    #elif defined(__FLASHPLAYER__) || defined(__ANDROID__) || defined(SB_IPHONE) || defined (EMSCRIPTEN)
    #else
        ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)
        glXGetProcAddressARB((const GLubyte *)"glCompressedTexImage2DARB");
    #endif
    ...
    //around line 2065
    /*    all's well!    */
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
       soilGlCompressedTexImage2D = ext_addr;
       has_DXT_capability = SOIL_CAPABILITY_PRESENT;
    #endif

    8. In GPU/TBOData.cpp, we don't use TBOData.

    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    #include "external/glew/glew.h"
    #endif
    ....
    #define BUFFER_OFFSET(i) ((char *)NULL + (i))
    #if !defined(EMSCRIPTEN)
    ...
    #endif

    9. In GPU/TBOData.h, give every function an empty implementation

    #if !defined(EMSCRIPTEN)
    class TBOData
    {	...   }
    #else
    class TBOData
    {   ...   }
    #endif

    The same is for VBOData.h and VBOData.cpp

    10. In sb/PABlend.cpp

    void PABlend::getWeight(SrVec& pt, SrVec& v1, SrVec& v2, SrVec& v3, SrVec& v4, double& w1, double& w2, double& w3, double& w4)
    dMatrix invMat(3, 3);
    //around line 1166
    #if !defined(EMSCRIPTEN)
        MeCtUBLAS::inverseMatrix(mat,invMat);
    #else
        SrMat mat4x4, mat4x4_inv;
        for(int i = 0; i < 3; ++i)
            for(int j = 0; j < 3; ++j)
                mat4x4.setData(j, i, mat(i, j));
        mat4x4_inv = mat4x4.inverse();
    #endif
    dVector vecIn(3);
    ...
    vecIn(2) = pt.z - v4.z;
    #if !defined(EMSCRIPTEN)
        MeCtUBLAS::matrixVecMult(invMat, vecIn, vecOut);
        w1 = vecOut(0);
        w2 = vecOut(1);
        w3 = vecOut(2);
        w4 = 1 - vecOut(0) - vecOut(1) - vecOut(2);
    #else
        SrVec vec_in, vec_out;
        for(int i = 0; i < 3; ++i)
            vec_in.setData(i, vecIn(i));
        //vec_out = mat4x4_inv * vec_in;
        vec_out =  vec_in*mat4x4_inv;
        w1 = vec_out.getData(0);
        w2 = vec_out.getData(1);
        w3 = vec_out.getData(2);
        w4 = 1 - w1 - w2 - w3;
    #endif
    Icon

    Numeric Library Bindings for Boost is not ported well, still trying to fix this issue, once fixed those modifications should be deleted

    11. In sb/SBEvent.cpp

    SBEventManager::~SBEventManager()
    #if !defined(SB_NO_JAVASCRIPT) && defined(EMSCRIPTEN)
    	delete handler; // deleting old handler causes crash when handler is created with Python - need to fix this
    #endif
    void SBEventManager::removeEventHandler(const std::string& type)
    #if !defined(SB_NO_JAVASCRIPT) && defined(EMSCRIPTEN)
    	delete oldHandler; // deleting old handler causes crash when handler is created with Python - need to fix this
    #endif

    12. In sb/sbm_character.cpp

    void SbmCharacter::createStandardControllers()
    //around line 382
    #if !defined(EMSCRIPTEN)
        postprocess_ct = new MeCtPosePostProcessing(sbSkel);
        postprocess_ct->setName(getName() + "_postprocessController");
        postprocess_ct->ref();
    #endif
    ...
    //around line 492
    #if !defined(EMSCRIPTEN)
        postprocess_ct->init(dynamic_cast<SmartBody::SBCharacter*>(this),"base");
    #endif
    ... 
    //around line 520
    #if !defined(EMSCRIPTEN)
        ct_tree_p->add_controller( postprocess_ct );    
    #endif
    Icon

    Numeric Library Bindings for Boost is not ported well, still trying to fix this issue, once fixed those modifications should be deleted

    13. In sb/SBNavigationMesh.cpp

    SBAPI bool SBNavigationMesh::buildNavigationMeshFromModel( SrModel& inMesh )
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
        int* tris = new int[inMesh.F.size()*3];
        for (int i=0;i<inMesh.F.size();i++)
        {
          tris[i*3+0] = inMesh.F.get(i)[0];
          tris[i*3+1] = inMesh.F.get(i)[1];
          tris[i*3+2] = inMesh.F.get(i)[2];
        }
    #else
        const int* tris = &inMesh.F.get(0)[0];
    #endif

    14. In sb/SBScene.cpp

    #if !defined(__FLASHPLAYER__) && !defined(ANDROID_BUILD) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include "external/glew/glew.h"
    #include "sbm/GPU/SbmDeformableMeshGPU.h"
    #endif
    #ifndef SB_NO_JAVASCRIPT
    #include <emscripten.h>
    #endif
    ...
    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    #include <external/zlib-1.2.5/zip.h>
    #endif
    void SBScene::initialize()
    #if !defined (__ANDROID__) && !defined(SB_IPHONE) && !defined(__native_client__) && !defined(EMSCRIPTEN)
        SbmShaderManager::singleton().setViewer(NULL);
    #endif
    //around line 2179
    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
    void writeFileToZip(zipFile& zf, std::string readFileName, std::string fileNameInZip)
    ...
    #endif
    void SBScene::saveAssets(std::stringstream& strstr, bool remoteSetup, std::string outMediaPath)
    std::vector<std::string> SBScene::checkVisibility(const std::string& characterName)
    {
    	std::vector<std::string> visible_pawns, nonOccludePawns;
    #if !defined(EMSCRIPTEN)
    	...
    #endif
    //	Returns visible pawns
    	return nonOccludePawns;
    }
    std::vector<std::string> SBScene::occlusionTest( const std::vector<std::string>& testPawns)
    {
    	std::vector<std::string> visiblePawns;
    #if !defined(GLES_RENDER) && !defined(EMSCRIPTEN)
    	...
    #endif
    	return visiblePawns;
    }
    bool SBScene::run(const std::string& command)
    #ifndef SB_NO_JAVASCRIPT
        emscripten_run_script(
            command.c_str()
        );
        //otehr options:
        //int emscripten_run_script_int(const char *script)
        //char *emscripten_run_script_string(const char *script)
    #endif
    bool SBScene::runScript(const std::string& script)
    #ifndef SB_NO_JAVASCRIPT
        emscripten_run_script(script.c_str());
    #endif

    15. In sb/SBScene.h

    #if !defined(__FLASHPLAYER__) && !defined(EMSCRIPTEN)
        SBAPI void exportScenePackage(std::string outDir, std::string outZipArchiveName = "");
        SBAPI void exportCharacter(std::string charName, std::string outDir);
    #endif

    16. In sb/SBSteerManager.cpp, we need to add this even though we don't use dynamic library, or std::string ai = dynamic_cast<SmartBody::StringAttribute*>( SmartBody::SBScene::getScene()->getSteerManager()->getAttribute("aimodule") )->getValue(); will crush.

    #if defined(EMSCRIPTEN)
        createStringAttribute("aimodule", "pprAI", true, "Basic", 60, false, false, false, "Agent module library");
    #endif

    17. In sb/SBVersion.hpp

    #ifdef __ANDROID__
        strstr << " android ";
    #else
    #ifdef EMSCRIPTEN
        strstr << " emscripten ";
    #else
        strstr << " other ";
    #endif
    #endif

    18. In sbm/Heightfiled.cpp

    void Heightfield::render( int renderMode ){
    #if defined (__ANDROID__) || defined (SB_IPHONE) || defined(__native_client__) || defined(EMSCRIPTEN)
    #else
    ...
    #endif
    }

    19. In PPRAISteeringAgent.cpp, we need to pass a pointer to handleEvent or it will cause pointer delete exception when bind to Javascript using Embind

    void PPRAISteeringAgent::sendLocomotionEvent(const std::string& status)
    void PPRAISteeringAgent::sendLocomotionEvent(const std::string& status)
    {
    #if defined(EMSCRIPTEN)
        std::string eventType = "locomotion";
        SmartBody::SBMotionEvent* motionEvent = new SmartBody::SBMotionEvent();
        motionEvent->setType(eventType);            
        std::stringstream strstr;
        strstr << character->getName() << " " << status;
        motionEvent->setParameters(strstr.str());
        SmartBody::SBEventManager* manager = SmartBody::SBScene::getScene()->getEventManager();        
        manager->handleEvent(motionEvent, SmartBody::SBScene::getScene()->getSimulationManager()->getTime());
        //LOG("PPRAISteeringAgent::sendLocomotionEvent Over");
    #else
       ...
    #endif
    }

    20. In sbm/sbm_deformable_mesh.cpp

    #elif defined(EMSCRIPTEN)
    #include <GLES2/gl2.h>
    #include <GLES2/gl2ext.h>
    #endif
    #if !defined(__FLASHPLAYER__) && !defined(ANDROID_BUILD) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include "external/glew/glew.h"
    #include "sbm/GPU/SbmDeformableMeshGPU.h"
    #endif
    void DeformableMeshInstance::blendShapes()
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
    				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    #else
    				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
    				glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB, GL_FLOAT, NULL);
    #endif
    ...
    #if !defined(EMSCRIPTEN)
    			SbmBlendTextures::BlendAllAppearancesPairwise( _tempFBOPairs, _tempTexPairs, weights, texIDs, texture_names, SbmBlendTextures::getShader("Blend_All_Textures_Pairwise"), tex_w, tex_h);
    #endif

    In void DeformableMeshInstance::update(), add  updateTransformBuffer();

    #if defined(EMSCRIPTEN)
        updateTransformBuffer();
        return;
    #endif
        //updateFast();
        //return;


    21. In sbm/sbm_deformable_mesh.h

    #elif defined(__FLASHPLAYER__)
        #include <GL/gl.h>
    #elif defined(EMSCRIPTEN)
        #include <GLES2/gl2.h>
        #include <GLES2/gl2ext.h>
    class SbmSubMesh
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
        std::vector<SrModel::Face> triBuf;
    #else
        std::vector<SrVec3i> triBuf;
    #endif

    22. In sbm/SbmBlendFace.cpp, we don't use SbmBlendFace for now, treat it the same as VBOData, TBOData and SbmBlendFace.h

    #if !defined(__FLASHPLAYER__) && !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include "external/glew/glew.h"
    #include "external/jpge/jpge.h"
    #endif
    
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    SbmBlendFace::SbmBlendFace() : DeformableMesh(){
    ...
    }
    ....
    #endif
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    SbmBlendTextures::SbmBlendTextures(){
    }
    ....
    #endif


    23. In SbmDeformableMeshGPU.h

    #if !defined(EMSCRIPTEN)
    //The original code
    #else
    //Empty implementation of each function
    #endif

    For SbmDeformableMeshGPU.cpp #if !defined(EMSCRIPTEN) all implementations, also true for SbmShader.cpp and SbmShader.h

    24. For SBAssetHandlerCOLLADA.cpp, SBAssetHandlerObj.cpp, SBAssetHandlerOgre.cpp, SBAssetHandlerPly.cpp, and SBAssetHandlerSBMeshBinary.cpp

    #if !defined (__ANDROID__) && !defined(SB_IPHONE) &&  !defined(__FLASHPLAYER__) && !defined(__native_client__) && !defined(EMSCRIPTEN)
        SbmDeformableMeshGPU* mesh = new SbmDeformableMeshGPU();
    #else
        DeformableMesh* mesh = new DeformableMesh();
    #endif

    25. In SbmTexture.cpp

    void SbmTexture::buildTexture(bool buildMipMap)
    //around line 277
    #if !defined(EMSCRIPTEN)    //OpenGL ES 2.0 no EMUN for GL_TEXTURE_2D
        myGLEnable(GL_TEXTURE_2D);
    #endif
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    #if !defined(EMSCRIPTEN)
        myGLEnable(iType);    
    #endif
    ...
    //around line
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
        if (!glIsTexture(texID))
        {
            SbmShaderProgram::printOglError("SbmTexture.cpp:100");
        }
    #endif
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
    #define GL_CLAMP GL_CLAMP_TO_EDGE
    #define GL_RGB8 GL_RGB
    #define GL_RGBA8 GL_RGBA
    #endif
    ...
    #if !defined(EMSCRIPTEN)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    #endif
    ...
        //glTexImage2D(iType,0,texture_format,width,height,0,texture_format,GL_UNSIGNED_BYTE,buffer);    
    #if !defined (__FLASHPLAYER__) && !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
        if (buildMipMap)
            gluBuild2DMipmaps(iType, channels, width, height, texture_format, GL_UNSIGNED_BYTE, &imgBuffer[0] );
        else
            glTexImage2D(iType,0,texture_format,width,height,0,texture_format,GL_UNSIGNED_BYTE, &imgBuffer[0]);
    #elif defined(EMSCRIPTEN)
        glTexImage2D(iType,0,texture_format,width,height,0,texture_format,GL_UNSIGNED_BYTE, &imgBuffer[0]);
        glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
        glGenerateMipmap(GL_TEXTURE_2D);
    #endif
    ...
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
        GLclampf iPrority = 1.0;
        glPrioritizeTextures(1,&texID,&iPrority);
    #endif

    26. In sr_gl.h

    #elif defined(EMSCRIPTEN)
    #include <GLES/gl.h>
    #include <GLES2/gl2.h>
    #include <GLES2/gl2ext.h>
    # else
    # include <GL/gl.h>
    # include <GL/glu.h>
    ...
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
    #define GLES_RENDER 1
    #define GLdouble GLfloat
    #endif

    27. In sr_gl.cpp, we give every function an empty implementation cause we don't need those functions

    #if !defined(EMSCRIPTEN)
    //======================================= geometry ================================
    ....till the end
    #else
    SBAPI void glClearColor ( const SrColor& c ){};
    SBAPI void glLight ( int id, const SrLight& l, bool bind_pos){}; //!< id = x E {0,...,7}, from GL_LIGHTx
    SBAPI void glLightPos( int id, const SrLight& l ){};
    SBAPI void glMaterial ( const SrMaterial &m ){}; //!< Sets material for GL_FRONT_AND_BACK
    SBAPI void glMaterialFront ( const SrMaterial &m ){};
    SBAPI void glMaterialBack ( const SrMaterial &m ){};
    //==================================== matrices ==============================
    SBAPI void glMultMatrix ( const SrMat &m ){};
    SBAPI void glLoadMatrix ( const SrMat &m ){};
    SBAPI void glTranslate ( const SrVec &v ){};
    SBAPI void glScale ( float s ){};
    SBAPI void glRotate ( const SrQuat &q ){};
    SBAPI void glLookAt ( const SrVec &eye, const SrVec &center, const SrVec &up ){};
    SBAPI void glPerspective ( float fovy, float aspect, float znear, float zfar ){};
    SBAPI void glGetViewMatrix ( SrMat &m ){};
    SBAPI void glGetProjectionMatrix ( SrMat &m ){};
    //==================================== info ==============================
    SBAPI void glPrintInfo ( SrOutput &o ){};
    #endif

     

    28. In sr_gl_render_funcs.cpp

    #if !defined(__FLASHPLAYER__) && !defined(ANDROID_BUILD) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include "external/glew/glew.h"
    #include "external/SOIL/SOIL.h"
    #endif
    ...
    #if !defined(ANDROID_BUILD) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include <sbm/GPU/SbmShader.h>
    #include <sbm/GPU/SbmDeformableMeshGPU.h>
    #endif
    ...
    #if !defined(EMSCRIPTEN)
    //=============================== render_model ====================================
    ... till the end 
    #else
    static void renderBlendFace( DeformableMeshInstance* shape){};
    static void renderDeformableMesh( DeformableMeshInstance* shape, bool showSkinWeight = false ){};
    static void render_model ( SrSnShapeBase* shape ){};
    static void render_lines ( SrSnShapeBase* shape ){};
    static void render_points ( SrSnShapeBase* shape ){};
    static void render_box ( SrSnShapeBase* shape ){};
    static void render_sphere ( SrSnShapeBase* shape ){};
    static void render_cylinder ( SrSnShapeBase* shape ){};
    static void render_polygon ( SrSnShapeBase* shape ){};
    static void render_polygons ( SrSnShapeBase* shape ){};
    #endif
    Icon

    Note: For the rendering code inside SmartBody I will give all of them empty implementation later, since we don't use those rendering code.

    29. In sr_model.cpp

    int SrModel::common_vertices_of_faces ( int i1, int i2 )
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
       unsigned short *f1 = &(F[i1].a);
       unsigned short *f2 = &(F[i2].a);
    #else
       int *f1 = &(F[i1].a);
       int *f2 = &(F[i2].a);
    #endif

    30. Insr_model.h

    struct Face
    #if defined(__ANDROID__) || defined(SB_IPHONE) || defined(EMSCRIPTEN)
    ...
    #else
    ...
    #endif

    31. In sr_sn_colorsurf.cpp

    # include <sr/sr_sn_colorsurf.h>
    #if !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    # include <sr/sr_gl.h>
    #endif
    void SrSnColorSurf::gl_render_node(bool alphaBlend) const
    #if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    ...
    #endif

    32. In sr_camera.cpp

    #elif defined(EMSCRIPTEN)
    	#include<GLES2/gl2.h>
    	#include<GLES2/gl2ext.h>
    ...
    void SrFrustum::extractFrustum()
    {
    #if !defined(__ANDROID__) && !defined(EMSCRIPTEN)
    ...
    #endif
    }

    33. In sr_model_important_ply.cpp

    #if !defined (__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    #include <sbm/GPU/SbmTexture.h>
    #endif
    ...
    static void load_texture(int type, const char* file, const SrStringArray& paths)
    {
    #if !defined (__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    ...
    #endif
    }
    ....
    bool SrModel::import_ply( const char* file )
    {
    ...
    #if TEST_TEXTURE
    #if !defined (__ANDROID__) && !defined(SB_IPHONE) && !defined(EMSCRIPTEN)
    ...
    #endif
    #endif
    }

    34. Change all .cc files extension in protocols to .cpp
    35. In SBPython.cpp, move #ifndef SB_NO_PYTHON up to the top of the function

    void initPython(std::string pythonLibPath)
    {	
    #ifndef SB_NO_PYTHON
    	...
    #endif
    }

    36. In SBHandSynthesis.cpp, SBMotionGraph.cpp add #include <boost/lexical_cast.hpp>37) In SBPythonMesh.cpp change NO_PYTHON to SB_NO_PYTHON38) In SBPythonClass.cpp, move #ifndef SB_NO_PYTHON right above SrViewer* getViewer()39) In SBPythonSystem.cpp, move #include <sb/SBVersion.hpp> inside #ifndef SB_NO_PYTHON

  • File deleted
    1. Exclude example.c, iowin32.h and iowin32.c in external/zlib from project
  • File added
    Unlike other versions of SmartBody, we use Embind instead of Boost:: python to bind C/C++ functions and classes to Javascript, so that the complied code could be used in Javascript. For more information about Embind, refer here
    List of added files:
    SBJavascript.cpp, SBJavascript.h, SBJavascriptAnimation.cpp, SBJavascriptAttribute.cpp, SBJavascriptCharacter.cpp, SBJavascriptClass.cpp, SBJavascriptClass.h, SBJavascriptInternal.h, SBJavascriptMath.cpp, SBJavascriptMesh.cpp, SBJavascriptMotion.cpp, SBJavascriptScene.cpp
    SBJavascriptSimulation.cpp, SBJavascriptSkeleton.cpp, SBJavascriptSystem.cpp

    Icon

    Will embrace this part about the usage of Embind if needed.

Link SmartBody and Supporting Libraries

We wrote a small rendering engine for SmartBody/Javascript, you could use it either as a reference or standalone application. It contains code on initialize EGL, OpenGL ES 2.0 for the rendering, as well as a binding for Interface. Please refer to the project for more information. 
To compile the project, first we copy all the static libraries into the project, there is a batch file called CopyLibs.bat can be used.
After that open Project property page and choose the configure type either be Browser Application (.html) or Console Application( .js). If you only need the SmartBody Javascript libraries and will do the HTML presentation by yourself, you should choose using Console Application( .js). Also you need to add the Additional Include Directories, Preprocessor and Command Line very similar to SmartBody. We will focus on Emcc Linker part.

In Emcc Linker->Input->Additional Dependencies add the names of static libraries you copied.

Icon

1) Emcc Linker will only show up if you choose the Configureation Type as Browser Application (.html), this is a bug. After you configure the Emcc Linker remember to switch Configuration Type back to Console Application( .js) if you only wanna a Javascript file.

2) As for whether to generate only a Javascript file or a Browser Application(.html) file, first use Browser Application to generate both .html and .js file, you could use that .html file as a reference on how to write your own html file for the application. We will talk about how to modify that .html file later.

3) The .js file generated by Browser Application(.html) is different from that generated by Console Application( .js). The former will embed the .html file information inside the generated .js file, remember don't mix that .js file with your own .html application.


In the Command Line window

-s ALLOW_MEMORY_GROWTH=1 --bind -s DISABLE_EXCEPTION_CATCHING=0 -g2 
Icon

Building with -s ALLOW_MEMORY_GROWTH=1 allows the total amount of memory used to change depending on the demands of the application. This is useful for apps that don’t know ahead of time how much they will need, but it disables some optimizations. (Work is ongoing to improve this.)

To re-enable C++ exception catching, use -s DISABLE_EXCEPTION_CATCHING=0.

-g2 is used for debug version which contains debug information, for release version delete this flag.

For meaning and descriptions of those flags please refer to here

Then we could build the SmartBodyJS project, which we generate SmartBodyJS.js and SmartBodyJS.mem file.

Icon

The --memory-init-file 1 emcc option causes the compiler to emit this code in a separate binary file with suffix .mem. The .mem file is loaded (asynchronously) by the main .js file before main()is called and compiled code is able to run.From Emscripten 1.21.1 this setting is enabled by default for fully optimized builds, that is,-O2 and above.

Rendering using WebGL friendly subset of OpenGL

If you write your own code for rendering, remember to use WebGL friendly subset of OpenGL, which maps OpenGL command directly to WebGL. It include almost all commands of OpenGL ES 2.0 except for client-side array. More information could be found here

[1] OpenGL, OpenGL ES, WebGL, GLSL, GLSL ES API Tables (very useful when converting code to OpenGL ES 2.0 or WebGL)

http://web.eecs.umich.edu/~sugih/courses/eecs487/common/notes/APITables.xml  

[2] WebGL Browser Report (useful when you need to know your brower's support for WebGL)

https://www.browserleaks.com/webgl

[3] GCC and MSVC C++ Demangler (useful when debuging code)

http://demangler.com/

 

Attachments: