[
  {
    "path": ".gitignore",
    "content": "#########################\n# openFrameworks patterns\n#########################\n\n# build files\nopenFrameworks.a\nopenFrameworksDebug.a\nopenFrameworksUniversal.a\nlibs/openFrameworksCompiled/lib/*/*\n!libs/openFrameworksCompiled/lib/*/.gitkeep\n\n# apothecary\nscripts/apothecary\n\n# rule to avoid non-official addons going into git\n# see addons/.gitignore\naddons/*\n\n# rule to avoid non-official apps going into git\n# see apps/.gitignore\napps/*\n\n# rule to ignore compiled / downloaded libs\n/libs/*\n!/libs/openFrameworks\n!/libs/openFrameworksCompiled\n\n# also, see examples/.gitignore\n\n#########################\n# general\n#########################\n\n[Bb]uild/\n[Oo]bj/\n*.o\nexamples/**/[Dd]ebug*/\nexamples/**/[Rr]elease*/\nexamples/**/gcc-debug/\nexamples/**/gcc-release/\ntests/**/[Dd]ebug*/\ntests/**/[Rr]elease*/\ntests/**/gcc-debug/\ntests/**/gcc-release/\n*.mode*\n*.app/\n*.pyc\n.svn/\n*.log\n*.cpp.eep\n*.cpp.elf\n*.cpp.hex\n\n#########################\n# IDE\n#########################\n\n# XCode\n*.pbxuser\n*.perspective\n*.perspectivev3\n*.mode1v3\n*.mode2v3\n# XCode 4\nxcuserdata\n*.xcworkspace\n\n# Code::Blocks\n*.depend\n*.layout\n\n# Visual Studio\n*.sdf\n*.opensdf\n*.suo\n*.pdb\n*.ilk\n*.aps\nipch/\n**/.vs/*\n\n# Eclipse\n.metadata\nlocal.properties\n.externalToolBuilders\n\n# Android Studio\n.idea\n.gradle\ngradle\ngradlew\ngradlew.bat\n\n# QtCreator\n*.qbs.user\n*.pro.user\n*.pri\n\n\n#########################\n# operating system\n#########################\n\n# Linux\n*~\n# KDE\n.directory\n.AppleDouble\n\n# OSX\n.DS_Store\n*.swp\n*~.nib\n# Thumbnails\n._*\nexamples/ios/**/mediaAssets\n\n# Windows\n# Windows image file caches\nThumbs.db\n# Folder config file\nDesktop.ini\n\n# Android\n.csettings\n/libs/openFrameworksCompiled/project/android/paths.make\n\n# Android Studio\n*.iml\n\n#########################\n# miscellaneous\n#########################\n\n.mailmap\n/apps*/\n\n#########################\n# core examples\n#########################\n\nbin/*\n!bin/data/\n\n**/bin/*\n!**/bin/data/\n\n#########################\n# IDE\n#########################\n\n# XCode\n*.xcodeproj\nProject.xcconfig\nopenFrameworks-Info.plist\nofxiOS-Info.plist\nofxiOS_Prefix.pch\n*/*/Default*.png\n*/*/Icon*.png\n\n# Code::Blocks\n# *.cbp\n# *.workspace\n\n# Visual Studio\n# *.sln\n# *.vcxproj\n*.vcxproj.user\n*.vcxproj.filters\nicon.rc\n\n# Eclipse\n.cproject\n.project\n.settings/\n\n# QtCreator\n# *.qbs\n*.qbs.user*\n*.pro\n*.pro.user\nqtc_Desktop_*\n\n#########################\n# operating system\n#########################\n\n# Linux\n# Makefile\n# config.make\n# Leave Android files in until project generation works\n!/android/*/Makefile\n!/android/*/config.make\n\n# Android\nandroid/*/test link\nandroid/*/gen\nandroid/*/res/raw\nlibOFAndroidApp*.so\ngdbserver\ngdb.setup\nlibneondetection.so\nApplication.mk\nAndroid.mk\n\n!android/*/.cproject\n!android/*/.project\n!android/*/.settings\n!android/*/.settings/*\n"
  },
  {
    "path": "README.md",
    "content": "ofxMSAFluid\n=====================================\n\nIntroduction\n------------\nC++ openFrameworks addon for solving and drawing 2D fluid systems based on Navier-Stokes equations and Jos Stam's paper \"Real-Time Fluid Dynamics for Games\" [http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf](http://www.dgp.toronto.edu/people/stam/reality/Research/pdf/GDC03.pdf)\n\nDemo at [www.memo.tv/msafluid/](http://www.memo.tv/msafluid)\n\nOther useful resources and implementations I looked at while building this library:  \n\n- Mike Ash (C), http://mikeash.com/?page=pyblog/fluid-simulation-for-dummies.html\n- Alexander McKenzie (Java), http://www.multires.caltech.edu/teaching/demos/java/stablefluids.htm\n- Pierluigi Pesenti (AS3 port of Alexander's), http://blog.oaxoa.com/2008/01/21/actionscript-3-fluids-simulation/\n- Gustav Taxen (C), http://www.nada.kth.se/~gustavt/fluids/\n- Dave Wallin (C++), http://nuigroup.com/touchlib/ (uses portions from Gustav's)\n\nLicence\n-------\nThe code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license).  \nCopyright (c) 2008-2012 Memo Akten, [www.memo.tv](http://www.memo.tv)  \nThe Mega Super Awesome Visuals Company\n\n\nInstallation\n------------\nCopy to your openFrameworks/addons folder.\n\nDependencies\n------------\n- MSACore\n\nCompatibility\n------------\nopenFrameworks 0072  \nI am generally testing only with [openFrameworks](www.openframeworks.cc), however it should work with [Cinder](www.libcinder.org) too. If it doesn't, please file an issue.\n\n\nKnown issues\n------------\nProbably will not work with Cinder without some (minor) changes\n\nVersion history\n------------\n### v2.1    23/09/2012\n- compatible with OF0072\n- renamed (uppercase) MSA namespace to (lowercase) msa. (kept MSA as an alias for backwards compatibility)\n- all classes are now inside a new namespace 'msa::fluid::'\n\n### v2.0\n- move to centralized MSALibs (requires MSACore)\n- everything is msa:: namespace\n- u[] and v[] condensed to (Vec2f uv[])\n- r[], g[], b[] condensed to (Vec3f color[])\n- unified API for getting and setting info:\n   - all vel & colors set and get with the structs\n   - all getters and setters have 3 functions, index, (i, j), Vec2f pos\n\n### v1.2\t02/05/2009\n- unified API with processing.org version\n- solver u, v, r, g, b arrays now public\n- drawer can incDrawMode and decDrawMode\n- loads of optimizations by Maa (http://www.lagraine.com/ - new content coming soon)\n\n### v1.1\t07/04/2009\n- changed license to revised BSD (a lot more more permissive than GPL)\n\n### v1.0\n- added RGB or monochrome functionality (enableRGB())\n- vector drawing implemented\n- get and set info much improved\n- added draw mode system\n- setup() now only takes dimensions, other parameters have their own setters\n\n### v0.9\t04/12/08\n- initial version\n\n\n\n"
  },
  {
    "path": "addon_config.mk",
    "content": "meta:\n\tADDON_NAME = ofxMSAFluid\n\tADDON_DESCRIPTION = C++ openFrameworks addon for Stam style Fluid Solver\n\tADDON_AUTHOR = Memo Akten, www.memo.tv\n\tADDON_TAGS = \"Fluid\"\n\tADDON_URL = https://github.com/memo/ofxMSAFluid\n\ncommon:\n\t# dependencies with other addons, a list of them separated by spaces\n\t# or use += in several lines\n\tADDON_DEPENDENCIES = ofxMSACore\n"
  },
  {
    "path": "example/Makefile",
    "content": "# Attempt to load a config.make file.\n# If none is found, project defaults in config.project.make will be used.\nifneq ($(wildcard config.make),)\n\tinclude config.make\nendif\n\n# make sure the the OF_ROOT location is defined\nifndef OF_ROOT\n\tOF_ROOT=$(realpath ../../..)\nendif\n\n# call the project makefile!\ninclude $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk\n"
  },
  {
    "path": "example/addons.make",
    "content": "ofxMSACore\nofxMSAFluid\nofxMSAInteractiveObject\nofxSimpleGuiToo\nofxXmlSettings\n"
  },
  {
    "path": "example/config.make",
    "content": "################################################################################\n# CONFIGURE PROJECT MAKEFILE (optional)\n#   This file is where we make project specific configurations.\n################################################################################\n\n################################################################################\n# OF ROOT\n#   The location of your root openFrameworks installation\n#       (default) OF_ROOT = ../../.. \n################################################################################\n# OF_ROOT = ../../..\n\n################################################################################\n# PROJECT ROOT\n#   The location of the project - a starting place for searching for files\n#       (default) PROJECT_ROOT = . (this directory)\n#    \n################################################################################\n# PROJECT_ROOT = .\n\n################################################################################\n# PROJECT SPECIFIC CHECKS\n#   This is a project defined section to create internal makefile flags to \n#   conditionally enable or disable the addition of various features within \n#   this makefile.  For instance, if you want to make changes based on whether\n#   GTK is installed, one might test that here and create a variable to check. \n################################################################################\n# None\n\n################################################################################\n# PROJECT EXTERNAL SOURCE PATHS\n#   These are fully qualified paths that are not within the PROJECT_ROOT folder.\n#   Like source folders in the PROJECT_ROOT, these paths are subject to \n#   exlclusion via the PROJECT_EXLCUSIONS list.\n#\n#     (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) \n#\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_EXTERNAL_SOURCE_PATHS = \n\n################################################################################\n# PROJECT EXCLUSIONS\n#   These makefiles assume that all folders in your current project directory \n#   and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations\n#   to look for source code. The any folders or files that match any of the \n#   items in the PROJECT_EXCLUSIONS list below will be ignored.\n#\n#   Each item in the PROJECT_EXCLUSIONS list will be treated as a complete \n#   string unless teh user adds a wildcard (%) operator to match subdirectories.\n#   GNU make only allows one wildcard for matching.  The second wildcard (%) is\n#   treated literally.\n#\n#      (default) PROJECT_EXCLUSIONS = (blank)\n#\n#\t\tWill automatically exclude the following:\n#\n#\t\t\t$(PROJECT_ROOT)/bin%\n#\t\t\t$(PROJECT_ROOT)/obj%\n#\t\t\t$(PROJECT_ROOT)/%.xcodeproj\n#\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_EXCLUSIONS =\n\n################################################################################\n# PROJECT LINKER FLAGS\n#\tThese flags will be sent to the linker when compiling the executable.\n#\n#\t\t(default) PROJECT_LDFLAGS = -Wl,-rpath=./libs\n#\n#   Note: Leave a leading space when adding list items with the += operator\n#\n# Currently, shared libraries that are needed are copied to the \n# $(PROJECT_ROOT)/bin/libs directory.  The following LDFLAGS tell the linker to\n# add a runtime path to search for those shared libraries, since they aren't \n# incorporated directly into the final executable application binary.\n################################################################################\n# PROJECT_LDFLAGS=-Wl,-rpath=./libs\n\n################################################################################\n# PROJECT DEFINES\n#   Create a space-delimited list of DEFINES. The list will be converted into \n#   CFLAGS with the \"-D\" flag later in the makefile.\n#\n#\t\t(default) PROJECT_DEFINES = (blank)\n#\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_DEFINES = \n\n################################################################################\n# PROJECT CFLAGS\n#   This is a list of fully qualified CFLAGS required when compiling for this \n#   project.  These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS \n#   defined in your platform specific core configuration files. These flags are\n#   presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. \n#\n#\t\t(default) PROJECT_CFLAGS = (blank)\n#\n#   Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in \n#   your platform specific configuration file will be applied by default and \n#   further flags here may not be needed.\n#\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_CFLAGS = \n\n################################################################################\n# PROJECT OPTIMIZATION CFLAGS\n#   These are lists of CFLAGS that are target-specific.  While any flags could \n#   be conditionally added, they are usually limited to optimization flags. \n#   These flags are added BEFORE the PROJECT_CFLAGS.\n#\n#   PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.\n#\n#\t\t(default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)\n#\n#   PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.\n#\n#\t\t(default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)\n#\n#   Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the \n#   PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration \n#   file will be applied by default and further optimization flags here may not \n#   be needed.\n#\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = \n# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = \n\n################################################################################\n# PROJECT COMPILERS\n#   Custom compilers can be set for CC and CXX\n#\t\t(default) PROJECT_CXX = (blank)\n#\t\t(default) PROJECT_CC = (blank)\n#   Note: Leave a leading space when adding list items with the += operator\n################################################################################\n# PROJECT_CXX = \n# PROJECT_CC = \n"
  },
  {
    "path": "example/example.qbs",
    "content": "import qbs\nimport qbs.Process\nimport qbs.File\nimport qbs.FileInfo\nimport qbs.TextFile\nimport \"../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs\" as ofApp\n\nProject{\n    property string of_root: '../../..'\n\n    ofApp {\n        name: { return FileInfo.baseName(sourceDirectory) }\n\n        files: [\n            'src/*',\n        ]\n\n        of.addons: [\n            'ofxMSAFluid',\n            'ofxSimpleGuiToo'\n        ]\n\n        // additional flags for the project. the of module sets some\n        // flags by default to add the core libraries, search paths...\n        // this flags can be augmented through the following properties:\n        of.pkgConfigs: []       // list of additional system pkgs to include\n        of.includePaths: []     // include search paths\n        of.cFlags: []           // flags passed to the c compiler\n        of.cxxFlags: []         // flags passed to the c++ compiler\n        of.linkerFlags: []      // flags passed to the linker\n        of.defines: []          // defines are passed as -D to the compiler\n        // and can be checked with #ifdef or #if in the code\n        of.frameworks: []       // osx only, additional frameworks to link with the project\n        of.staticLibraries: []  // static libraries\n        of.dynamicLibraries: [] // dynamic libraries\n\n        // create a console window when the application start\n        consoleApplication: true\n\n        // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html\n        // eg: this will enable ccache when compiling\n        //\n        // cpp.compilerWrapper: 'ccache'\n\n        Depends{\n            name: \"cpp\"\n        }\n\n        // common rules that parse the include search paths, core libraries...\n        Depends{\n            name: \"of\"\n        }\n\n        // dependency with the OF library\n        Depends{\n            name: \"openFrameworks\"\n        }\n    }\n\n    property bool makeOF: true  // use makfiles to compile the OF library\n    // will compile OF only once for all your projects\n    // otherwise compiled per project with qbs\n\n    property bool precompileOfMain: false  // precompile ofMain.h\n    // faster to recompile when including ofMain.h\n    // but might use a lot of space per project\n\n    references: [FileInfo.joinPaths(of_root, \"/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs\")]\n}\n"
  },
  {
    "path": "example/example.sln",
    "content": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"example\", \"example.vcxproj\", \"{7FD42DF7-442E-479A-BA76-D0022F99702A}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"openframeworksLib\", \"..\\..\\..\\libs\\openFrameworksCompiled\\project\\vs\\openframeworksLib.vcxproj\", \"{5837595D-ACA9-485C-8E76-729040CE4B0B}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64\n\t\t{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64\n\t\t{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "example/example.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Condition=\"'$(WindowsTargetPlatformVersion)'==''\">\n    <LatestTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</LatestTargetPlatformVersion>\n    <WindowsTargetPlatformVersion Condition=\"'$(WindowsTargetPlatformVersion)' == ''\">$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>\n    <TargetPlatformVersion>$(WindowsTargetPlatformVersion)</TargetPlatformVersion>\n  </PropertyGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{7FD42DF7-442E-479A-BA76-D0022F99702A}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>example</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <PlatformToolset>v141</PlatformToolset>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"..\\..\\..\\libs\\openFrameworksCompiled\\project\\vs\\openFrameworksRelease.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"..\\..\\..\\libs\\openFrameworksCompiled\\project\\vs\\openFrameworksRelease.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"..\\..\\..\\libs\\openFrameworksCompiled\\project\\vs\\openFrameworksDebug.props\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n    <Import Project=\"..\\..\\..\\libs\\openFrameworksCompiled\\project\\vs\\openFrameworksDebug.props\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <OutDir>bin\\</OutDir>\n    <IntDir>obj\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>$(ProjectName)_debug</TargetName>\n    <LinkIncremental>true</LinkIncremental>\n    <GenerateManifest>true</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <OutDir>bin\\</OutDir>\n    <IntDir>obj\\$(Platform)\\$(Configuration)\\</IntDir>\n    <TargetName>$(ProjectName)_debug</TargetName>\n    <LinkIncremental>true</LinkIncremental>\n    <GenerateManifest>true</GenerateManifest>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>bin\\</OutDir>\n    <IntDir>obj\\$(Platform)\\$(Configuration)\\</IntDir>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <OutDir>bin\\</OutDir>\n    <IntDir>obj\\$(Platform)\\$(Configuration)\\</IntDir>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);src;..\\..\\..\\addons\\ofxMSACore\\src;..\\..\\..\\addons\\ofxMSAFluid\\src;..\\..\\..\\addons\\ofxMSAInteractiveObject\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls;..\\..\\..\\addons\\ofxXmlSettings\\libs;..\\..\\..\\addons\\ofxXmlSettings\\src</AdditionalIncludeDirectories>\n      <CompileAs>CompileAsCpp</CompileAs>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent />\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);src;..\\..\\..\\addons\\ofxMSACore\\src;..\\..\\..\\addons\\ofxMSAFluid\\src;..\\..\\..\\addons\\ofxMSAInteractiveObject\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls;..\\..\\..\\addons\\ofxXmlSettings\\libs;..\\..\\..\\addons\\ofxXmlSettings\\src</AdditionalIncludeDirectories>\n      <CompileAs>CompileAsCpp</CompileAs>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <Link>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent />\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WholeProgramOptimization>false</WholeProgramOptimization>\n      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);src;..\\..\\..\\addons\\ofxMSACore\\src;..\\..\\..\\addons\\ofxMSAFluid\\src;..\\..\\..\\addons\\ofxMSAInteractiveObject\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls;..\\..\\..\\addons\\ofxXmlSettings\\libs;..\\..\\..\\addons\\ofxXmlSettings\\src</AdditionalIncludeDirectories>\n      <CompileAs>CompileAsCpp</CompileAs>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <Link>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent />\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WholeProgramOptimization>false</WholeProgramOptimization>\n      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <WarningLevel>Level3</WarningLevel>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);src;..\\..\\..\\addons\\ofxMSACore\\src;..\\..\\..\\addons\\ofxMSAFluid\\src;..\\..\\..\\addons\\ofxMSAInteractiveObject\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src;..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls;..\\..\\..\\addons\\ofxXmlSettings\\libs;..\\..\\..\\addons\\ofxXmlSettings\\src</AdditionalIncludeDirectories>\n      <CompileAs>CompileAsCpp</CompileAs>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <Link>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <GenerateDebugInformation>false</GenerateDebugInformation>\n      <SubSystem>Console</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <RandomizedBaseAddress>false</RandomizedBaseAddress>\n      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <PostBuildEvent />\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"src\\main.cpp\" />\n    <ClCompile Include=\"src\\Particle.cpp\" />\n    <ClCompile Include=\"src\\ParticleSystem.cpp\" />\n    <ClCompile Include=\"src\\testApp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACoreGL.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidDrawerBase.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidSolver.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxMSAInteractiveObject\\src\\ofxMSAInteractiveObject.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiButton.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiColorPicker.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiComboBox.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiContent.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiFPSCounter.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiMovieSlider.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiQuadWarp.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiSlider2d.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiTitle.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiToggle.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiConfig.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiControl.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiPage.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiToo.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiValueControl.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxXmlSettings\\src\\ofxXmlSettings.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxXmlSettings\\libs\\tinyxml.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxXmlSettings\\libs\\tinyxmlerror.cpp\" />\n    <ClCompile Include=\"..\\..\\..\\addons\\ofxXmlSettings\\libs\\tinyxmlparser.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"src\\Particle.h\" />\n    <ClInclude Include=\"src\\ParticleSystem.h\" />\n    <ClInclude Include=\"src\\testApp.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACore-Cinder.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACore-OF.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACore.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACoreCommon.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACoreGL.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSACore\\src\\MSACoreMath.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluid.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidDrawerBase.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidDrawerGl-Cinder.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidDrawerGl-OF.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidParticleUpdater.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAFluid\\src\\MSAFluidSolver.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxMSAInteractiveObject\\src\\ofxMSAInteractiveObject.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiButton.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiColorPicker.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiComboBox.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiContent.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiFPSCounter.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiMovieSlider.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiQuadWarp.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiSlider2d.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiSliderBase.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiSliderFloat.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiSliderInt.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiTitle.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\Controls\\ofxSimpleGuiToggle.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiConfig.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiControl.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiIncludes.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiPage.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiToo.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxSimpleGuiToo\\src\\ofxSimpleGuiValueControl.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxXmlSettings\\src\\ofxXmlSettings.h\" />\n    <ClInclude Include=\"..\\..\\..\\addons\\ofxXmlSettings\\libs\\tinyxml.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"$(OF_ROOT)\\libs\\openFrameworksCompiled\\project\\vs\\openframeworksLib.vcxproj\">\n      <Project>{5837595d-aca9-485c-8e76-729040ce4b0b}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"icon.rc\">\n      <AdditionalOptions Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">/D_DEBUG %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalOptions Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">/D_DEBUG %(AdditionalOptions)</AdditionalOptions>\n      <AdditionalIncludeDirectories>$(OF_ROOT)\\libs\\openFrameworksCompiled\\project\\vs</AdditionalIncludeDirectories>\n    </ResourceCompile>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ProjectExtensions>\n    <VisualStudio>\n      <UserProperties RESOURCE_FILE=\"icon.rc\" />\n    </VisualStudio>\n  </ProjectExtensions>\n</Project>"
  },
  {
    "path": "example/src/Particle.cpp",
    "content": "/*\n *  Particle.cpp\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.\n *\n */\n\n#include \"Particle.h\"\n\nstatic const float MOMENTUM = 0.5f;\nstatic const float FLUID_FORCE = 0.6f;\n\nvoid Particle::init(float x, float y) {\n\tpos = ofVec2f( x, y );\n\tvel = ofVec2f(0, 0);\n\tradius = 5;\n\talpha  = msa::Rand::randFloat( 0.3f, 1 );\n\tmass = msa::Rand::randFloat( 0.1f, 1 );\n}\n\nvoid Particle::update( const msa::fluid::Solver &solver, const ofVec2f &windowSize, const ofVec2f &invWindowSize ) {\n\t// only update if particle is visible\n\tif( alpha == 0 )\n\t\treturn;\n\t\n\tvel = solver.getVelocityAtPos( pos * invWindowSize ) * (mass * FLUID_FORCE ) * windowSize + vel * MOMENTUM;\n\tpos += vel;\t\n\t\n\t// bounce of edges\n\tif( pos.x < 0 ) {\n\t\tpos.x = 0;\n\t\tvel.x *= -1;\n\t}\n\telse if( pos.x > windowSize.x ) {\n\t\tpos.x = windowSize.x;\n\t\tvel.x *= -1;\n\t}\n\t\n\tif( pos.y < 0 ) {\n\t\tpos.y = 0;\n\t\tvel.y *= -1;\n\t}\n\telse if( pos.y > windowSize.y ) {\n\t\tpos.y = windowSize.y;\n\t\tvel.y *= -1;\n\t}\n\t\n\t// hackish way to make particles glitter when the slow down a lot\n//\tif( vel.squareLength() < 1 ) {\n//\t\tvel += msa::Rand::randVec2f() * 0.5f;\n//\t}\n\t\n\t// fade out a bit (and kill if alpha == 0);\n\talpha *= 0.999f;\n\tif( alpha < 0.01f )\n\t\talpha = 0;\n}\n\n\n\nvoid Particle::updateVertexArrays( bool drawingFluid, const ofVec2f &invWindowSize, int i, float* posBuffer, float* colBuffer) {\n\tint vi = i * 4;\n\tposBuffer[vi++] = pos.x - vel.x;\n\tposBuffer[vi++] = pos.y - vel.y;\n\tposBuffer[vi++] = pos.x;\n\tposBuffer[vi++] = pos.y;\n\t\n\tint ci = i * 6;\n\tif( drawingFluid ) {\n\t\t// if drawing fluid, draw lines as black & white\n\t\tcolBuffer[ci++] = alpha;\n\t\tcolBuffer[ci++] = alpha;\n\t\tcolBuffer[ci++] = alpha;\n\t\tcolBuffer[ci++] = alpha;\n\t\tcolBuffer[ci++] = alpha;\n\t\tcolBuffer[ci++] = alpha;\n\t} else {\n\t\t// otherwise, use color\n\t\tfloat vxNorm = vel.x * invWindowSize.x;\n\t\tfloat vyNorm = vel.y * invWindowSize.y;\n\t\tfloat v2 = vxNorm * vxNorm + vyNorm * vyNorm;\n#define VMAX 0.013f\n\t\tif(v2>VMAX*VMAX) v2 = VMAX*VMAX;\n\t\tfloat satInc = mass > 0.5 ? mass * mass * mass : 0;\n\t\tsatInc *= satInc * satInc * satInc;\n\t\tofColor color;\n\t\tcolor.setHsb(0, v2 * 255.0f / ( VMAX * VMAX ) + satInc, ofLerp(0.5, 1, mass) * alpha * 255.0f);\n\t\t\n\t\tcolBuffer[ci++] = color.r;\n\t\tcolBuffer[ci++] = color.g;\n\t\tcolBuffer[ci++] = color.b;\n\t\tcolBuffer[ci++] = color.r;\n\t\tcolBuffer[ci++] = color.g;\n\t\tcolBuffer[ci++] = color.b;\n\t}\n}"
  },
  {
    "path": "example/src/Particle.h",
    "content": "/*\n *  Particle.h\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.\n *\n */\n\n#pragma once\n\n#include \"MSACore.h\"\n#include \"MSAFluidSolver.h\"\n\nclass Particle {\npublic:\t\n    ofVec2f\tpos, vel;\n    float\tradius;\n    float\talpha;\n    float\tmass;\n\t\n    void init(float x, float y);\n    void update( const msa::fluid::Solver &solver, const ofVec2f &windowSize, const ofVec2f &invWindowSize );\n\tvoid updateVertexArrays( bool drawingFluid, const ofVec2f &invWindowSize, int i, float* posBuffer, float* colBuffer);\n};\n\n"
  },
  {
    "path": "example/src/ParticleSystem.cpp",
    "content": "/*\n *  ParticleSystem.cpp\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.\n *\n */\n\n#include \"ParticleSystem.h\"\n\nParticleSystem::ParticleSystem() {\n\tcurIndex = 0;\n}\n\nvoid ParticleSystem::updateAndDraw(const msa::fluid::Solver &solver, ofVec2f windowSize, bool drawingFluid) {\n    ofVec2f invWindowSize(1.0f / windowSize.x, 1.0f / windowSize.y);\n\n\tglEnable(GL_BLEND);\n\tglDisable(GL_TEXTURE_2D);\n    glBlendFunc(GL_ONE,GL_ONE);\n//\tglEnable(GL_LINE_SMOOTH);\n    ofSetLineWidth(1);\n\t\n\tfor(int i=0; i<MAX_PARTICLES; i++) {\n\t\tif(particles[i].alpha > 0) {\n\t\t\tparticles[i].update(solver, windowSize, invWindowSize);\n\t\t\tparticles[i].updateVertexArrays(drawingFluid, invWindowSize, i, posArray, colArray);\n\t\t}\n\t}    \n\tglEnableClientState(GL_VERTEX_ARRAY);\n\tglVertexPointer(2, GL_FLOAT, 0, posArray);\n\t\n\tglEnableClientState(GL_COLOR_ARRAY);\n\tglColorPointer(3, GL_FLOAT, 0, colArray);\n\t\n\tglDrawArrays(GL_LINES, 0, MAX_PARTICLES * 2);\n\t\n\tglDisableClientState(GL_VERTEX_ARRAY);\n\tglDisableClientState(GL_COLOR_ARRAY);\n\t\n\tglDisable(GL_BLEND);\n}\n\n\nvoid ParticleSystem::addParticles(const ofVec2f &pos, int count){\n\tfor(int i=0; i<count; i++)\n\t\taddParticle(pos + msa::Rand::randVec2f() * 15);\n}\n\n\nvoid ParticleSystem::addParticle(const ofVec2f &pos) {\n\tparticles[curIndex].init(pos.x, pos.y);\n\tcurIndex++;\n\tif(curIndex >= MAX_PARTICLES) curIndex = 0;\n}\n"
  },
  {
    "path": "example/src/ParticleSystem.h",
    "content": "/*\n *  ParticleSystem.h\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.\n *\n */\n#pragma once\n\n#include \"Particle.h\"\n\n#define MAX_PARTICLES\t\t50000\n\nclass ParticleSystem {\npublic:\t\n\t\n    float posArray[MAX_PARTICLES * 2 * 2];\n    float colArray[MAX_PARTICLES * 3 * 2];\n    int curIndex;\n\t\n    Particle particles[MAX_PARTICLES];\n\t\n\tParticleSystem();\n\n    void updateAndDraw(const msa::fluid::Solver &aSolver, ofVec2f windowSize, bool drawingFluid);\n\tvoid addParticles(const ofVec2f &pos, int count);\n\tvoid addParticle(const ofVec2f &pos);\n};\n\n"
  },
  {
    "path": "example/src/main.cpp",
    "content": "\n#include \"testApp.h\"\n\nint main( ){\n\tofSetupOpenGL(1024, 768, OF_WINDOW);\t\t\t// <-------- setup the GL context\n\tofRunApp(new testApp);\n}\n"
  },
  {
    "path": "example/src/testApp.cpp",
    "content": "#include \"testApp.h\"\n\n\nfloat tuioXScaler = 1;\nfloat tuioYScaler = 1;\n\n//--------------------------------------------------------------\nvoid testApp::setup() {\t \n\t//for(int i=0; i<strlen(sz); i++) sz[i] += 20;\n\t\n\t// setup fluid stuff\n\tfluidSolver.setup(100, 100);\n    fluidSolver.enableRGB(true).setFadeSpeed(0.002).setDeltaT(0.5).setVisc(0.00015).setColorDiffusion(0);\n\tfluidDrawer.setup(&fluidSolver);\n\t\n\tfluidCellsX\t\t\t= 150;\n\t\n\tdrawFluid\t\t\t= true;\n\tdrawParticles\t\t= true;\n\t\n\tofSetFrameRate(60);\n\tofBackground(0, 0, 0);\n\tofSetVerticalSync(false);\n\t\n#ifdef USE_TUIO\n\ttuioClient.start(3333);\n#endif\n\n\t\n#ifdef USE_GUI \n\tgui.addSlider(\"fluidCellsX\", fluidCellsX, 20, 400);\n\tgui.addButton(\"resizeFluid\", resizeFluid);\n    gui.addSlider(\"colorMult\", colorMult, 0, 100);\n    gui.addSlider(\"velocityMult\", velocityMult, 0, 100);\n\tgui.addSlider(\"fs.viscocity\", fluidSolver.viscocity, 0.0, 0.01);\n\tgui.addSlider(\"fs.colorDiffusion\", fluidSolver.colorDiffusion, 0.0, 0.0003); \n\tgui.addSlider(\"fs.fadeSpeed\", fluidSolver.fadeSpeed, 0.0, 0.1); \n\tgui.addSlider(\"fs.solverIterations\", fluidSolver.solverIterations, 1, 50); \n\tgui.addSlider(\"fs.deltaT\", fluidSolver.deltaT, 0.1, 5);\n\tgui.addComboBox(\"fd.drawMode\", (int&)fluidDrawer.drawMode, msa::fluid::getDrawModeTitles());\n\tgui.addToggle(\"fs.doRGB\", fluidSolver.doRGB); \n\tgui.addToggle(\"fs.doVorticityConfinement\", fluidSolver.doVorticityConfinement); \n\tgui.addToggle(\"drawFluid\", drawFluid); \n\tgui.addToggle(\"drawParticles\", drawParticles); \n\tgui.addSlider(\"velDrawMult\", fluidDrawer.velDrawMult, 0.0, 20);\n\tgui.addSlider(\"velDrawThreshold\", fluidDrawer.velDrawThreshold, 0.0, 1);\n\tgui.addSlider(\"brightness\", fluidDrawer.brightness, 0.0, 2);\n\tgui.addToggle(\"useAdditiveBlending\", fluidDrawer.useAdditiveBlending);\n\t\n\tgui.addToggle(\"fs.wrapX\", fluidSolver.wrap_x);\n\tgui.addToggle(\"fs.wrapY\", fluidSolver.wrap_y);\n    gui.addSlider(\"tuioXScaler\", tuioXScaler, 0, 2);\n    gui.addSlider(\"tuioYScaler\", tuioYScaler, 0, 2);\n    \n\tgui.currentPage().setXMLName(\"ofxMSAFluidSettings.xml\");\n    gui.loadFromXML();\n\tgui.setDefaultKeys(true);\n\tgui.setAutoSave(true);\n    gui.show();\n#endif\n\t\n\twindowResized(ofGetWidth(), ofGetHeight());\t\t// force this at start (cos I don't think it is called)\n\tpMouse = msa::getWindowCenter();\n\tresizeFluid\t\t\t= true;\n\t\n\tofEnableAlphaBlending();\n\tofSetBackgroundAuto(false);\n}\n\n\nvoid testApp::fadeToColor(float r, float g, float b, float speed) {\n    glColor4f(r, g, b, speed);\n\tofRect(0, 0, ofGetWidth(), ofGetHeight());\n}\n\n\n// add force and dye to fluid, and create particles\nvoid testApp::addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce) {\n    float speed = vel.x * vel.x  + vel.y * vel.y * msa::getWindowAspectRatio() * msa::getWindowAspectRatio();    // balance the x and y components of speed with the screen aspect ratio\n    if(speed > 0) {\n\t\tpos.x = ofClamp(pos.x, 0.0f, 1.0f);\n\t\tpos.y = ofClamp(pos.y, 0.0f, 1.0f);\n\t\t\n        int index = fluidSolver.getIndexForPos(pos);\n\t\t\n\t\tif(addColor) {\n//\t\t\tColor drawColor(CM_HSV, (getElapsedFrames() % 360) / 360.0f, 1, 1);\n\t\t\tofColor drawColor;\n\t\t\tdrawColor.setHsb((ofGetFrameNum() % 255), 255, 255);\n\t\t\t\n\t\t\tfluidSolver.addColorAtIndex(index, drawColor * colorMult);\n\t\t\t\n\t\t\tif(drawParticles)\n\t\t\t\tparticleSystem.addParticles(pos * ofVec2f(ofGetWindowSize()), 10);\n\t\t}\n\t\t\n\t\tif(addForce)\n\t\t\tfluidSolver.addForceAtIndex(index, vel * velocityMult);\n\t\t\n    }\n}\n\n\nvoid testApp::update(){\n\tif(resizeFluid) \t{\n\t\tfluidSolver.setSize(fluidCellsX, fluidCellsX / msa::getWindowAspectRatio());\n\t\tfluidDrawer.setup(&fluidSolver);\n\t\tresizeFluid = false;\n\t}\n\t\n#ifdef USE_TUIO\n\ttuioClient.getMessage();\n\t\n\t// do finger stuff\n\tlist<ofxTuioCursor*>cursorList = tuioClient.getTuioCursors();\n\tfor(list<ofxTuioCursor*>::iterator it=cursorList.begin(); it != cursorList.end(); it++) {\n\t\tofxTuioCursor *tcur = (*it);\n        float vx = tcur->getXSpeed() * tuioCursorSpeedMult;\n        float vy = tcur->getYSpeed() * tuioCursorSpeedMult;\n        if(vx == 0 && vy == 0) {\n            vx = ofRandom(-tuioStationaryForce, tuioStationaryForce);\n            vy = ofRandom(-tuioStationaryForce, tuioStationaryForce);\n        }\n        addToFluid(ofVec2f(tcur->getX() * tuioXScaler, tcur->getY() * tuioYScaler), ofVec2f(vx, vy), true, true);\n    }\n#endif\n\t\n\tfluidSolver.update();\n}\n\nvoid testApp::draw(){\n\tif(drawFluid) {\n        ofClear(0);\n\t\tglColor3f(1, 1, 1);\n\t\tfluidDrawer.draw(0, 0, ofGetWidth(), ofGetHeight());\n\t} else {\n//\t\tif(ofGetFrameNum()%5==0)\n            fadeToColor(0, 0, 0, 0.01);\n\t}\n\tif(drawParticles)\n\t\tparticleSystem.updateAndDraw(fluidSolver, ofGetWindowSize(), drawFluid);\n\t\n//\tofDrawBitmapString(sz, 50, 50);\n\n#ifdef USE_GUI \n\tgui.draw();\n#endif\n}\n\n\nvoid testApp::keyPressed  (int key){ \n    switch(key) {\n\t\tcase '1':\n\t\t\tfluidDrawer.setDrawMode(msa::fluid::kDrawColor);\n\t\t\tbreak;\n\n\t\tcase '2':\n\t\t\tfluidDrawer.setDrawMode(msa::fluid::kDrawMotion);\n\t\t\tbreak;\n\n\t\tcase '3':\n\t\t\tfluidDrawer.setDrawMode(msa::fluid::kDrawSpeed);\n\t\t\tbreak;\n\t\t\t\n\t\tcase '4':\n\t\t\tfluidDrawer.setDrawMode(msa::fluid::kDrawVectors);\n\t\t\tbreak;\n    \n\t\tcase 'd':\n\t\t\tdrawFluid ^= true;\n\t\t\tbreak;\n\t\t\t\n\t\tcase 'p':\n\t\t\tdrawParticles ^= true;\n\t\t\tbreak;\n\t\t\t\n\t\tcase 'f':\n\t\t\tofToggleFullscreen();\n\t\t\tbreak;\n\t\t\t\n\t\tcase 'r':\n\t\t\tfluidSolver.reset();\n\t\t\tbreak;\n\t\t\t\n\t\tcase 'b': {\n//\t\t\tTimer timer;\n//\t\t\tconst int ITERS = 3000;\n//\t\t\ttimer.start();\n//\t\t\tfor(int i = 0; i < ITERS; ++i) fluidSolver.update();\n//\t\t\ttimer.stop();\n//\t\t\tcout << ITERS << \" iterations took \" << timer.getSeconds() << \" seconds.\" << std::endl;\n\t\t}\n\t\t\tbreak;\n\t\t\t\n    }\n}\n\n\n//--------------------------------------------------------------\nvoid testApp::mouseMoved(int x, int y){\n\tofVec2f eventPos = ofVec2f(x, y);\n\tofVec2f mouseNorm = ofVec2f(eventPos) / ofGetWindowSize();\n\tofVec2f mouseVel = ofVec2f(eventPos - pMouse) / ofGetWindowSize();\n\taddToFluid(mouseNorm, mouseVel, true, true);\n\tpMouse = eventPos;\n}\n\nvoid testApp::mouseDragged(int x, int y, int button) {\n\tofVec2f eventPos = ofVec2f(x, y);\n\tofVec2f mouseNorm = ofVec2f(eventPos) / ofGetWindowSize();\n\tofVec2f mouseVel = ofVec2f(eventPos - pMouse) / ofGetWindowSize();\n\taddToFluid(mouseNorm, mouseVel, false, true);\n\tpMouse = eventPos;\n}\n\n"
  },
  {
    "path": "example/src/testApp.h",
    "content": "#pragma once\n\n#include \"MSAFluid.h\"\n//#include \"MSATimer.h\"\n#include \"ParticleSystem.h\"\n\n#include \"ofMain.h\"\n\n// comment this line out if you don't wanna use TUIO\n// you will need ofxTUIO & ofxOsc\n//#define USE_TUIO\n\n// comment this line out if you don't wanna use the GUI\n// you will need ofxSimpleGuiToo, ofxMSAInteractiveObject & ofxXmlSettings\n// if you don't use the GUI, you won't be able to see the fluid parameters\n#define USE_GUI\t\t\n\n\n#ifdef USE_TUIO\n#include \"ofxTuio.h\"\n#define tuioCursorSpeedMult\t\t\t\t0.5\t// the iphone screen is so small, easy to rack up huge velocities! need to scale down \n#define tuioStationaryForce\t\t\t\t0.001f\t// force exerted when cursor is stationary\n#endif\n\n\n#ifdef USE_GUI \n#include \"ofxSimpleGuiToo.h\"\n#endif\n\nclass testApp : public ofBaseApp {\npublic:\n\n\n\n\tfloat                   colorMult;\n\tfloat                   velocityMult;\n\tint                     fluidCellsX;\n\tbool                    resizeFluid;\n\tbool                    drawFluid;\n\tbool                    drawParticles;\n\n\t// TODO\n\tstruct {\n\t\tint count;\n\t\tstruct Disturber {\n\t\t\tofVec2f pos;\n\t\t\tofVec2f vel;\n\t\t\tfloat amp;\n\t\t};\n\t\tfloat noiseAmp;\n\t\tfloat noiseFreq;\n\t\tbool draw;\n\t\tvector<Disturber> forces;\n\t} randForce;\n\n\tmsa::fluid::Solver      fluidSolver;\n\tmsa::fluid::DrawerGl\tfluidDrawer;\n\n\tParticleSystem          particleSystem;\n\n\tofVec2f                 pMouse;\n\n\tfloat vectorLength;\n\n\tvoid setup();\n\tvoid update();\n\tvoid draw();\n\t\n\tvoid keyPressed  (int key);\n\tvoid mouseMoved(int x, int y );\n\tvoid mouseDragged(int x, int y, int button);\n\n\tvoid fadeToColor(float r, float g, float b, float speed);\n\tvoid addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce);\n\n\t\n#ifdef USE_TUIO\n\tofxTuioClient tuioClient;\n#endif\t\n\t\n};\n"
  },
  {
    "path": "license.md",
    "content": "The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license).\n\nCopyright (c) 2008-2012 Memo Akten, [www.memo.tv](http://www.memo.tv)  \nThe Mega Super Awesome Visuals Company\n\n//\tApril-Mai 2009 optimized and extended by Maa (http://www.lagraine.com/ - new content coming soon)\n\n/* Portions Copyright (c) 2010, The Cinder Project, http://libcinder.org */\n\n\n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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."
  },
  {
    "path": "src/MSAFluid.h",
    "content": "#pragma once\n\n#include \"MSAFluidSolver.h\"\n\n#if defined( MSA_HOST_OPENFRAMEWORKS )\n#include \"MSAFluidDrawerGl-OF.h\"\n\n#elif defined( MSA_HOST_CINDER )\n#include \"MSAFluidDrawerGl-Cinder.h\"\n\n#endif\n"
  },
  {
    "path": "src/MSAFluidDrawerBase.cpp",
    "content": "/***********************************************************************\n \n This class is for drawing a fluidsolver using the openFrameworks texture\n \n ************************************************************************/\n\n#include \"MSAFluidDrawerBase.h\"\n\n\nnamespace msa {\n    namespace fluid {\n        \n        //--------------------------------------------------------------\n        vector<string>& getDrawModeTitles(){\n            static vector<string> drawModeTitles;\n            if(drawModeTitles.size() == 0) {\n                drawModeTitles.push_back(\"kDrawColor\");\n                drawModeTitles.push_back(\"kDrawMotion\");\n                drawModeTitles.push_back(\"kDrawSpeed\");\n                drawModeTitles.push_back(\"kDrawVectors\");\n            }\n            return drawModeTitles;\n        }\n        \n        \n        //--------------------------------------------------------------\n        DrawerBase::DrawerBase() {\n            _pixels\t\t\t\t= NULL;\n            _fluidSolver\t\t= NULL;\n            _didICreateTheFluid\t= false;\n            \n            enabled\t\t\t\t= true;\n            useAdditiveBlending = false;\n            brightness\t\t\t= 1;\n            doInvert\t\t\t= false;\n            velDrawMult\t\t\t\t= 1;\n            vectorSkipCount\t\t= 0;\n            \n            enableAlpha(false);\n            \n            setDrawMode(kDrawColor);\n        }\n        \n        //--------------------------------------------------------------\n        DrawerBase::~DrawerBase() {\n            deleteFluidSolver();\n        }\n        \n\n        //--------------------------------------------------------------\n        Solver* DrawerBase::setup(int NX, int NY) {\n            deleteFluidSolver();\n            _fluidSolver = new Solver;\n            _fluidSolver->setup(NX, NY);\n            allocatePixels();\n            createTexture();\n            \n            return _fluidSolver;\n        }\n        \n\n        //--------------------------------------------------------------\n        Solver* DrawerBase::setup(Solver* f) {\n            deleteFluidSolver();\n            _fluidSolver = f;\n            allocatePixels();\n            createTexture();\n            \n            return _fluidSolver;\n        }\n        \n        //--------------------------------------------------------------\n        Solver* DrawerBase::getFluidSolver() {\n            return _fluidSolver;\n        }\n        \n        //--------------------------------------------------------------\n        void DrawerBase::enableAlpha(bool b) {\n            _alphaEnabled = b;\n            if(_alphaEnabled) {\n                _glType = GL_RGBA;\n                _bpp = 4;\n            } else {\n                _glType = GL_RGB;\n                _bpp = 3;\n            }\n            \n            if(isFluidReady()) {\n                allocatePixels();\n                createTexture();\n            }\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::allocatePixels() {\n            if(_pixels) delete []_pixels;\n            int texWidth = _fluidSolver->getWidth()-2;\n            int texHeight =_fluidSolver->getHeight()-2;\n            _pixels = new unsigned char[texWidth * texHeight * _bpp];\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::reset() {\n            if(!isFluidReady()) {\n                printf(\"DrawerBase::reset() - Fluid not ready\\n\");\n                return;\n            }\n            _fluidSolver->reset();\n        }\n        \n        //--------------------------------------------------------------\n        void DrawerBase::update() {\n            if(!isFluidReady()) {\n                printf(\"DrawerBase::updateFluid() - Fluid not ready\\n\");\n                return;\n            }\n            _fluidSolver->update();\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::setDrawMode(DrawMode newDrawMode) {\n            drawMode = newDrawMode;\n            if(drawMode < 0) drawMode = (DrawMode)(kDrawCount-1);\n            else if(drawMode >= kDrawCount) drawMode = (DrawMode)0;\n        }\n        \n        //--------------------------------------------------------------\n        void DrawerBase::incDrawMode() {\n            setDrawMode((DrawMode)((int)drawMode + 1));\n        }\n        \n        //--------------------------------------------------------------\n        void DrawerBase::decDrawMode() {\n            setDrawMode((DrawMode)(drawMode - 1));\n        }\n        \n        //--------------------------------------------------------------\n        DrawMode DrawerBase::getDrawMode() {\n            return drawMode;\n        }\n        \n        //--------------------------------------------------------------\n        string DrawerBase::getDrawModeName() {\n            return getDrawModeTitles().at(drawMode);\n        }\n        \n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::draw(float x, float y) const {\n            if(enabled == false) return;\n            \n            draw(x, y, getWindowWidth(), getWindowHeight());\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::draw(float x, float y, float renderWidth, float renderHeight) const {\n            if(enabled == false) return;\n            \n            switch(drawMode) {\n                case kDrawColor:\n                    drawColor(x, y, renderWidth, renderHeight);\n                    break;\n                    \n                case kDrawMotion:\n                    drawMotion(x, y, renderWidth, renderHeight);\n                    break;\n                    \n                case kDrawSpeed:\n                    drawSpeed(x, y, renderWidth, renderHeight);\n                    break;\n                    \n                case kDrawVectors:\n                    drawVectors(x, y, renderWidth, renderHeight);\n                    break;\n                    \n                default:\n                    break;\n                    \n            }\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::drawColor(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {\n            if(enabled == false) return;\n            \n            ofPushStyle();\n            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);\n            else ofDisableAlphaBlending();\n\n            int fw = _fluidSolver->getWidth();\n            int fh = _fluidSolver->getHeight();\n            \n            Vec2f vel;\n            Color color;\n            int index = 0;\n            for(int j=1; j < fh-1; j++) {\n                for(int i=1; i < fw-1; i++) {\n                    _fluidSolver->getInfoAtCell(i, j, &vel, &color);\n                    int r = (unsigned char)min(color.r * 255 * brightness, 255.0f);\n                    int g = (unsigned char)min(color.g * 255 * brightness, 255.0f);\n                    int b = (unsigned char)min(color.b * 255 * brightness, 255.0f);\n                    if(doInvert) {\n                        r = 255 - r;\n                        g = 255 - g;\n                        b = 255 - b;\n                    }\n                    _pixels[index++] = r;\n                    _pixels[index++] = g;\n                    _pixels[index++] = b;\n                    \n                    if(_alphaEnabled) _pixels[index++] = withAlpha ? max(b, max(r, g)) : 255;\n                }\n            }\n            \n            updateTexture();\n            drawTexture(x, y, renderWidth, renderHeight);\n            ofPopStyle();\n        }\n        \n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::drawMotion(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {\n            if(enabled == false) return;\n            \n            ofPushStyle();\n            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);\n            else ofDisableAlphaBlending();\n            \n            int fw = _fluidSolver->getWidth();\n            int fh = _fluidSolver->getHeight();\n            \n            Vec2f vel;\n            int index = 0;\n            for(int j=1; j < fh-1; j++) {\n                for(int i=1; i < fw-1; i++) {\n                    _fluidSolver->getInfoAtCell(i, j, &vel, NULL);\n                    float speed2 = fabs(vel.x) * fw + fabs(vel.y) * fh;\n                    int speed = (int)min(speed2 * 255 * brightness, 255.0f);\n                    _pixels[index++] = (unsigned char)min(fabs(vel.x) * fw * 255 * brightness, 255.0f);\n                    _pixels[index++] = (unsigned char)min(fabs(vel.y) * fh * 255 * brightness, 255.0f);\n                    _pixels[index++] = (unsigned char)0;\n                    \n                    if(_alphaEnabled) _pixels[index++] = withAlpha ? speed : 255;\n                    \n                }\n            }\n            \n            updateTexture();\n            drawTexture(x, y, renderWidth, renderHeight);\n            ofPopStyle();\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::drawSpeed(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {\n            if(enabled == false) return;\n            \n            ofPushStyle();\n            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);\n            else ofDisableAlphaBlending();\n            \n            int fw = _fluidSolver->getWidth();\n            int fh = _fluidSolver->getHeight();\n            \n            Vec2f vel;\n            int index = 0;\n            for(int j=1; j < fh-1; j++) {\n                for(int i=1; i < fw-1; i++) {\n                    _fluidSolver->getInfoAtCell(i, j, &vel, NULL);\n                    float speed2 = fabs(vel.x) * fw + fabs(vel.y) * fh;\n                    int speed = (int)min(speed2 * 255 * brightness, 255.0f);\n                    _pixels[index++] = (unsigned char)speed;\n                    _pixels[index++] = (unsigned char)speed;\n                    _pixels[index++] = (unsigned char)speed;\n                    \n                    if(_alphaEnabled) _pixels[index++] = withAlpha ? speed : 255;\n                }\n            }\n            \n            updateTexture();\n            drawTexture(x, y, renderWidth, renderHeight);\n            ofPopStyle();\n        }\n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::drawVectors(float x, float y, float renderWidth, float renderHeight)  const {\n            if(enabled == false) return;\n            \n            ofPushStyle();\n            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);\n            else ofDisableAlphaBlending();\n\n            int fw = _fluidSolver->getWidth();\n            int fh = _fluidSolver->getHeight();\n\n            //\tint xStep = renderWidth / 10;\t\t// every 10 pixels\n            //\tint yStep = renderHeight / 10;\t\t// every 10 pixels\n            \n            ofPushMatrix();\n            ofTranslate(x, y, 0);\n            ofScale(renderWidth/(fw-2), renderHeight/(fh-2), 1.0);\n            \n            float maxVel = 5.0f/20000;\n            \n            Vec2f vel;\n            float vt = velDrawThreshold * _fluidSolver->getInvWidth() * _fluidSolver->getInvHeight();\n            vt *= vt;\n\t\t\tofMesh mesh;\n            for (int j=0; j<fh-2; j+=vectorSkipCount+1 ){\n                for (int i=0; i<fw-2; i+=vectorSkipCount+1 ){\n\t\t\t\t\tofVec2f pos(i, j);\n\t\t\t\t\tvel = _fluidSolver->getVelocityAtCell(i+1, j+1);\n                    float d2 = vel.lengthSquared();\n                    if(d2>vt) {\n                        if(d2 > maxVel * maxVel) {\n                            float mult = maxVel * maxVel/ d2;\n                            //\t\t\t\tfloat mult = (d2 - maxVel * maxVel) / d2;\n                            vel.x *= mult;\n                            vel.y *= mult;\n                        }\n                        vel *= velDrawMult * 50000;\n                        float b = mapRange(d2, vt, maxVel, 0.0f, brightness);\n                        b = brightness*255;\n\t\t\t\t\t\tmesh.addColor(ofColor::black);\n\t\t\t\t\t\tmesh.addVertex(ofVec3f(pos));\n\n\t\t\t\t\t\tmesh.addColor(ofColor(b, b, b));\n\t\t\t\t\t\tmesh.addVertex(ofVec3f(pos + vel));\n\n\t\t\t\t\t\t//ofSetColor(b, b, b);\n\t\t\t\t\t\t//ofDrawLine(i, j, i + vel.x, j + vel.y);\n\n\t\t\t\t\t\t//ofSetPolyMode(OF_POLY_WINDING_POSITIVE);\n\t\t\t\t\t\t//ofNoFill();\n\t\t\t\t\t\t//ofBeginShape();\n\t\t\t\t\t\t//ofSetColor(0, 0, 0);\n\t\t\t\t\t\t//ofVertex(i, j);\n\t\t\t\t\t\t//ofSetColor(b, b, b);\n\t\t\t\t\t\t//ofVertex(i + vel.x, j + vel.y);\n\t\t\t\t\t\t//ofEndShape();\n\n\n\t\t\t\t\t}\n                }\n            }\n\t\t\tmesh.setMode(OF_PRIMITIVE_LINES);\n\t\t\tmesh.drawWireframe();\n            ofPopMatrix();\n            ofPopStyle();\n        }\n        \n        \n        \n        //--------------------------------------------------------------\n        void DrawerBase::deleteFluidSolver() {\n            //\tprintf(\"DrawerBase::deleteFluidSolver()\\n\");\n            if(_fluidSolver && _didICreateTheFluid) {\n                delete _fluidSolver;\n                _fluidSolver = NULL;\n                \n                if(_pixels) delete []_pixels;\n                _pixels = NULL;\n                \n                deleteTexture();\n            }\n        }\n        \n        //--------------------------------------------------------------\n        bool DrawerBase::isFluidReady() {\n            if(!_fluidSolver) {\n                printf(\"DrawerBase::isFluidReady() - No fluid solver\\n\");\n                return false;\n            }\n            \n            if(!_fluidSolver->isInited()) {\n                printf(\"DrawerBase::isFluidReady() - Fluid solver not initialized yet, call init()\\n\");\n                return false;\n            }\n            \n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/MSAFluidDrawerBase.h",
    "content": "/***********************************************************************\n \n This class is for drawing a fluidsolver using the OpenFrameworks texture\n \n ************************************************************************/\n\n#pragma once\n\n#include \"MSACore.h\"\n#include \"MSAFluidSolver.h\"\n\nnamespace msa {\n\tnamespace fluid {\n        \n        typedef enum {\n            kDrawColor,\n            kDrawMotion,\n            kDrawSpeed,\n            kDrawVectors,\n            kDrawCount\n        } DrawMode;\n        \n        \n        vector<string>& getDrawModeTitles();\n        \n        class DrawerBase\n#ifdef MSA_HOST_OPENFRAMEWORKS\n        : public ofBaseDraws\n#endif\n        {\n        public:\n            bool\tenabled;\n            bool\tdoInvert;\n            bool\tuseAdditiveBlending;\n            float\tbrightness;\n            float\tvelDrawThreshold;\n            float\tvelDrawMult;\n            int\t\tvectorSkipCount;\n            \n            DrawMode\t\tdrawMode;\n            \n            DrawerBase();\n            virtual ~DrawerBase();\n            \n            Solver* setup(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);\n            Solver* setup(Solver* f);\n            Solver* getFluidSolver();\n            \n            void enableAlpha(bool b);\n            \n            void update();\n            \n            void draw(float x, float y) const override;\n            void draw(float x, float y, float renderWidth, float renderHeight) const override;\t\t\t\t// this one does chooses one of the below based on drawmode\n            void drawColor(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;\n            void drawMotion(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;\n            void drawSpeed(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;\n            void drawVectors(float x, float y, float renderWidth, float renderHeight) const;\n            void reset();\n            \n           // float getWidth() const override {}\n            //float getHeight() const override {}\n            \n            void setDrawMode(DrawMode newDrawMode);\n            void incDrawMode();\n            void decDrawMode();\n            DrawMode getDrawMode();\n            string getDrawModeName();\n            \n        protected:\n            unsigned char\t\t*_pixels;\t\t\t\t\t\t// pixels array to be drawn\n            \n            int\t\t\t\t\t_glType;\t\t\t\t\t\t// GL_RGB or GL_RGBA\n            bool\t\t\t\t_alphaEnabled;\n            int\t\t\t\t\t_bpp;\t\t\t\t\t\t\t// 3 or 4\n            \n            Solver              *_fluidSolver;\n            bool\t\t\t\t_didICreateTheFluid;    // TODO: replace with shared pointer\n            \n            void\t\t\t\tallocatePixels();\n            \n            virtual void\t\tcreateTexture() = 0;\t\t\t\t\t\t\t\t\t// override to create a texture\n            virtual void\t\tupdateTexture() const = 0;\t\t\t\t\t\t\t\t\t// override to update the texture from the pixels array\n            virtual void\t\tdeleteTexture() = 0;\t\t\t\t\t\t\t\t\t// override to delete the texture\n            virtual void\t\tdrawTexture(float x, float y, float w, float h) const = 0;\t// override to draw texture\n            \n            void\t\t\t\tdeleteFluidSolver();\n            bool\t\t\t\tisFluidReady();\n            \n        };\n    }\n}\n"
  },
  {
    "path": "src/MSAFluidDrawerGl-Cinder.h",
    "content": "/***********************************************************************\n \n This class is for drawing a fluidsolver using the OpenFrameworks texture\n \n /***********************************************************************\n \n Copyright (c) 2008, 2009, 2010, Memo Akten, www.memo.tv\n *** The Mega Super Awesome Visuals Company ***\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n *     * Redistributions of source code must retain the above copyright\n *       notice, this list of conditions and the following disclaimer.\n *     * Redistributions in binary form must reproduce the above copyright\n *       notice, this list of conditions and the following disclaimer in the\n *       documentation and/or other materials provided with the distribution.\n *     * Neither the name of MSA Visuals nor the names of its contributors \n *       may be used to endorse or promote products derived from this software\n *       without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" \n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, \n * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS \n * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE \n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE. \n *\n * ***********************************************************************/ \n\n#pragma once\n\n#include \"MSAFluidDrawerBase.h\"\n#include \"cinder/Surface.h\"\n#include \"cinder/gl/Texture.h\"\n\nnamespace msa {\n\t\n\tclass FluidDrawerGl : public FluidDrawerBase {\n\tpublic:\n\t\t\n\t\tfloat getWidth() {\n\t\t\treturn tex.getWidth();\n\t\t}\n\t\t\n\t\tfloat getHeight() {\n\t\t\treturn tex.getHeight();\n\t\t}\n\t\t\n\tprotected:\t\n\t\tci::Surface8u\t\tsurface;\n\t\tci::gl::Texture\t\ttex;\n\n\t\tvoid createTexture() {\n\t\t\tint texWidth = _fluidSolver->getWidth()-2;\n\t\t\tint texHeight =_fluidSolver->getHeight()-2;\n\t\t\t\n\t\t\tsurface = ci::Surface8u( _pixels, texWidth, texHeight, false, ci::SurfaceChannelOrder::RGB );\n\t\t\t\n\t\t\tci::gl::Texture::Format format;\n\t\t\tformat.setInternalFormat( _glType );\n\t\t\ttex = ci::gl::Texture( texWidth, texHeight, format );\n\t\t}\n\t\t\n\t\t\n\t\tvoid updateTexture() {\n\t\t\ttex.update( surface );\n\t\t}\n\t\t\n\t\tvoid deleteTexture() {\n\t\t\ttex.reset();\n\t\t}\n\t\t\n\t\tvoid drawTexture(float x, float y, float w, float h) {\n\t\t\tci::gl::draw( tex, ci::Rectf( x, y, x + w, y + h ) );\n\t\t}\n\t};\n}\n"
  },
  {
    "path": "src/MSAFluidDrawerGl-OF.h",
    "content": "/***********************************************************************\n \n This class is for drawing a fluidsolver using the OpenFrameworks texture\n \n ************************************************************************/\n\n#pragma once\n\n#include \"MSAFluidDrawerBase.h\"\n\nnamespace msa {\n    namespace fluid {\n        \n        class DrawerGl : public DrawerBase {\n        public:\n            float getWidth() const override {\n                return tex.getWidth();\n            }\n            \n            float getHeight() const override {\n                return tex.getHeight();\n            }\n            \n            ofTexture&\tgetTextureReference() {\n                return tex;\n            }\n            \n            \n        protected:\n            mutable ofTexture\t\t\ttex;\n            \n            void createTexture() override {\n                int texWidth = _fluidSolver->getWidth()-2;\n                int texHeight =_fluidSolver->getHeight()-2;\n                tex.allocate(texWidth, texHeight, _glType);\n            }\n            \n            \n            void updateTexture() const override {\n                tex.loadData(_pixels, (int)tex.getWidth(), (int)tex.getHeight(), _glType);\n            }\n            \n            void deleteTexture() override {\n                tex.clear();\n            }\n            \n            void drawTexture(float x, float y, float w, float h) const override {\n                tex.draw(x, y, w, h);\n            }\t\t\n        };\n    }\n}\n"
  },
  {
    "path": "src/MSAFluidParticleUpdater.h",
    "content": "/***********************************************************************\n \n This class interfaces the fluid solver with ofxMSAPhysics (applies fluid velocity as forces to particles)\n \n ***********************************************************************/\n\n// only include this if you have MSAPhysics as well\n\n\n#pragma once\n\n#include \"MSAFluid.h\"\n#include \"MSAPhysicsParticleUpdater.h\"\n\nnamespace msa {\n\t\n\ttemplate <typename T>\n\tclass FluidParticleUpdater : public Physics::ParticleUpdaterT<T> {\n\tpublic:\n\t\tfloat strength;\n\t\tSolver *fluidSolver;\n\t\t\n\t\tFluidParticleUpdater() {\n\t\t\tfluidSolver = NULL;\n\t\t}\n\t\t\n\t\tvoid update(Physics::ParticleT<T> *p) {\n\t\t\tif(fluidSolver) {\n\t\t\t\tVec2f fluidVel = fluidSolver->getVelocityAtPos(p->getPosition()* p->getParams()->worldSizeInv);\n\t\t\t\tfloat invMass = p->getInvMass();\n\t\t\t\tp->addVelocity(fluidVel.x * invMass * strength, fluidVel.y * invMass * strength, 0);\n\t\t\t}\n\t\t}\n\t\t\n\t};\n\t\n}\n"
  },
  {
    "path": "src/MSAFluidSolver.cpp",
    "content": "/***********************************************************************\n \n This class is for the actual solver (doesn't draw anything)\n \n ************************************************************************/\n\n#include \"MSAFluidSolver.h\"\n\nnamespace msa {\n    namespace fluid {\n        \n        Solver::Solver()\n        :density(NULL)\n        ,densityOld(NULL)\n        ,uv(NULL)\n        ,uvOld(NULL)\n        ,color(NULL)\n        ,colorOld(NULL)\n        ,curl(NULL)\n        ,_isInited(false)\n        {\n        }\n        \n        //--------------------------------------------------------------\n        Solver& Solver::setSize(int NX, int NY)\n        {\n            _NX = NX;\n            _NY = NY;\n            _numCells = (_NX + 2) * (_NY + 2);\n            \n            _invNX = 1.0f / _NX;\n            _invNY = 1.0f / _NY;\n            _invNumCells = 1.0f / _numCells;\n            \n            width           = getWidth();\n            height          = getHeight();\n            invWidth        = 1.0f/width;\n            invHeight       = 1.0f/height;\n            \n            reset();\n            return *this;\n        }\n        \n        \n        //--------------------------------------------------------------\n        Solver& Solver::setup(int NX, int NY)\n        {\n            setDeltaT();\n            setFadeSpeed();\n            setSolverIterations();\n            enableVorticityConfinement(false);\n            setWrap(false, false);\n            \n            //maa\n            viscocity =  FLUID_DEFAULT_VISC;\n            colorDiffusion = FLUID_DEFAULT_COLOR_DIFFUSION;\n            \n            return setSize(NX, NY);\n        }\n        \n        //--------------------------------------------------------------\n        Solver&  Solver::setDeltaT(float deltaT) {\n            this->deltaT = deltaT;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        Solver&  Solver::setFadeSpeed(float fadeSpeed) {\n            this->fadeSpeed = fadeSpeed;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        Solver&  Solver::setSolverIterations(int solverIterations) {\n            this->solverIterations = solverIterations;\n            return *this;\n        }\n        \n        \n        //--------------------------------------------------------------\n        // whether fluid is RGB or monochrome (if only pressure / velocity is needed no need to update 3 channels)\n        Solver&  Solver::enableRGB(bool doRGB) {\n            this->doRGB = doRGB;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        Solver&  Solver::enableVorticityConfinement(bool b) {\n            doVorticityConfinement = b;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        bool Solver::getVorticityConfinement() {\n            return doVorticityConfinement;\n        }\n        \n        //--------------------------------------------------------------\n        Solver& Solver::setWrap(bool bx, bool by) {\n            wrap_x = bx;\n            wrap_y = by;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        bool Solver::isInited() const {\n            return _isInited;\n        }\n        \n        //--------------------------------------------------------------\n        Solver::~Solver() {\n            destroy();\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::destroy() {\n            _isInited = false;\n            \n            if(density)\t\tdelete []density;\n            if(densityOld)\tdelete []densityOld;\n            if(color)\t\tdelete []color;\n            if(colorOld)\tdelete []colorOld;\n            if(uv)\t\tdelete []uv;\n            if(uvOld)\tdelete []uvOld;\n            if(curl)       delete []curl;\n        }\n        \n        \n        //--------------------------------------------------------------\n        void Solver::reset() {\n            destroy();\n            _isInited = true;\n            \n            density\t\t= new float[_numCells];\n            densityOld\t= new float[_numCells];\n            color\t\t= new Vec3f[_numCells];\n            colorOld\t= new Vec3f[_numCells];\n            uv    = new Vec2f[_numCells];\n            uvOld = new Vec2f[_numCells];\n            curl = new float[_numCells];\n            \n            for (int i = _numCells-1; i>=0; --i) {\n                density[i] = 0;\n                densityOld[i] = 0;\n                color[i] = Vec3f::zero();\n                colorOld[i] = Vec3f::zero();\n                uv[i] = Vec2f::zero();\n                uvOld[i] = Vec2f::zero();\n                curl[i] = 0.0f;\n            }\n        }\n        \n        //--------------------------------------------------------------\n        // return total number of cells (_NX+2) * (_NY+2)\n        int Solver::getNumCells() const {\n            return _numCells;\n        }\n        \n        //--------------------------------------------------------------\n        int Solver::getWidth() const {\n            return _NX + 2;\n        }\n        \n        \n        //--------------------------------------------------------------\n        int Solver::getHeight() const {\n            return _NY + 2;\n        }\n        \n        //--------------------------------------------------------------\n        float Solver::getInvWidth() const {\n            return invWidth;\n        }\n        \n        \n        //--------------------------------------------------------------\n        float Solver::getInvHeight() const {\n            return invHeight;\n        }\n        \n        //--------------------------------------------------------------\n        Vec2f Solver::getSize() {\n            return Vec2f(getWidth(), getHeight());\n        }\n        \n        //--------------------------------------------------------------\n        Vec2f Solver::getInvSize() {\n            return Vec2f(invWidth, invHeight);\n        }\n        \n        \n        \n        //--------------------------------------------------------------\n        Solver& Solver::setVisc(float newVisc) {\n            viscocity = newVisc;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        // returns current viscocity\n        float Solver::getVisc() const {\n            return viscocity;\n        }\n        \n        //--------------------------------------------------------------\n        Solver& Solver::setColorDiffusion(float diff)\n        {\n            colorDiffusion = diff;\n            return *this;\n        }\n        \n        //--------------------------------------------------------------\n        float\tSolver::getColorDiffusion()\n        {\n            return colorDiffusion;\n        }\n        \n        //--------------------------------------------------------------\n        // returns average density of fluid\n        float Solver::getAvgDensity() const {\n            return _avgDensity;\n        }\n        \n        //--------------------------------------------------------------\n        // returns average uniformity\n        float Solver::getUniformity() const {\n            return _uniformity;\n        }\n        \n        //--------------------------------------------------------------\n        float Solver::getAvgSpeed() const {\n            return _avgSpeed;\n        }\n        \n        //--------------------------------------------------------------\n        // Curl and vorticityConfinement based on code by Alexander McKenzie\n        float Solver::calcCurl(int i, int j)\n        {\n            float du_dy = uv[FLUID_IX(i, j + 1)].x - uv[FLUID_IX(i, j - 1)].x;\n            float dv_dx = uv[FLUID_IX(i + 1, j)].y - uv[FLUID_IX(i - 1, j)].y;\n            return (du_dy - dv_dx) * 0.5f;\t// for optimization should be moved to later and done with another operation\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::vorticityConfinement(Vec2f* Fvc_xy) {\n            float dw_dx, dw_dy;\n            float length;\n            float v;\n            \n            // Calculate magnitude of calcCurl(u,v) for each cell. (|w|)\n            for (int j = _NY; j > 0; --j)\n            {\n                for (int i = _NX; i > 0; --i)\n                {\n                    curl[FLUID_IX(i, j)] = fabs(calcCurl(i, j));\n                }\n            }\n            \n            for (int j = _NY-1; j > 1; --j)\t//for (int j = 2; j < _NY; j++)\n            {\n                for (int i = _NX-1; i > 1; --i)\t\t//for (int i = 2; i < _NX; i++)\n                {\n                    // Find derivative of the magnitude (_N = del |w|)\n                    dw_dx = (curl[FLUID_IX(i + 1, j)] - curl[FLUID_IX(i - 1, j)]);\t// was * 0.5f; now done later with 2./lenght\n                    dw_dy = (curl[FLUID_IX(i, j + 1)] - curl[FLUID_IX(i, j - 1)]);\t// was * 0.5f;\n                    \n                    // Calculate vector length. (|_N|)\n                    // Add small factor to prevent divide by zeros.\n                    length = (float) sqrt(dw_dx * dw_dx + dw_dy * dw_dy) + 0.000001f;\n                    \n                    // N = (_N/|_N|)\n                    length = 2./length;\t// the 2. come from the previous * 0.5\n                    dw_dx *= length;\n                    dw_dy *= length;\n                    \n                    v = calcCurl(i, j);\n                    \n                    // N x w\n                    Fvc_xy[FLUID_IX(i, j)].x = dw_dy * -v;\n                    Fvc_xy[FLUID_IX(i, j)].y = dw_dx *  v;\n                }\n            }\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::update() {\n            addSource(uv, uvOld);\n            \n            if(doVorticityConfinement)\n            {\n                vorticityConfinement(uvOld);\n                addSource(uv, uvOld);\n            }\n            \n            SWAP(uv, uvOld);\n            \n            diffuseUV(viscocity);\n            \n            project(uv, uvOld);\n            \n            SWAP(uv, uvOld);\n            \n            advect2d(uv, uvOld);\n            \n            project(uv, uvOld);\n            \n            if(doRGB)\n            {\n                addSource(color, colorOld);\n                SWAP(color, colorOld);\n                \n                if(colorDiffusion!=0. && deltaT!=0.)\n                {\n                    diffuseRGB(0, colorDiffusion);\n                    SWAP(color, colorOld);\n                }\n                \n                advectRGB(0, uv);\n                fadeRGB();\n            }\n            else\n            {\n                addSource(density, densityOld);\n                SWAP(density, densityOld);\n                \n                if(colorDiffusion!=0. && deltaT!=0.) {\n                    diffuse(0, density, densityOld, colorDiffusion);\n                    SWAP(density, densityOld);\n                }\n                \n                advect(0, density, densityOld, uv);\n                fadeDensity();\n            }\n        }\n        \n#define ZERO_THRESH\t\t1e-9\t\t\t// if value falls under this, set to zero (to avoid denormal slowdown)\n#define CHECK_ZERO(p)\tif(fabsf(p)<ZERO_THRESH) p = 0\n        \n        //--------------------------------------------------------------\n        void Solver::fadeDensity() {\n            // I want the fluid to gradually fade out so the screen doesn't fill. the amount it fades out depends on how full it is, and how uniform (i.e. boring) the fluid is...\n            //\t\tfloat holdAmount = 1 - _avgDensity * _avgDensity * fadeSpeed;\t// this is how fast the density will decay depending on how full the screen currently is\n            float holdAmount = 1 - fadeSpeed;\n            \n            _avgDensity = 0;\n            _avgSpeed = 0;\n            \n            float totalDeviations = 0;\n            float currentDeviation;\n            float tmp;\n            _avgSpeed = 0;\n            \n            for (int i = _numCells-1; i >=0; --i) {\n                \n                // clear old values\n                uvOld[i] = Vec2f::zero();\n                densityOld[i] = 0;\n                \n                // calc avg speed\n                _avgSpeed += uv[i].x * uv[i].x + uv[i].y * uv[i].y;\n                \n                // calc avg density\n                tmp = min(1.0f, density[i]);\n                _avgDensity += tmp;\t// add it up\n                \n                // calc deviation (for uniformity)\n                currentDeviation = tmp - _avgDensity;\n                totalDeviations += currentDeviation * currentDeviation;\n                \n                // fade out old\n                density[i] = tmp * holdAmount;\n                \n                CHECK_ZERO(density[i]);\n                CHECK_ZERO(uv[i].x);\n                CHECK_ZERO(uv[i].y);\n                if(doVorticityConfinement) CHECK_ZERO(curl[i]);\n                \n            }\n            _avgDensity *= _invNumCells;\n            _avgSpeed *= _invNumCells;\n            \n            //\tprintln(\"%.3f\\n\", _avgSpeed);\n            _uniformity = 1.0f / (1 + totalDeviations * _invNumCells);\t\t// 0: very wide distribution, 1: very uniform\n        }\n        \n        \n        //--------------------------------------------------------------\n        void Solver::fadeRGB() {\n            // I want the fluid to gradually fade out so the screen doesn't fill. the amount it fades out depends on how full it is, and how uniform (i.e. boring) the fluid is...\n            //\t\tfloat holdAmount = 1 - _avgDensity * _avgDensity * fadeSpeed;\t// this is how fast the density will decay depending on how full the screen currently is\n            float holdAmount = 1 - fadeSpeed;\n            \n            _avgDensity = 0;\n            _avgSpeed = 0;\n            \n            float totalDeviations = 0;\n            float currentDeviation;\n            Vec3f tmp;\n            _avgSpeed = 0;\n            \n            for (int i = _numCells-1; i >=0; --i)\n            {\n                // clear old values\n                uvOld[i] = Vec2f::zero();\n                colorOld[i] = Vec3f::zero();\n                \n                // calc avg speed\n                _avgSpeed += uv[i].x * uv[i].x + uv[i].y * uv[i].y;\n                \n                // calc avg density\n                tmp.x = min(1.0f, color[i].x);\n                tmp.y = min(1.0f, color[i].y);\n                tmp.z = min(1.0f, color[i].z);\n                //\t\t\ttmp.a = min(1.0f, color[i].a);\n                \n                //\t\t\tfloat density = max(tmp.a, max(tmp.r, max(tmp.g, tmp.b)));\n                //\t\t\tfloat density = max(tmp.r, max(tmp.g, tmp.b));\n                float density = max(tmp.x, max(tmp.y, tmp.z));\n                _avgDensity += density;\t// add it up\n                \n                // calc deviation (for _uniformity)\n                currentDeviation = density - _avgDensity;\n                totalDeviations += currentDeviation * currentDeviation;\n                \n                // fade out old\n                color[i] = tmp * holdAmount;\n                \n                CHECK_ZERO(color[i].x);\n                CHECK_ZERO(color[i].y);\n                CHECK_ZERO(color[i].z);\n                //\t\t\tCHECK_ZERO(color[i].a);\n                CHECK_ZERO(uv[i].x);\n                CHECK_ZERO(uv[i].y);\n                if(doVorticityConfinement) CHECK_ZERO(curl[i]);\n            }\n            _avgDensity *= _invNumCells;\n            _avgSpeed *= _invNumCells;\n            \n            //println(\"%.3f\\n\", _avgDensity);\n            _uniformity = 1.0f / (1 + totalDeviations * _invNumCells);\t\t// 0: very wide distribution, 1: very uniform\n        }\n        \n        \n        //\tvoid Solver::addSourceUV()\n        //\t{\n        //\t\tfor (int i = _numCells-1; i >=0; --i) {\n        //\t\t\tuv[i] += deltaT * uvOld[i];\n        //\t\t}\n        //\t}\n        //\n        //\tvoid Solver::addSourceRGB()\n        //\t{\n        //\t\tfor (int i = _numCells-1; i >=0; --i) {\n        //\t\t\tcolor[i] += deltaT * colorOld[i];\n        //\t\t}\n        //\t}\n        //\n        //\tvoid Solver::addSource(float* x, float* x0) {\n        //\t\tfor (int i = _numCells-1; i >=0; --i) {\n        //\t\t\tx[i] += deltaT * x0[i];\n        //\t\t}\n        //\t}\n        \n        //--------------------------------------------------------------\n        void Solver::advect(int bound, float* d, const float* d0, const Vec2f* duv) {\n            int i0, j0, i1, j1;\n            float x, y, s0, t0, s1, t1;\n            int\tindex;\n            \n            const float dt0x = deltaT * _NX;\n            const float dt0y = deltaT * _NY;\n            \n            for (int j = _NY; j > 0; --j)\n            {\n                for (int i = _NX; i > 0; --i)\n                {\n                    index = FLUID_IX(i, j);\n                    x = i - dt0x * duv[index].x;\n                    y = j - dt0y * duv[index].y;\n                    \n                    if (x > _NX + 0.5) x = _NX + 0.5f;\n                    if (x < 0.5)     x = 0.5f;\n                    \n                    i0 = (int) x;\n                    i1 = i0 + 1;\n                    \n                    if (y > _NY + 0.5) y = _NY + 0.5f;\n                    if (y < 0.5)     y = 0.5f;\n                    \n                    j0 = (int) y;\n                    j1 = j0 + 1;\n                    \n                    s1 = x - i0;\n                    s0 = 1 - s1;\n                    t1 = y - j0;\n                    t0 = 1 - t1;\n                    \n                    d[index] = s0 * (t0 * d0[FLUID_IX(i0, j0)] + t1 * d0[FLUID_IX(i0, j1)])\n                    + s1 * (t0 * d0[FLUID_IX(i1, j0)] + t1 * d0[FLUID_IX(i1, j1)]);\n                    \n                }\n            }\n            setBoundary(bound, d);\n        }\n        \n        //--------------------------------------------------------------\n        //          d    d0    du    dv\n        // advect(1, u, uOld, uOld, vOld);\n        // advect(2, v, vOld, uOld, vOld);\n        void Solver::advect2d(Vec2f *uv, const Vec2f *duv) {\n            int i0, j0, i1, j1;\n            float s0, t0, s1, t1;\n            int\tindex;\n            \n            const float dt0x = deltaT * _NX;\n            const float dt0y = deltaT * _NY;\n            \n            for (int j = _NY; j > 0; --j)\n            {\n                for (int i = _NX; i > 0; --i)\n                {\n                    index = FLUID_IX(i, j);\n                    float x = i - dt0x * duv[index].x;\n                    float y = j - dt0y * duv[index].y;\n                    \n                    if (x > _NX + 0.5) x = _NX + 0.5f;\n                    if (x < 0.5)     x = 0.5f;\n                    \n                    i0 = (int) x;\n                    i1 = i0 + 1;\n                    \n                    if (y > _NY + 0.5) y = _NY + 0.5f;\n                    if (y < 0.5)     y = 0.5f;\n                    \n                    j0 = (int) y;\n                    j1 = j0 + 1;\n                    \n                    s1 = x - i0;\n                    s0 = 1 - s1;\n                    t1 = y - j0;\n                    t0 = 1 - t1;\n                    \n                    uv[index].x = s0 * (t0 * duv[FLUID_IX(i0, j0)].x + t1 * duv[FLUID_IX(i0, j1)].x)\n                    + s1 * (t0 * duv[FLUID_IX(i1, j0)].x + t1 * duv[FLUID_IX(i1, j1)].x);\n                    uv[index].y = s0 * (t0 * duv[FLUID_IX(i0, j0)].y + t1 * duv[FLUID_IX(i0, j1)].y)\n                    + s1 * (t0 * duv[FLUID_IX(i1, j0)].y + t1 * duv[FLUID_IX(i1, j1)].y);\n                    \n                }\n            }\n            setBoundary2d(1, uv);\n            setBoundary2d(2, uv);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::advectRGB(int bound, const Vec2f* duv) {\n            int i0, j0;\n            float x, y, s0, t0, s1, t1, dt0x, dt0y;\n            int\tindex;\n            \n            dt0x = deltaT * _NX;\n            dt0y = deltaT * _NY;\n            \n            for (int j = _NY; j > 0; --j)\n            {\n                for (int i = _NX; i > 0; --i)\n                {\n                    index = FLUID_IX(i, j);\n                    x = i - dt0x * duv[index].x;\n                    y = j - dt0y * duv[index].y;\n                    \n                    if (x > _NX + 0.5) x = _NX + 0.5f;\n                    if (x < 0.5)     x = 0.5f;\n                    \n                    i0 = (int) x;\n                    \n                    if (y > _NY + 0.5) y = _NY + 0.5f;\n                    if (y < 0.5)     y = 0.5f;\n                    \n                    j0 = (int) y;\n                    \n                    s1 = x - i0;\n                    s0 = 1 - s1;\n                    t1 = y - j0;\n                    t0 = 1 - t1;\n                    \n                    i0 = FLUID_IX(i0, j0);\t//we don't need col/row index any more but index in 1 dimension\n                    j0 = i0 + (_NX + 2);\n                    color[index] = (colorOld[i0] * t0 + colorOld[j0] * t1) * s0 + (colorOld[i0+1] * t0 + colorOld[j0+1] * t1) * s1;\n                }\n            }\n            setBoundaryRGB();\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::diffuse(int bound, float* c, float* c0, float diff)\n        {\n            float a = deltaT * diff * _NX * _NY;\t//todo find the exact strategy for using _NX and _NY in the factors\n            linearSolver(bound, c, c0, a, 1.0 + 4 * a);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::diffuseRGB(int bound, float diff)\n        {\n            float a = deltaT * diff * _NX * _NY;\n            linearSolverRGB(a, 1.0 + 4 * a);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::diffuseUV(float diff)\n        {\n            float a = deltaT * diff * _NX * _NY;\n            linearSolverUV(a, 1.0 + 4 * a);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::project(Vec2f* xy, Vec2f* pDiv)\n        {\n            float\th;\n            int\t\tindex;\n            int\t\tstep_x = _NX + 2;\n            \n            h = - 0.5f / _NX;\n            for (int j = _NY; j > 0; --j)\n            {\n                index = FLUID_IX(_NX, j);\n                for (int i = _NX; i > 0; --i)\n                {\n                    pDiv[index].x = h * (xy[index+1].x - xy[index-1].x + xy[index+step_x].y - xy[index-step_x].y);\n                    pDiv[index].y = 0;\n                    --index;\n                }\n            }\n            \n            setBoundary02d(reinterpret_cast<Vec2f*>(&pDiv[0].x));\n            setBoundary02d(reinterpret_cast<Vec2f*>(&pDiv[0].y));\n            \n            linearSolverProject(pDiv);\n            \n            float fx = 0.5f * _NX;\n            float fy = 0.5f * _NY;\t//maa\tchange it from _NX to _NY\n            for (int j = _NY; j > 0; --j)\n            {\n                index = FLUID_IX(_NX, j);\n                for (int i = _NX; i > 0; --i)\n                {\n                    xy[index].x -= fx * (pDiv[index+1].x - pDiv[index-1].x);\n                    xy[index].y -= fy * (pDiv[index+step_x].x - pDiv[index-step_x].x);\n                    --index;\n                }\n            }\n            \n            setBoundary2d(1, xy);\n            setBoundary2d(2, xy);\n        }\n        \n        \n        //--------------------------------------------------------------\n        //\tGauss-Seidel relaxation\n        void Solver::linearSolver(int bound, float* __restrict x, const float* __restrict x0, float a, float c)\n        {\n            int\tstep_x = _NX + 2;\n            int index;\n            c = 1. / c;\n            for (int k = solverIterations; k > 0; --k)\t// MEMO\n            {\n                for (int j = _NY; j > 0 ; --j)\n                {\n                    index = FLUID_IX(_NX, j);\n                    for (int i = _NX; i > 0 ; --i)\n                    {\n                        x[index] = ((x[index-1] + x[index+1] + x[index - step_x] + x[index + step_x]) * a + x0[index]) * c;\n                        --index;\n                    }\n                }\n                setBoundary(bound, x);\n            }\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::linearSolverProject(Vec2f* __restrict pdiv)\n        {\n            int\tstep_x = _NX + 2;\n            int index;\n            for (int k = solverIterations; k > 0; --k) {\n                for (int j = _NY; j > 0 ; --j) {\n                    index = FLUID_IX(_NX, j);\n                    float prev = pdiv[index+1].x;\n                    for (int i = _NX; i > 0 ; --i)\n                    {\n                        prev = (pdiv[index-1].x + prev + pdiv[index - step_x].x + pdiv[index + step_x].x + pdiv[index].y) * .25;\n                        pdiv[index].x = prev;\n                        --index;\n                    }\n                }\n                setBoundary02d(reinterpret_cast<Vec2f*>(&pdiv[0].x));\n            }\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::linearSolverRGB(float a, float c)\n        {\n            int index3, index4, index;\n            int\tstep_x = _NX + 2;\n            c = 1. / c;\n            for (int k = solverIterations; k > 0; --k)\t// MEMO\n            {           \n                for (int j = _NY; j > 0 ; --j)\n                {\n                    index = FLUID_IX(_NX, j);\n                    //index1 = index - 1;\t\t//FLUID_IX(i-1, j);\n                    //index2 = index + 1;\t\t//FLUID_IX(i+1, j);\n                    index3 = index - step_x;\t//FLUID_IX(i, j-1);\n                    index4 = index + step_x;\t//FLUID_IX(i, j+1);\n                    for (int i = _NX; i > 0 ; --i)\n                    {\t\n                        color[index] = ((color[index-1] + color[index+1]  +  color[index3] + color[index4]) * a  +  colorOld[index]) * c;                                \n                        --index;\n                        --index3;\n                        --index4;\n                    }\n                }\n                setBoundaryRGB();\t\n            }\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::linearSolverUV(float a, float c)\n        {\n            int index;\n            int\tstep_x = _NX + 2;\n            c = 1. / c;\n            Vec2f* __restrict localUV = uv;\n            const Vec2f* __restrict localOldUV = uvOld;\n            \n            for (int k = solverIterations; k > 0; --k)\t// MEMO\n            {           \n                for (int j = _NY; j > 0 ; --j)\n                {\n                    index = FLUID_IX(_NX, j);\n                    float prevU = localUV[index+1].x;\n                    float prevV = localUV[index+1].y;\n                    for (int i = _NX; i > 0 ; --i)\n                    {\n                        prevU = ((localUV[index-1].x + prevU + localUV[index - step_x].x + localUV[index + step_x].x) * a  + localOldUV[index].x) * c;\n                        prevV = ((localUV[index-1].y + prevV + localUV[index - step_x].y + localUV[index + step_x].y) * a  + localOldUV[index].y) * c;\n                        localUV[index].x = prevU;\n                        localUV[index].y = prevV;\n                        --index;\n                    }\n                }\n                setBoundary2d(1, uv);\n            }\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::setBoundary(int bound, float* x)\n        {\n            int dst1, dst2, src1, src2;\n            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);\n            \n            dst1 = FLUID_IX(0, 1);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(_NX+1, 1);\n            src2 = FLUID_IX(_NX, 1);\n            if(wrap_x)\n                SWAP(src1, src2);\n            if(bound == 1 && !wrap_x)\n                for (int i = _NY; i > 0; --i)\n                {\n                    x[dst1] = -x[src1];\tdst1 += step;\tsrc1 += step;\t\n                    x[dst2] = -x[src2];\tdst2 += step;\tsrc2 += step;\t\n                }\n            else\n                for (int i = _NY; i > 0; --i)\n                {\n                    x[dst1] = x[src1];\tdst1 += step;\tsrc1 += step;\t\n                    x[dst2] = x[src2];\tdst2 += step;\tsrc2 += step;\t\n                }\n            \n            dst1 = FLUID_IX(1, 0);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(1, _NY+1);\n            src2 = FLUID_IX(1, _NY);\n            if(wrap_y)\n                SWAP(src1, src2);\n            if(bound == 2 && !wrap_y)\n                for (int i = _NX; i > 0; --i)\n                {\n                    x[dst1++] = -x[src1++];\t\n                    x[dst2++] = -x[src2++];\t\n                }\n            else\n                for (int i = _NX; i > 0; --i)\n                {\n                    x[dst1++] = x[src1++];\n                    x[dst2++] = x[src2++];\t\n                }\n            \n            x[FLUID_IX(0,   0)] = 0.5f * (x[FLUID_IX(1, 0)] + x[FLUID_IX(0, 1)]);\n            x[FLUID_IX(0, _NY+1)] = 0.5f * (x[FLUID_IX(1, _NY+1)] + x[FLUID_IX(0, _NY)]);\n            x[FLUID_IX(_NX+1,   0)] = 0.5f * (x[FLUID_IX(_NX, 0)] + x[FLUID_IX(_NX+1, 1)]);\n            x[FLUID_IX(_NX+1, _NY+1)] = 0.5f * (x[FLUID_IX(_NX, _NY+1)] + x[FLUID_IX(_NX+1, _NY)]);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::setBoundary02d(Vec2f* x)\n        {\n            int dst1, dst2, src1, src2;\n            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);\n            \n            dst1 = FLUID_IX(0, 1);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(_NX+1, 1);\n            src2 = FLUID_IX(_NX, 1);\n            if(wrap_x)\n                SWAP(src1, src2);\n            for (int i = _NY; i > 0; --i)\n            {\n                x[dst1].x = x[src1].x;\tdst1 += step;\tsrc1 += step;\t\n                x[dst2].x = x[src2].x;\tdst2 += step;\tsrc2 += step;\t\n            }\n            \n            dst1 = FLUID_IX(1, 0);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(1, _NY+1);\n            src2 = FLUID_IX(1, _NY);\n            if(wrap_y)\n                SWAP(src1, src2);\n            for (int i = _NX; i > 0; --i)\n            {\n                x[dst1++] = x[src1++];\n                x[dst2++] = x[src2++];\t\n            }\n            \n            x[FLUID_IX(0,   0)].x = 0.5f * (x[FLUID_IX(1, 0)].x + x[FLUID_IX(0, 1)].x);\n            x[FLUID_IX(0, _NY+1)].x = 0.5f * (x[FLUID_IX(1, _NY+1)].x + x[FLUID_IX(0, _NY)].x);\n            x[FLUID_IX(_NX+1,   0)].x = 0.5f * (x[FLUID_IX(_NX, 0)].x + x[FLUID_IX(_NX+1, 1)].x);\n            x[FLUID_IX(_NX+1, _NY+1)].x = 0.5f * (x[FLUID_IX(_NX, _NY+1)].x + x[FLUID_IX(_NX+1, _NY)].x);\n        }\n        \n        //--------------------------------------------------------------\n        void Solver::setBoundary2d(int bound, Vec2f *xy)\n        {\n            int dst1, dst2, src1, src2;\n            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);\n            \n            dst1 = FLUID_IX(0, 1);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(_NX+1, 1);\n            src2 = FLUID_IX(_NX, 1);\n            if(wrap_x)\n                SWAP(src1, src2);\n            if(bound == 1 && !wrap_x)\n                for (int i = _NY; i > 0; --i)\n                {\n                    xy[dst1].x = -xy[src1].x;\tdst1 += step;\tsrc1 += step;\t\n                    xy[dst2].x = -xy[src2].x;\tdst2 += step;\tsrc2 += step;\t\n                }\n            else\n                for (int i = _NY; i > 0; --i)\n                {\n                    xy[dst1].x = xy[src1].x;\tdst1 += step;\tsrc1 += step;\t\n                    xy[dst2].x = xy[src2].x;\tdst2 += step;\tsrc2 += step;\t\n                }\n            \n            dst1 = FLUID_IX(1, 0);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(1, _NY+1);\n            src2 = FLUID_IX(1, _NY);\n            if(wrap_y)\n                SWAP(src1, src2);\n            if(bound == 2 && !wrap_y)\n                for (int i = _NX; i > 0; --i)\n                {\n                    xy[dst1++].y = -xy[src1++].y;\t\n                    xy[dst2++].y = -xy[src2++].y;\t\n                }\n            else\n                for (int i = _NX; i > 0; --i)\n                {\n                    xy[dst1++].y = xy[src1++].y;\n                    xy[dst2++].y = xy[src2++].y;\t\n                }\n            \n            xy[FLUID_IX(0,   0)][bound-1] = 0.5f * (xy[FLUID_IX(1, 0)][bound-1] + xy[FLUID_IX(0, 1)][bound-1]);\n            xy[FLUID_IX(0, _NY+1)][bound-1] = 0.5f * (xy[FLUID_IX(1, _NY+1)][bound-1] + xy[FLUID_IX(0, _NY)][bound-1]);\n            xy[FLUID_IX(_NX+1,   0)][bound-1] = 0.5f * (xy[FLUID_IX(_NX, 0)][bound-1] + xy[FLUID_IX(_NX+1, 1)][bound-1]);\n            xy[FLUID_IX(_NX+1, _NY+1)][bound-1] = 0.5f * (xy[FLUID_IX(_NX, _NY+1)][bound-1] + xy[FLUID_IX(_NX+1, _NY)][bound-1]);\n        }\n        \n        //#define CPY_RGB(d, s)\t\t{\tr[d] = r[s];\tg[d] = g[s];\tb[d] = b[s]; }\n        //#define CPY_RGB_NEG(d, s)\t{\tr[d] = -r[s];\tg[d] = -g[s];\tb[d] = -b[s]; }\n        \n        //--------------------------------------------------------------\n        void Solver::setBoundaryRGB()\n        {\n            int dst1, dst2, src1, src2;\n            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);\n            \n            dst1 = FLUID_IX(0, 1);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(_NX+1, 1);\n            src2 = FLUID_IX(_NX, 1);\n            if(wrap_x)\n                SWAP(src1, src2);\n            for (int i = _NY; i > 0; --i)\n            {\n                color[dst1] = color[src1];\n                dst1 += step;\n                src1 += step;\t\n                \n                color[dst2] = color[src2];\n                dst2 += step;\n                src2 += step;\t\n            }\n            \n            dst1 = FLUID_IX(1, 0);\n            src1 = FLUID_IX(1, 1);\n            dst2 = FLUID_IX(1, _NY+1);\n            src2 = FLUID_IX(1, _NY);\n            if(wrap_y)\n                SWAP(src1, src2);\n            for (int i = _NX; i > 0; --i)\n            {\n                color[dst1] = color[src1];\n                ++dst1;\n                ++src1;\t\n                \n                color[dst2] = color[src2];\n                ++dst2;\n                ++src2;\t\n            }\n\t\t}\n\t\t\n        \n        //--------------------------------------------------------------\n        void Solver::randomizeColor() {\n            for (int i = getWidth()-1; i > 0; --i)\n            {\n                for (int j = getHeight()-1; j > 0; --j)\n                {\n                    int index = FLUID_IX(i, j);\n                    color[index] = Vec3f(Rand::randFloat(), Rand::randFloat(), Rand::randFloat());\n                    density[index] = Rand::randFloat();\n                }\n            }\n        }\n        \n    }\n}\n"
  },
  {
    "path": "src/MSAFluidSolver.h",
    "content": "/***********************************************************************\n \n This class is for the actual solver (doesn't draw anything)\n \n ************************************************************************/\n\n#pragma once\n\n#include \"MSACore.h\"\n\nnamespace msa {\n\tnamespace fluid {\n        \n        // do not change these values, you can override them using the solver methods\n#define\t\tFLUID_DEFAULT_NX\t\t\t\t\t100\n#define\t\tFLUID_DEFAULT_NY\t\t\t\t\t100\n#define     FLUID_DEFAULT_DT\t\t\t\t\t0.04f\t//Maa\t25fps\n#define\t\tFLUID_DEFAULT_VISC\t\t\t\t\t0.0001f\n#define     FLUID_DEFAULT_COLOR_DIFFUSION\t\t0.0f\n#define     FLUID_DEFAULT_FADESPEED\t\t\t\t0.03f\n#define\t\tFLUID_DEFAULT_SOLVER_ITERATIONS\t\t10\n        \n#define\t\tFLUID_IX(i, j)\t\t((i) + (_NX + 2)  *(j))\n        \n        class Solver {\n        public:\n            Solver();\n            virtual ~Solver();\n            \n            Solver& setup(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);\n            Solver& setSize(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);\n            \n            // solve one step of the fluid solver\n            void update();\n            \n            // clear all forces in fluid and reset\n            void reset();\n            \n            // get fluid cell index for cell coordinates or normalized position\n            inline int getIndexForCell(int i, int j) const;\n            inline int getIndexForPos(const Vec2f &pos) const;\n            \n            \n            // get color and/or vel at any point in the fluid.\n            // pass pointers to Vec2f (for velocity) and Color (for color) and they get filled with the info\n            // leave any pointer NULL if you don't want that info\n            inline void getInfoAtIndex(int index, Vec2f *vel, Color *color = NULL) const;\n            inline void getInfoAtCell(int i, int j, Vec2f *vel, Color *color = NULL) const;\n            inline void getInfoAtPos(const Vec2f &pos, Vec2f *vel, Color *color = NULL) const;\n            \n            \n            // get just velocity\n            inline Vec2f getVelocityAtIndex(int index) const;\n            inline Vec2f getVelocityAtCell(int i, int j) const;\n            inline Vec2f getVelocityAtPos(const Vec2f &pos) const;\n            \n            \n            // get just color\n            inline Color getColorAtIndex(int index) const;\n            inline Color getColorAtCell(int i, int j) const;\n            inline Color getColorAtPos(const Vec2f &pos) const;\n            \n            \n            // add force (at cell index, cell coordinates, or normalized position)\n            inline void addForceAtIndex(int index, const Vec2f &force);\n            inline void addForceAtCell(int i, int j, const Vec2f &force);\n            inline void addForceAtPos(const Vec2f &pos, const Vec2f &force);\n            \n            \n            // add color (at cell index, cell coordinates, or normalized position)\n            inline void addColorAtIndex(int index, const Color &color);\n            inline void addColorAtCell(int i, int j, const Color &color);\n            inline void addColorAtPos(const Vec2f &pos, const Color &color);\n            \n            \n            // fill with random color at every cell\n            void randomizeColor();\n            \n            // return number of cells and dimensions\n            int getNumCells() const;\n            int getWidth() const;\n            int getHeight() const;\n            float getInvWidth() const;\n            float getInvHeight() const;\n            Vec2f getSize();\n            Vec2f getInvSize();\n            \n            bool isInited() const;\n            \n            // accessors for  viscocity, it will lerp to the target at lerpspeed\n            Solver& setVisc(float newVisc);\n            float getVisc() const;\n            \n            // accessors for  color diffusion\n            // if diff == 0, color diffusion is not performed\n            // ** COLOR DIFFUSION IS SLOW!\n            Solver& setColorDiffusion(float diff);\n            float\tgetColorDiffusion();\n            \n            Solver& enableRGB(bool isRGB);\n            Solver& setDeltaT(float deltaT = FLUID_DEFAULT_DT);\n            Solver& setFadeSpeed(float fadeSpeed = FLUID_DEFAULT_FADESPEED);\n            Solver& setSolverIterations(int solverIterations = FLUID_DEFAULT_SOLVER_ITERATIONS);\n            Solver& enableVorticityConfinement(bool b);\n            bool getVorticityConfinement();\n            Solver& setWrap(bool bx, bool by);\n            \n            // returns average density of fluid\n            float getAvgDensity() const;\n            \n            // returns average _uniformity\n            float getUniformity() const;\n            \n            // returns average speed of fluid\n            float getAvgSpeed() const;\n            \n            // allocate an array large enough to hold information for u, v, r, g, OR b\n            float* alloc()\t{ return new float[_numCells];\t}\n            \n            \n            float\t*density, *densityOld;\t\t// used if not RGB\n            Vec3f\t*color, *colorOld;\t\t\t// used for RGB\n            Vec2f\t*uv, *uvOld;\n            \n            float\t*curl;\n            \n            bool\tdoRGB;\t\t\t\t// for monochrome, update only density\n            bool\tdoVorticityConfinement;\n            int\t\tsolverIterations;\n            \n            float\tcolorDiffusion;\n            float\tviscocity;\n            float\tfadeSpeed;\n            float\tdeltaT;\n            bool\twrap_x;\n            bool\twrap_y;\n            \n        protected:\n            \n            float width;\n            float height;\n            float invWidth;\n            float invHeight;\n            \n            int\t\t_NX, _NY, _numCells;\n            float\t_invNX, _invNY, _invNumCells;\n            bool\t_isInited;\n            float\t*_tmp;\n            \n            float\t_avgDensity;\t\t\t// this will hold the average color of the last frame (how full it is)\n            float\t_uniformity;\t\t\t// this will hold the _uniformity of the last frame (how uniform the color is);\n            float\t_avgSpeed;\n            \n            void\tdestroy();\n            \n            inline\tfloat\tcalcCurl(int i, int j);\n            void\tvorticityConfinement(Vec2f *Fvc_xy);\n            \n            template<typename T>\n            void\taddSource(T *x, T *x0);\n            \n            void\tadvect(int b, float *d, const float *d0, const Vec2f *duv);\n            void\tadvect2d(Vec2f *uv, const Vec2f *duv);\n            void\tadvectRGB(int b, const Vec2f *duv);\n            \n            void\tdiffuse(int b, float *c, float *c0, float diff);\n            void\tdiffuseRGB(int b, float diff);\n            void\tdiffuseUV(float diff);\n            \n            void\tproject(Vec2f *xy, Vec2f *pDiv);\n            void\tlinearSolver(int b, float *x, const float *x0, float a, float c);\n            void\tlinearSolverProject(Vec2f *pdiv);\n            void\tlinearSolverRGB(float a, float c);\n            void\tlinearSolverUV(float a, float c);\n            \n            void\tsetBoundary(int b, float *x);\n            void\tsetBoundary02d(Vec2f* x);\n            void\tsetBoundary2d(int b, Vec2f *xy);\n            void\tsetBoundaryRGB();\n            \n            void\tfadeDensity();\n            void\tfadeRGB();\n        };\n        \n        \n        //-------- get index\n        inline int Solver::getIndexForCell(int i, int j) const {\n            i = clamp(i, 1, _NX);\n            j = clamp(j, 1, _NY);\n            return FLUID_IX(i, j);\n        }\n        \n        inline int Solver::getIndexForPos(const Vec2f &pos) const {\n            return getIndexForCell((int)floor(pos.x * width), (int)floor(pos.y * height));\n        }\n        \n        \n        \n        //-------- get info\n        inline\tvoid Solver::getInfoAtIndex(int index, Vec2f *vel, Color *color) const {\n            if(vel) *vel = getVelocityAtIndex(index);\n            if(color) *color = getColorAtIndex(index);\n        }\n        \n        inline void Solver::getInfoAtCell(int i, int j, Vec2f *vel, Color *color) const {\n            getInfoAtIndex(getIndexForCell(i, j), vel, color);\n        }\n        \n        \n        inline void Solver::getInfoAtPos(const Vec2f &pos, Vec2f *vel, Color *color) const {\n            getInfoAtIndex(getIndexForPos(pos), vel, color);\n        }\n        \n        \n        //-------- get velocity\n        inline Vec2f Solver::getVelocityAtIndex(int index) const {\n            return uv[index];\n        }\n        \n        inline Vec2f Solver::getVelocityAtCell(int i, int j) const {\n            return getVelocityAtIndex(getIndexForCell(i, j));\n        }\n        \n        inline Vec2f Solver::getVelocityAtPos(const Vec2f &pos) const {\n            return getVelocityAtIndex(getIndexForPos(pos));\n        }\n        \n        \n        //-------- get color\n        inline Color Solver::getColorAtIndex(int index) const {\n            if(doRGB) {\n                return Color(this->color[index].x, this->color[index].y, this->color[index].z);\n            } else {\n                return Color(density[index], density[index], density[index]);\n            }\n        }\n        \n        inline Color Solver::getColorAtCell(int i, int j) const {\n            return getColorAtIndex(getIndexForCell(i, j));\n        }\n        \n        inline Color Solver::getColorAtPos(const Vec2f &pos) const {\n            return getColorAtIndex(getIndexForPos(pos));\n        }\n        \n        \n        //-------- add force\n        inline void Solver::addForceAtIndex(int index, const Vec2f &force) {\n            uv[index] += force;\n        }\n        \n        inline void Solver::addForceAtCell(int i, int j, const Vec2f &force) {\n            addForceAtIndex(getIndexForCell(i, j), force);\n        }\n        \n        inline void Solver::addForceAtPos(const Vec2f &pos, const Vec2f &force) {\n            addForceAtIndex(getIndexForPos(pos), force);\n        }\n        \n        \n        //-------- add color\n        inline void Solver::addColorAtIndex(int index, const Color &color) {\n            if(doRGB) {\n                colorOld[index] += Vec3f(color.r, color.g, color.b);\n            } else {\n                density[index] += color.r;\n            }\n        }\n        \n        inline void Solver::addColorAtCell(int i, int j, const Color &color) {\n            addColorAtIndex(getIndexForCell(i, j), color);\n        }\n        \n        inline void Solver::addColorAtPos(const Vec2f &pos, const Color &color) {\n            addColorAtIndex(getIndexForPos(pos), color);\n        }\n        \n        template<typename T>\n        void Solver::addSource(T *x, T *x0) {\n            for(int i = _numCells-1; i >=0; --i) {\n                x[i] += x0[i] * deltaT;\n            }\n        }\n    }\n}"
  }
]