Full Code of memo/ofxMSAFluid for AI

master b42412365279 cached
25 files
114.6 KB
29.9k tokens
30 symbols
1 requests
Download .txt
Repository: memo/ofxMSAFluid
Branch: master
Commit: b42412365279
Files: 25
Total size: 114.6 KB

Directory structure:
gitextract_0z8_2c1k/

├── .gitignore
├── README.md
├── addon_config.mk
├── example/
│   ├── Makefile
│   ├── addons.make
│   ├── config.make
│   ├── example.qbs
│   ├── example.sln
│   ├── example.vcxproj
│   └── src/
│       ├── Particle.cpp
│       ├── Particle.h
│       ├── ParticleSystem.cpp
│       ├── ParticleSystem.h
│       ├── main.cpp
│       ├── testApp.cpp
│       └── testApp.h
├── license.md
└── src/
    ├── MSAFluid.h
    ├── MSAFluidDrawerBase.cpp
    ├── MSAFluidDrawerBase.h
    ├── MSAFluidDrawerGl-Cinder.h
    ├── MSAFluidDrawerGl-OF.h
    ├── MSAFluidParticleUpdater.h
    ├── MSAFluidSolver.cpp
    └── MSAFluidSolver.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
#########################
# openFrameworks patterns
#########################

# build files
openFrameworks.a
openFrameworksDebug.a
openFrameworksUniversal.a
libs/openFrameworksCompiled/lib/*/*
!libs/openFrameworksCompiled/lib/*/.gitkeep

# apothecary
scripts/apothecary

# rule to avoid non-official addons going into git
# see addons/.gitignore
addons/*

# rule to avoid non-official apps going into git
# see apps/.gitignore
apps/*

# rule to ignore compiled / downloaded libs
/libs/*
!/libs/openFrameworks
!/libs/openFrameworksCompiled

# also, see examples/.gitignore

#########################
# general
#########################

[Bb]uild/
[Oo]bj/
*.o
examples/**/[Dd]ebug*/
examples/**/[Rr]elease*/
examples/**/gcc-debug/
examples/**/gcc-release/
tests/**/[Dd]ebug*/
tests/**/[Rr]elease*/
tests/**/gcc-debug/
tests/**/gcc-release/
*.mode*
*.app/
*.pyc
.svn/
*.log
*.cpp.eep
*.cpp.elf
*.cpp.hex

#########################
# IDE
#########################

# XCode
*.pbxuser
*.perspective
*.perspectivev3
*.mode1v3
*.mode2v3
# XCode 4
xcuserdata
*.xcworkspace

# Code::Blocks
*.depend
*.layout

# Visual Studio
*.sdf
*.opensdf
*.suo
*.pdb
*.ilk
*.aps
ipch/
**/.vs/*

# Eclipse
.metadata
local.properties
.externalToolBuilders

# Android Studio
.idea
.gradle
gradle
gradlew
gradlew.bat

# QtCreator
*.qbs.user
*.pro.user
*.pri


#########################
# operating system
#########################

# Linux
*~
# KDE
.directory
.AppleDouble

# OSX
.DS_Store
*.swp
*~.nib
# Thumbnails
._*
examples/ios/**/mediaAssets

# Windows
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini

# Android
.csettings
/libs/openFrameworksCompiled/project/android/paths.make

# Android Studio
*.iml

#########################
# miscellaneous
#########################

.mailmap
/apps*/

#########################
# core examples
#########################

bin/*
!bin/data/

**/bin/*
!**/bin/data/

#########################
# IDE
#########################

# XCode
*.xcodeproj
Project.xcconfig
openFrameworks-Info.plist
ofxiOS-Info.plist
ofxiOS_Prefix.pch
*/*/Default*.png
*/*/Icon*.png

# Code::Blocks
# *.cbp
# *.workspace

# Visual Studio
# *.sln
# *.vcxproj
*.vcxproj.user
*.vcxproj.filters
icon.rc

# Eclipse
.cproject
.project
.settings/

# QtCreator
# *.qbs
*.qbs.user*
*.pro
*.pro.user
qtc_Desktop_*

#########################
# operating system
#########################

# Linux
# Makefile
# config.make
# Leave Android files in until project generation works
!/android/*/Makefile
!/android/*/config.make

# Android
android/*/test link
android/*/gen
android/*/res/raw
libOFAndroidApp*.so
gdbserver
gdb.setup
libneondetection.so
Application.mk
Android.mk

!android/*/.cproject
!android/*/.project
!android/*/.settings
!android/*/.settings/*


================================================
FILE: README.md
================================================
ofxMSAFluid
=====================================

Introduction
------------
C++ 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)

Demo at [www.memo.tv/msafluid/](http://www.memo.tv/msafluid)

Other useful resources and implementations I looked at while building this library:  

- Mike Ash (C), http://mikeash.com/?page=pyblog/fluid-simulation-for-dummies.html
- Alexander McKenzie (Java), http://www.multires.caltech.edu/teaching/demos/java/stablefluids.htm
- Pierluigi Pesenti (AS3 port of Alexander's), http://blog.oaxoa.com/2008/01/21/actionscript-3-fluids-simulation/
- Gustav Taxen (C), http://www.nada.kth.se/~gustavt/fluids/
- Dave Wallin (C++), http://nuigroup.com/touchlib/ (uses portions from Gustav's)

Licence
-------
The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license).  
Copyright (c) 2008-2012 Memo Akten, [www.memo.tv](http://www.memo.tv)  
The Mega Super Awesome Visuals Company


Installation
------------
Copy to your openFrameworks/addons folder.

Dependencies
------------
- MSACore

Compatibility
------------
openFrameworks 0072  
I 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.


Known issues
------------
Probably will not work with Cinder without some (minor) changes

Version history
------------
### v2.1    23/09/2012
- compatible with OF0072
- renamed (uppercase) MSA namespace to (lowercase) msa. (kept MSA as an alias for backwards compatibility)
- all classes are now inside a new namespace 'msa::fluid::'

### v2.0
- move to centralized MSALibs (requires MSACore)
- everything is msa:: namespace
- u[] and v[] condensed to (Vec2f uv[])
- r[], g[], b[] condensed to (Vec3f color[])
- unified API for getting and setting info:
   - all vel & colors set and get with the structs
   - all getters and setters have 3 functions, index, (i, j), Vec2f pos

### v1.2	02/05/2009
- unified API with processing.org version
- solver u, v, r, g, b arrays now public
- drawer can incDrawMode and decDrawMode
- loads of optimizations by Maa (http://www.lagraine.com/ - new content coming soon)

### v1.1	07/04/2009
- changed license to revised BSD (a lot more more permissive than GPL)

### v1.0
- added RGB or monochrome functionality (enableRGB())
- vector drawing implemented
- get and set info much improved
- added draw mode system
- setup() now only takes dimensions, other parameters have their own setters

### v0.9	04/12/08
- initial version





================================================
FILE: addon_config.mk
================================================
meta:
	ADDON_NAME = ofxMSAFluid
	ADDON_DESCRIPTION = C++ openFrameworks addon for Stam style Fluid Solver
	ADDON_AUTHOR = Memo Akten, www.memo.tv
	ADDON_TAGS = "Fluid"
	ADDON_URL = https://github.com/memo/ofxMSAFluid

common:
	# dependencies with other addons, a list of them separated by spaces
	# or use += in several lines
	ADDON_DEPENDENCIES = ofxMSACore


================================================
FILE: example/Makefile
================================================
# Attempt to load a config.make file.
# If none is found, project defaults in config.project.make will be used.
ifneq ($(wildcard config.make),)
	include config.make
endif

# make sure the the OF_ROOT location is defined
ifndef OF_ROOT
	OF_ROOT=$(realpath ../../..)
endif

# call the project makefile!
include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk


================================================
FILE: example/addons.make
================================================
ofxMSACore
ofxMSAFluid
ofxMSAInteractiveObject
ofxSimpleGuiToo
ofxXmlSettings


================================================
FILE: example/config.make
================================================
################################################################################
# CONFIGURE PROJECT MAKEFILE (optional)
#   This file is where we make project specific configurations.
################################################################################

################################################################################
# OF ROOT
#   The location of your root openFrameworks installation
#       (default) OF_ROOT = ../../.. 
################################################################################
# OF_ROOT = ../../..

################################################################################
# PROJECT ROOT
#   The location of the project - a starting place for searching for files
#       (default) PROJECT_ROOT = . (this directory)
#    
################################################################################
# PROJECT_ROOT = .

################################################################################
# PROJECT SPECIFIC CHECKS
#   This is a project defined section to create internal makefile flags to 
#   conditionally enable or disable the addition of various features within 
#   this makefile.  For instance, if you want to make changes based on whether
#   GTK is installed, one might test that here and create a variable to check. 
################################################################################
# None

################################################################################
# PROJECT EXTERNAL SOURCE PATHS
#   These are fully qualified paths that are not within the PROJECT_ROOT folder.
#   Like source folders in the PROJECT_ROOT, these paths are subject to 
#   exlclusion via the PROJECT_EXLCUSIONS list.
#
#     (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank) 
#
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXTERNAL_SOURCE_PATHS = 

################################################################################
# PROJECT EXCLUSIONS
#   These makefiles assume that all folders in your current project directory 
#   and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
#   to look for source code. The any folders or files that match any of the 
#   items in the PROJECT_EXCLUSIONS list below will be ignored.
#
#   Each item in the PROJECT_EXCLUSIONS list will be treated as a complete 
#   string unless teh user adds a wildcard (%) operator to match subdirectories.
#   GNU make only allows one wildcard for matching.  The second wildcard (%) is
#   treated literally.
#
#      (default) PROJECT_EXCLUSIONS = (blank)
#
#		Will automatically exclude the following:
#
#			$(PROJECT_ROOT)/bin%
#			$(PROJECT_ROOT)/obj%
#			$(PROJECT_ROOT)/%.xcodeproj
#
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXCLUSIONS =

################################################################################
# PROJECT LINKER FLAGS
#	These flags will be sent to the linker when compiling the executable.
#
#		(default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
#
#   Note: Leave a leading space when adding list items with the += operator
#
# Currently, shared libraries that are needed are copied to the 
# $(PROJECT_ROOT)/bin/libs directory.  The following LDFLAGS tell the linker to
# add a runtime path to search for those shared libraries, since they aren't 
# incorporated directly into the final executable application binary.
################################################################################
# PROJECT_LDFLAGS=-Wl,-rpath=./libs

################################################################################
# PROJECT DEFINES
#   Create a space-delimited list of DEFINES. The list will be converted into 
#   CFLAGS with the "-D" flag later in the makefile.
#
#		(default) PROJECT_DEFINES = (blank)
#
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_DEFINES = 

################################################################################
# PROJECT CFLAGS
#   This is a list of fully qualified CFLAGS required when compiling for this 
#   project.  These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS 
#   defined in your platform specific core configuration files. These flags are
#   presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below. 
#
#		(default) PROJECT_CFLAGS = (blank)
#
#   Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in 
#   your platform specific configuration file will be applied by default and 
#   further flags here may not be needed.
#
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CFLAGS = 

################################################################################
# PROJECT OPTIMIZATION CFLAGS
#   These are lists of CFLAGS that are target-specific.  While any flags could 
#   be conditionally added, they are usually limited to optimization flags. 
#   These flags are added BEFORE the PROJECT_CFLAGS.
#
#   PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
#
#		(default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
#
#   PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
#
#		(default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
#
#   Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the 
#   PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration 
#   file will be applied by default and further optimization flags here may not 
#   be needed.
#
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_OPTIMIZATION_CFLAGS_RELEASE = 
# PROJECT_OPTIMIZATION_CFLAGS_DEBUG = 

################################################################################
# PROJECT COMPILERS
#   Custom compilers can be set for CC and CXX
#		(default) PROJECT_CXX = (blank)
#		(default) PROJECT_CC = (blank)
#   Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CXX = 
# PROJECT_CC = 


================================================
FILE: example/example.qbs
================================================
import qbs
import qbs.Process
import qbs.File
import qbs.FileInfo
import qbs.TextFile
import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp

Project{
    property string of_root: '../../..'

    ofApp {
        name: { return FileInfo.baseName(sourceDirectory) }

        files: [
            'src/*',
        ]

        of.addons: [
            'ofxMSAFluid',
            'ofxSimpleGuiToo'
        ]

        // additional flags for the project. the of module sets some
        // flags by default to add the core libraries, search paths...
        // this flags can be augmented through the following properties:
        of.pkgConfigs: []       // list of additional system pkgs to include
        of.includePaths: []     // include search paths
        of.cFlags: []           // flags passed to the c compiler
        of.cxxFlags: []         // flags passed to the c++ compiler
        of.linkerFlags: []      // flags passed to the linker
        of.defines: []          // defines are passed as -D to the compiler
        // and can be checked with #ifdef or #if in the code
        of.frameworks: []       // osx only, additional frameworks to link with the project
        of.staticLibraries: []  // static libraries
        of.dynamicLibraries: [] // dynamic libraries

        // create a console window when the application start
        consoleApplication: true

        // other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html
        // eg: this will enable ccache when compiling
        //
        // cpp.compilerWrapper: 'ccache'

        Depends{
            name: "cpp"
        }

        // common rules that parse the include search paths, core libraries...
        Depends{
            name: "of"
        }

        // dependency with the OF library
        Depends{
            name: "openFrameworks"
        }
    }

    property bool makeOF: true  // use makfiles to compile the OF library
    // will compile OF only once for all your projects
    // otherwise compiled per project with qbs

    property bool precompileOfMain: false  // precompile ofMain.h
    // faster to recompile when including ofMain.h
    // but might use a lot of space per project

    references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")]
}


================================================
FILE: example/example.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Win32 = Debug|Win32
		Debug|x64 = Debug|x64
		Release|Win32 = Release|Win32
		Release|x64 = Release|x64
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64
		{7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64
		{5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal


================================================
FILE: example/example.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Condition="'$(WindowsTargetPlatformVersion)'==''">
    <LatestTargetPlatformVersion>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))</LatestTargetPlatformVersion>
    <WindowsTargetPlatformVersion Condition="'$(WindowsTargetPlatformVersion)' == ''">$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
    <TargetPlatformVersion>$(WindowsTargetPlatformVersion)</TargetPlatformVersion>
  </PropertyGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{7FD42DF7-442E-479A-BA76-D0022F99702A}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>example</RootNamespace>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <PlatformToolset>v141</PlatformToolset>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    <Import Project="..\..\..\libs\openFrameworksCompiled\project\vs\openFrameworksRelease.props" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    <Import Project="..\..\..\libs\openFrameworksCompiled\project\vs\openFrameworksRelease.props" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    <Import Project="..\..\..\libs\openFrameworksCompiled\project\vs\openFrameworksDebug.props" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
    <Import Project="..\..\..\libs\openFrameworksCompiled\project\vs\openFrameworksDebug.props" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <OutDir>bin\</OutDir>
    <IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
    <TargetName>$(ProjectName)_debug</TargetName>
    <LinkIncremental>true</LinkIncremental>
    <GenerateManifest>true</GenerateManifest>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <OutDir>bin\</OutDir>
    <IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
    <TargetName>$(ProjectName)_debug</TargetName>
    <LinkIncremental>true</LinkIncremental>
    <GenerateManifest>true</GenerateManifest>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <OutDir>bin\</OutDir>
    <IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <OutDir>bin\</OutDir>
    <IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <WarningLevel>Level3</WarningLevel>
      <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>
      <CompileAs>CompileAsCpp</CompileAs>
      <ObjectFileName>$(IntDir)</ObjectFileName>
    </ClCompile>
    <Link>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Console</SubSystem>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
    <PostBuildEvent />
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <WarningLevel>Level3</WarningLevel>
      <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>
      <CompileAs>CompileAsCpp</CompileAs>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <ObjectFileName>$(IntDir)</ObjectFileName>
    </ClCompile>
    <Link>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Console</SubSystem>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
    <PostBuildEvent />
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WholeProgramOptimization>false</WholeProgramOptimization>
      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <WarningLevel>Level3</WarningLevel>
      <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>
      <CompileAs>CompileAsCpp</CompileAs>
      <MultiProcessorCompilation>true</MultiProcessorCompilation>
      <ObjectFileName>$(IntDir)</ObjectFileName>
    </ClCompile>
    <Link>
      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <SubSystem>Console</SubSystem>
      <OptimizeReferences>true</OptimizeReferences>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
    <PostBuildEvent />
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WholeProgramOptimization>false</WholeProgramOptimization>
      <PreprocessorDefinitions>MSA_HOST_OPENFRAMEWORKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <WarningLevel>Level3</WarningLevel>
      <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>
      <CompileAs>CompileAsCpp</CompileAs>
      <ObjectFileName>$(IntDir)</ObjectFileName>
    </ClCompile>
    <Link>
      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <SubSystem>Console</SubSystem>
      <OptimizeReferences>true</OptimizeReferences>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <RandomizedBaseAddress>false</RandomizedBaseAddress>
      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
    </Link>
    <PostBuildEvent />
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="src\main.cpp" />
    <ClCompile Include="src\Particle.cpp" />
    <ClCompile Include="src\ParticleSystem.cpp" />
    <ClCompile Include="src\testApp.cpp" />
    <ClCompile Include="..\..\..\addons\ofxMSACore\src\MSACoreGL.cpp" />
    <ClCompile Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidDrawerBase.cpp" />
    <ClCompile Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidSolver.cpp" />
    <ClCompile Include="..\..\..\addons\ofxMSAInteractiveObject\src\ofxMSAInteractiveObject.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiButton.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiColorPicker.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiComboBox.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiContent.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiFPSCounter.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiMovieSlider.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiQuadWarp.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiSlider2d.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiTitle.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiToggle.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiConfig.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiControl.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiPage.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiToo.cpp" />
    <ClCompile Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiValueControl.cpp" />
    <ClCompile Include="..\..\..\addons\ofxXmlSettings\src\ofxXmlSettings.cpp" />
    <ClCompile Include="..\..\..\addons\ofxXmlSettings\libs\tinyxml.cpp" />
    <ClCompile Include="..\..\..\addons\ofxXmlSettings\libs\tinyxmlerror.cpp" />
    <ClCompile Include="..\..\..\addons\ofxXmlSettings\libs\tinyxmlparser.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="src\Particle.h" />
    <ClInclude Include="src\ParticleSystem.h" />
    <ClInclude Include="src\testApp.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACore-Cinder.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACore-OF.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACore.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACoreCommon.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACoreGL.h" />
    <ClInclude Include="..\..\..\addons\ofxMSACore\src\MSACoreMath.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluid.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidDrawerBase.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidDrawerGl-Cinder.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidDrawerGl-OF.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidParticleUpdater.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAFluid\src\MSAFluidSolver.h" />
    <ClInclude Include="..\..\..\addons\ofxMSAInteractiveObject\src\ofxMSAInteractiveObject.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiButton.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiColorPicker.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiComboBox.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiContent.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiFPSCounter.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiMovieSlider.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiQuadWarp.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiSlider2d.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiSliderBase.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiSliderFloat.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiSliderInt.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiTitle.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\Controls\ofxSimpleGuiToggle.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiConfig.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiControl.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiIncludes.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiPage.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiToo.h" />
    <ClInclude Include="..\..\..\addons\ofxSimpleGuiToo\src\ofxSimpleGuiValueControl.h" />
    <ClInclude Include="..\..\..\addons\ofxXmlSettings\src\ofxXmlSettings.h" />
    <ClInclude Include="..\..\..\addons\ofxXmlSettings\libs\tinyxml.h" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="$(OF_ROOT)\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj">
      <Project>{5837595d-aca9-485c-8e76-729040ce4b0b}</Project>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="icon.rc">
      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/D_DEBUG %(AdditionalOptions)</AdditionalOptions>
      <AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/D_DEBUG %(AdditionalOptions)</AdditionalOptions>
      <AdditionalIncludeDirectories>$(OF_ROOT)\libs\openFrameworksCompiled\project\vs</AdditionalIncludeDirectories>
    </ResourceCompile>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ProjectExtensions>
    <VisualStudio>
      <UserProperties RESOURCE_FILE="icon.rc" />
    </VisualStudio>
  </ProjectExtensions>
</Project>

================================================
FILE: example/src/Particle.cpp
================================================
/*
 *  Particle.cpp
 *  ofxMSAFluid Demo
 *
 *  Created by Mehmet Akten on 02/05/2009.
 *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.
 *
 */

#include "Particle.h"

static const float MOMENTUM = 0.5f;
static const float FLUID_FORCE = 0.6f;

void Particle::init(float x, float y) {
	pos = ofVec2f( x, y );
	vel = ofVec2f(0, 0);
	radius = 5;
	alpha  = msa::Rand::randFloat( 0.3f, 1 );
	mass = msa::Rand::randFloat( 0.1f, 1 );
}

void Particle::update( const msa::fluid::Solver &solver, const ofVec2f &windowSize, const ofVec2f &invWindowSize ) {
	// only update if particle is visible
	if( alpha == 0 )
		return;
	
	vel = solver.getVelocityAtPos( pos * invWindowSize ) * (mass * FLUID_FORCE ) * windowSize + vel * MOMENTUM;
	pos += vel;	
	
	// bounce of edges
	if( pos.x < 0 ) {
		pos.x = 0;
		vel.x *= -1;
	}
	else if( pos.x > windowSize.x ) {
		pos.x = windowSize.x;
		vel.x *= -1;
	}
	
	if( pos.y < 0 ) {
		pos.y = 0;
		vel.y *= -1;
	}
	else if( pos.y > windowSize.y ) {
		pos.y = windowSize.y;
		vel.y *= -1;
	}
	
	// hackish way to make particles glitter when the slow down a lot
//	if( vel.squareLength() < 1 ) {
//		vel += msa::Rand::randVec2f() * 0.5f;
//	}
	
	// fade out a bit (and kill if alpha == 0);
	alpha *= 0.999f;
	if( alpha < 0.01f )
		alpha = 0;
}



void Particle::updateVertexArrays( bool drawingFluid, const ofVec2f &invWindowSize, int i, float* posBuffer, float* colBuffer) {
	int vi = i * 4;
	posBuffer[vi++] = pos.x - vel.x;
	posBuffer[vi++] = pos.y - vel.y;
	posBuffer[vi++] = pos.x;
	posBuffer[vi++] = pos.y;
	
	int ci = i * 6;
	if( drawingFluid ) {
		// if drawing fluid, draw lines as black & white
		colBuffer[ci++] = alpha;
		colBuffer[ci++] = alpha;
		colBuffer[ci++] = alpha;
		colBuffer[ci++] = alpha;
		colBuffer[ci++] = alpha;
		colBuffer[ci++] = alpha;
	} else {
		// otherwise, use color
		float vxNorm = vel.x * invWindowSize.x;
		float vyNorm = vel.y * invWindowSize.y;
		float v2 = vxNorm * vxNorm + vyNorm * vyNorm;
#define VMAX 0.013f
		if(v2>VMAX*VMAX) v2 = VMAX*VMAX;
		float satInc = mass > 0.5 ? mass * mass * mass : 0;
		satInc *= satInc * satInc * satInc;
		ofColor color;
		color.setHsb(0, v2 * 255.0f / ( VMAX * VMAX ) + satInc, ofLerp(0.5, 1, mass) * alpha * 255.0f);
		
		colBuffer[ci++] = color.r;
		colBuffer[ci++] = color.g;
		colBuffer[ci++] = color.b;
		colBuffer[ci++] = color.r;
		colBuffer[ci++] = color.g;
		colBuffer[ci++] = color.b;
	}
}

================================================
FILE: example/src/Particle.h
================================================
/*
 *  Particle.h
 *  ofxMSAFluid Demo
 *
 *  Created by Mehmet Akten on 02/05/2009.
 *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.
 *
 */

#pragma once

#include "MSACore.h"
#include "MSAFluidSolver.h"

class Particle {
public:	
    ofVec2f	pos, vel;
    float	radius;
    float	alpha;
    float	mass;
	
    void init(float x, float y);
    void update( const msa::fluid::Solver &solver, const ofVec2f &windowSize, const ofVec2f &invWindowSize );
	void updateVertexArrays( bool drawingFluid, const ofVec2f &invWindowSize, int i, float* posBuffer, float* colBuffer);
};



================================================
FILE: example/src/ParticleSystem.cpp
================================================
/*
 *  ParticleSystem.cpp
 *  ofxMSAFluid Demo
 *
 *  Created by Mehmet Akten on 02/05/2009.
 *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.
 *
 */

#include "ParticleSystem.h"

ParticleSystem::ParticleSystem() {
	curIndex = 0;
}

void ParticleSystem::updateAndDraw(const msa::fluid::Solver &solver, ofVec2f windowSize, bool drawingFluid) {
    ofVec2f invWindowSize(1.0f / windowSize.x, 1.0f / windowSize.y);

	glEnable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
    glBlendFunc(GL_ONE,GL_ONE);
//	glEnable(GL_LINE_SMOOTH);
    ofSetLineWidth(1);
	
	for(int i=0; i<MAX_PARTICLES; i++) {
		if(particles[i].alpha > 0) {
			particles[i].update(solver, windowSize, invWindowSize);
			particles[i].updateVertexArrays(drawingFluid, invWindowSize, i, posArray, colArray);
		}
	}    
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(2, GL_FLOAT, 0, posArray);
	
	glEnableClientState(GL_COLOR_ARRAY);
	glColorPointer(3, GL_FLOAT, 0, colArray);
	
	glDrawArrays(GL_LINES, 0, MAX_PARTICLES * 2);
	
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
	
	glDisable(GL_BLEND);
}


void ParticleSystem::addParticles(const ofVec2f &pos, int count){
	for(int i=0; i<count; i++)
		addParticle(pos + msa::Rand::randVec2f() * 15);
}


void ParticleSystem::addParticle(const ofVec2f &pos) {
	particles[curIndex].init(pos.x, pos.y);
	curIndex++;
	if(curIndex >= MAX_PARTICLES) curIndex = 0;
}


================================================
FILE: example/src/ParticleSystem.h
================================================
/*
 *  ParticleSystem.h
 *  ofxMSAFluid Demo
 *
 *  Created by Mehmet Akten on 02/05/2009.
 *  Copyright 2009 MSA Visuals Ltd.. All rights reserved.
 *
 */
#pragma once

#include "Particle.h"

#define MAX_PARTICLES		50000

class ParticleSystem {
public:	
	
    float posArray[MAX_PARTICLES * 2 * 2];
    float colArray[MAX_PARTICLES * 3 * 2];
    int curIndex;
	
    Particle particles[MAX_PARTICLES];
	
	ParticleSystem();

    void updateAndDraw(const msa::fluid::Solver &aSolver, ofVec2f windowSize, bool drawingFluid);
	void addParticles(const ofVec2f &pos, int count);
	void addParticle(const ofVec2f &pos);
};



================================================
FILE: example/src/main.cpp
================================================

#include "testApp.h"

int main( ){
	ofSetupOpenGL(1024, 768, OF_WINDOW);			// <-------- setup the GL context
	ofRunApp(new testApp);
}


================================================
FILE: example/src/testApp.cpp
================================================
#include "testApp.h"


float tuioXScaler = 1;
float tuioYScaler = 1;

//--------------------------------------------------------------
void testApp::setup() {	 
	//for(int i=0; i<strlen(sz); i++) sz[i] += 20;
	
	// setup fluid stuff
	fluidSolver.setup(100, 100);
    fluidSolver.enableRGB(true).setFadeSpeed(0.002).setDeltaT(0.5).setVisc(0.00015).setColorDiffusion(0);
	fluidDrawer.setup(&fluidSolver);
	
	fluidCellsX			= 150;
	
	drawFluid			= true;
	drawParticles		= true;
	
	ofSetFrameRate(60);
	ofBackground(0, 0, 0);
	ofSetVerticalSync(false);
	
#ifdef USE_TUIO
	tuioClient.start(3333);
#endif

	
#ifdef USE_GUI 
	gui.addSlider("fluidCellsX", fluidCellsX, 20, 400);
	gui.addButton("resizeFluid", resizeFluid);
    gui.addSlider("colorMult", colorMult, 0, 100);
    gui.addSlider("velocityMult", velocityMult, 0, 100);
	gui.addSlider("fs.viscocity", fluidSolver.viscocity, 0.0, 0.01);
	gui.addSlider("fs.colorDiffusion", fluidSolver.colorDiffusion, 0.0, 0.0003); 
	gui.addSlider("fs.fadeSpeed", fluidSolver.fadeSpeed, 0.0, 0.1); 
	gui.addSlider("fs.solverIterations", fluidSolver.solverIterations, 1, 50); 
	gui.addSlider("fs.deltaT", fluidSolver.deltaT, 0.1, 5);
	gui.addComboBox("fd.drawMode", (int&)fluidDrawer.drawMode, msa::fluid::getDrawModeTitles());
	gui.addToggle("fs.doRGB", fluidSolver.doRGB); 
	gui.addToggle("fs.doVorticityConfinement", fluidSolver.doVorticityConfinement); 
	gui.addToggle("drawFluid", drawFluid); 
	gui.addToggle("drawParticles", drawParticles); 
	gui.addSlider("velDrawMult", fluidDrawer.velDrawMult, 0.0, 20);
	gui.addSlider("velDrawThreshold", fluidDrawer.velDrawThreshold, 0.0, 1);
	gui.addSlider("brightness", fluidDrawer.brightness, 0.0, 2);
	gui.addToggle("useAdditiveBlending", fluidDrawer.useAdditiveBlending);
	
	gui.addToggle("fs.wrapX", fluidSolver.wrap_x);
	gui.addToggle("fs.wrapY", fluidSolver.wrap_y);
    gui.addSlider("tuioXScaler", tuioXScaler, 0, 2);
    gui.addSlider("tuioYScaler", tuioYScaler, 0, 2);
    
	gui.currentPage().setXMLName("ofxMSAFluidSettings.xml");
    gui.loadFromXML();
	gui.setDefaultKeys(true);
	gui.setAutoSave(true);
    gui.show();
#endif
	
	windowResized(ofGetWidth(), ofGetHeight());		// force this at start (cos I don't think it is called)
	pMouse = msa::getWindowCenter();
	resizeFluid			= true;
	
	ofEnableAlphaBlending();
	ofSetBackgroundAuto(false);
}


void testApp::fadeToColor(float r, float g, float b, float speed) {
    glColor4f(r, g, b, speed);
	ofRect(0, 0, ofGetWidth(), ofGetHeight());
}


// add force and dye to fluid, and create particles
void testApp::addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce) {
    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
    if(speed > 0) {
		pos.x = ofClamp(pos.x, 0.0f, 1.0f);
		pos.y = ofClamp(pos.y, 0.0f, 1.0f);
		
        int index = fluidSolver.getIndexForPos(pos);
		
		if(addColor) {
//			Color drawColor(CM_HSV, (getElapsedFrames() % 360) / 360.0f, 1, 1);
			ofColor drawColor;
			drawColor.setHsb((ofGetFrameNum() % 255), 255, 255);
			
			fluidSolver.addColorAtIndex(index, drawColor * colorMult);
			
			if(drawParticles)
				particleSystem.addParticles(pos * ofVec2f(ofGetWindowSize()), 10);
		}
		
		if(addForce)
			fluidSolver.addForceAtIndex(index, vel * velocityMult);
		
    }
}


void testApp::update(){
	if(resizeFluid) 	{
		fluidSolver.setSize(fluidCellsX, fluidCellsX / msa::getWindowAspectRatio());
		fluidDrawer.setup(&fluidSolver);
		resizeFluid = false;
	}
	
#ifdef USE_TUIO
	tuioClient.getMessage();
	
	// do finger stuff
	list<ofxTuioCursor*>cursorList = tuioClient.getTuioCursors();
	for(list<ofxTuioCursor*>::iterator it=cursorList.begin(); it != cursorList.end(); it++) {
		ofxTuioCursor *tcur = (*it);
        float vx = tcur->getXSpeed() * tuioCursorSpeedMult;
        float vy = tcur->getYSpeed() * tuioCursorSpeedMult;
        if(vx == 0 && vy == 0) {
            vx = ofRandom(-tuioStationaryForce, tuioStationaryForce);
            vy = ofRandom(-tuioStationaryForce, tuioStationaryForce);
        }
        addToFluid(ofVec2f(tcur->getX() * tuioXScaler, tcur->getY() * tuioYScaler), ofVec2f(vx, vy), true, true);
    }
#endif
	
	fluidSolver.update();
}

void testApp::draw(){
	if(drawFluid) {
        ofClear(0);
		glColor3f(1, 1, 1);
		fluidDrawer.draw(0, 0, ofGetWidth(), ofGetHeight());
	} else {
//		if(ofGetFrameNum()%5==0)
            fadeToColor(0, 0, 0, 0.01);
	}
	if(drawParticles)
		particleSystem.updateAndDraw(fluidSolver, ofGetWindowSize(), drawFluid);
	
//	ofDrawBitmapString(sz, 50, 50);

#ifdef USE_GUI 
	gui.draw();
#endif
}


void testApp::keyPressed  (int key){ 
    switch(key) {
		case '1':
			fluidDrawer.setDrawMode(msa::fluid::kDrawColor);
			break;

		case '2':
			fluidDrawer.setDrawMode(msa::fluid::kDrawMotion);
			break;

		case '3':
			fluidDrawer.setDrawMode(msa::fluid::kDrawSpeed);
			break;
			
		case '4':
			fluidDrawer.setDrawMode(msa::fluid::kDrawVectors);
			break;
    
		case 'd':
			drawFluid ^= true;
			break;
			
		case 'p':
			drawParticles ^= true;
			break;
			
		case 'f':
			ofToggleFullscreen();
			break;
			
		case 'r':
			fluidSolver.reset();
			break;
			
		case 'b': {
//			Timer timer;
//			const int ITERS = 3000;
//			timer.start();
//			for(int i = 0; i < ITERS; ++i) fluidSolver.update();
//			timer.stop();
//			cout << ITERS << " iterations took " << timer.getSeconds() << " seconds." << std::endl;
		}
			break;
			
    }
}


//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y){
	ofVec2f eventPos = ofVec2f(x, y);
	ofVec2f mouseNorm = ofVec2f(eventPos) / ofGetWindowSize();
	ofVec2f mouseVel = ofVec2f(eventPos - pMouse) / ofGetWindowSize();
	addToFluid(mouseNorm, mouseVel, true, true);
	pMouse = eventPos;
}

void testApp::mouseDragged(int x, int y, int button) {
	ofVec2f eventPos = ofVec2f(x, y);
	ofVec2f mouseNorm = ofVec2f(eventPos) / ofGetWindowSize();
	ofVec2f mouseVel = ofVec2f(eventPos - pMouse) / ofGetWindowSize();
	addToFluid(mouseNorm, mouseVel, false, true);
	pMouse = eventPos;
}



================================================
FILE: example/src/testApp.h
================================================
#pragma once

#include "MSAFluid.h"
//#include "MSATimer.h"
#include "ParticleSystem.h"

#include "ofMain.h"

// comment this line out if you don't wanna use TUIO
// you will need ofxTUIO & ofxOsc
//#define USE_TUIO

// comment this line out if you don't wanna use the GUI
// you will need ofxSimpleGuiToo, ofxMSAInteractiveObject & ofxXmlSettings
// if you don't use the GUI, you won't be able to see the fluid parameters
#define USE_GUI		


#ifdef USE_TUIO
#include "ofxTuio.h"
#define tuioCursorSpeedMult				0.5	// the iphone screen is so small, easy to rack up huge velocities! need to scale down 
#define tuioStationaryForce				0.001f	// force exerted when cursor is stationary
#endif


#ifdef USE_GUI 
#include "ofxSimpleGuiToo.h"
#endif

class testApp : public ofBaseApp {
public:



	float                   colorMult;
	float                   velocityMult;
	int                     fluidCellsX;
	bool                    resizeFluid;
	bool                    drawFluid;
	bool                    drawParticles;

	// TODO
	struct {
		int count;
		struct Disturber {
			ofVec2f pos;
			ofVec2f vel;
			float amp;
		};
		float noiseAmp;
		float noiseFreq;
		bool draw;
		vector<Disturber> forces;
	} randForce;

	msa::fluid::Solver      fluidSolver;
	msa::fluid::DrawerGl	fluidDrawer;

	ParticleSystem          particleSystem;

	ofVec2f                 pMouse;

	float vectorLength;

	void setup();
	void update();
	void draw();
	
	void keyPressed  (int key);
	void mouseMoved(int x, int y );
	void mouseDragged(int x, int y, int button);

	void fadeToColor(float r, float g, float b, float speed);
	void addToFluid(ofVec2f pos, ofVec2f vel, bool addColor, bool addForce);

	
#ifdef USE_TUIO
	ofxTuioClient tuioClient;
#endif	
	
};


================================================
FILE: license.md
================================================
The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license).

Copyright (c) 2008-2012 Memo Akten, [www.memo.tv](http://www.memo.tv)  
The Mega Super Awesome Visuals Company

//	April-Mai 2009 optimized and extended by Maa (http://www.lagraine.com/ - new content coming soon)

/* Portions Copyright (c) 2010, The Cinder Project, http://libcinder.org */



Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: src/MSAFluid.h
================================================
#pragma once

#include "MSAFluidSolver.h"

#if defined( MSA_HOST_OPENFRAMEWORKS )
#include "MSAFluidDrawerGl-OF.h"

#elif defined( MSA_HOST_CINDER )
#include "MSAFluidDrawerGl-Cinder.h"

#endif


================================================
FILE: src/MSAFluidDrawerBase.cpp
================================================
/***********************************************************************
 
 This class is for drawing a fluidsolver using the openFrameworks texture
 
 ************************************************************************/

#include "MSAFluidDrawerBase.h"


namespace msa {
    namespace fluid {
        
        //--------------------------------------------------------------
        vector<string>& getDrawModeTitles(){
            static vector<string> drawModeTitles;
            if(drawModeTitles.size() == 0) {
                drawModeTitles.push_back("kDrawColor");
                drawModeTitles.push_back("kDrawMotion");
                drawModeTitles.push_back("kDrawSpeed");
                drawModeTitles.push_back("kDrawVectors");
            }
            return drawModeTitles;
        }
        
        
        //--------------------------------------------------------------
        DrawerBase::DrawerBase() {
            _pixels				= NULL;
            _fluidSolver		= NULL;
            _didICreateTheFluid	= false;
            
            enabled				= true;
            useAdditiveBlending = false;
            brightness			= 1;
            doInvert			= false;
            velDrawMult				= 1;
            vectorSkipCount		= 0;
            
            enableAlpha(false);
            
            setDrawMode(kDrawColor);
        }
        
        //--------------------------------------------------------------
        DrawerBase::~DrawerBase() {
            deleteFluidSolver();
        }
        

        //--------------------------------------------------------------
        Solver* DrawerBase::setup(int NX, int NY) {
            deleteFluidSolver();
            _fluidSolver = new Solver;
            _fluidSolver->setup(NX, NY);
            allocatePixels();
            createTexture();
            
            return _fluidSolver;
        }
        

        //--------------------------------------------------------------
        Solver* DrawerBase::setup(Solver* f) {
            deleteFluidSolver();
            _fluidSolver = f;
            allocatePixels();
            createTexture();
            
            return _fluidSolver;
        }
        
        //--------------------------------------------------------------
        Solver* DrawerBase::getFluidSolver() {
            return _fluidSolver;
        }
        
        //--------------------------------------------------------------
        void DrawerBase::enableAlpha(bool b) {
            _alphaEnabled = b;
            if(_alphaEnabled) {
                _glType = GL_RGBA;
                _bpp = 4;
            } else {
                _glType = GL_RGB;
                _bpp = 3;
            }
            
            if(isFluidReady()) {
                allocatePixels();
                createTexture();
            }
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::allocatePixels() {
            if(_pixels) delete []_pixels;
            int texWidth = _fluidSolver->getWidth()-2;
            int texHeight =_fluidSolver->getHeight()-2;
            _pixels = new unsigned char[texWidth * texHeight * _bpp];
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::reset() {
            if(!isFluidReady()) {
                printf("DrawerBase::reset() - Fluid not ready\n");
                return;
            }
            _fluidSolver->reset();
        }
        
        //--------------------------------------------------------------
        void DrawerBase::update() {
            if(!isFluidReady()) {
                printf("DrawerBase::updateFluid() - Fluid not ready\n");
                return;
            }
            _fluidSolver->update();
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::setDrawMode(DrawMode newDrawMode) {
            drawMode = newDrawMode;
            if(drawMode < 0) drawMode = (DrawMode)(kDrawCount-1);
            else if(drawMode >= kDrawCount) drawMode = (DrawMode)0;
        }
        
        //--------------------------------------------------------------
        void DrawerBase::incDrawMode() {
            setDrawMode((DrawMode)((int)drawMode + 1));
        }
        
        //--------------------------------------------------------------
        void DrawerBase::decDrawMode() {
            setDrawMode((DrawMode)(drawMode - 1));
        }
        
        //--------------------------------------------------------------
        DrawMode DrawerBase::getDrawMode() {
            return drawMode;
        }
        
        //--------------------------------------------------------------
        string DrawerBase::getDrawModeName() {
            return getDrawModeTitles().at(drawMode);
        }
        
        
        
        //--------------------------------------------------------------
        void DrawerBase::draw(float x, float y) const {
            if(enabled == false) return;
            
            draw(x, y, getWindowWidth(), getWindowHeight());
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::draw(float x, float y, float renderWidth, float renderHeight) const {
            if(enabled == false) return;
            
            switch(drawMode) {
                case kDrawColor:
                    drawColor(x, y, renderWidth, renderHeight);
                    break;
                    
                case kDrawMotion:
                    drawMotion(x, y, renderWidth, renderHeight);
                    break;
                    
                case kDrawSpeed:
                    drawSpeed(x, y, renderWidth, renderHeight);
                    break;
                    
                case kDrawVectors:
                    drawVectors(x, y, renderWidth, renderHeight);
                    break;
                    
                default:
                    break;
                    
            }
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::drawColor(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {
            if(enabled == false) return;
            
            ofPushStyle();
            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);
            else ofDisableAlphaBlending();

            int fw = _fluidSolver->getWidth();
            int fh = _fluidSolver->getHeight();
            
            Vec2f vel;
            Color color;
            int index = 0;
            for(int j=1; j < fh-1; j++) {
                for(int i=1; i < fw-1; i++) {
                    _fluidSolver->getInfoAtCell(i, j, &vel, &color);
                    int r = (unsigned char)min(color.r * 255 * brightness, 255.0f);
                    int g = (unsigned char)min(color.g * 255 * brightness, 255.0f);
                    int b = (unsigned char)min(color.b * 255 * brightness, 255.0f);
                    if(doInvert) {
                        r = 255 - r;
                        g = 255 - g;
                        b = 255 - b;
                    }
                    _pixels[index++] = r;
                    _pixels[index++] = g;
                    _pixels[index++] = b;
                    
                    if(_alphaEnabled) _pixels[index++] = withAlpha ? max(b, max(r, g)) : 255;
                }
            }
            
            updateTexture();
            drawTexture(x, y, renderWidth, renderHeight);
            ofPopStyle();
        }
        
        
        
        //--------------------------------------------------------------
        void DrawerBase::drawMotion(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {
            if(enabled == false) return;
            
            ofPushStyle();
            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);
            else ofDisableAlphaBlending();
            
            int fw = _fluidSolver->getWidth();
            int fh = _fluidSolver->getHeight();
            
            Vec2f vel;
            int index = 0;
            for(int j=1; j < fh-1; j++) {
                for(int i=1; i < fw-1; i++) {
                    _fluidSolver->getInfoAtCell(i, j, &vel, NULL);
                    float speed2 = fabs(vel.x) * fw + fabs(vel.y) * fh;
                    int speed = (int)min(speed2 * 255 * brightness, 255.0f);
                    _pixels[index++] = (unsigned char)min(fabs(vel.x) * fw * 255 * brightness, 255.0f);
                    _pixels[index++] = (unsigned char)min(fabs(vel.y) * fh * 255 * brightness, 255.0f);
                    _pixels[index++] = (unsigned char)0;
                    
                    if(_alphaEnabled) _pixels[index++] = withAlpha ? speed : 255;
                    
                }
            }
            
            updateTexture();
            drawTexture(x, y, renderWidth, renderHeight);
            ofPopStyle();
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::drawSpeed(float x, float y, float renderWidth, float renderHeight, bool withAlpha) const {
            if(enabled == false) return;
            
            ofPushStyle();
            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);
            else ofDisableAlphaBlending();
            
            int fw = _fluidSolver->getWidth();
            int fh = _fluidSolver->getHeight();
            
            Vec2f vel;
            int index = 0;
            for(int j=1; j < fh-1; j++) {
                for(int i=1; i < fw-1; i++) {
                    _fluidSolver->getInfoAtCell(i, j, &vel, NULL);
                    float speed2 = fabs(vel.x) * fw + fabs(vel.y) * fh;
                    int speed = (int)min(speed2 * 255 * brightness, 255.0f);
                    _pixels[index++] = (unsigned char)speed;
                    _pixels[index++] = (unsigned char)speed;
                    _pixels[index++] = (unsigned char)speed;
                    
                    if(_alphaEnabled) _pixels[index++] = withAlpha ? speed : 255;
                }
            }
            
            updateTexture();
            drawTexture(x, y, renderWidth, renderHeight);
            ofPopStyle();
        }
        
        
        //--------------------------------------------------------------
        void DrawerBase::drawVectors(float x, float y, float renderWidth, float renderHeight)  const {
            if(enabled == false) return;
            
            ofPushStyle();
            if(useAdditiveBlending) ofEnableBlendMode(OF_BLENDMODE_ADD);
            else ofDisableAlphaBlending();

            int fw = _fluidSolver->getWidth();
            int fh = _fluidSolver->getHeight();

            //	int xStep = renderWidth / 10;		// every 10 pixels
            //	int yStep = renderHeight / 10;		// every 10 pixels
            
            ofPushMatrix();
            ofTranslate(x, y, 0);
            ofScale(renderWidth/(fw-2), renderHeight/(fh-2), 1.0);
            
            float maxVel = 5.0f/20000;
            
            Vec2f vel;
            float vt = velDrawThreshold * _fluidSolver->getInvWidth() * _fluidSolver->getInvHeight();
            vt *= vt;
			ofMesh mesh;
            for (int j=0; j<fh-2; j+=vectorSkipCount+1 ){
                for (int i=0; i<fw-2; i+=vectorSkipCount+1 ){
					ofVec2f pos(i, j);
					vel = _fluidSolver->getVelocityAtCell(i+1, j+1);
                    float d2 = vel.lengthSquared();
                    if(d2>vt) {
                        if(d2 > maxVel * maxVel) {
                            float mult = maxVel * maxVel/ d2;
                            //				float mult = (d2 - maxVel * maxVel) / d2;
                            vel.x *= mult;
                            vel.y *= mult;
                        }
                        vel *= velDrawMult * 50000;
                        float b = mapRange(d2, vt, maxVel, 0.0f, brightness);
                        b = brightness*255;
						mesh.addColor(ofColor::black);
						mesh.addVertex(ofVec3f(pos));

						mesh.addColor(ofColor(b, b, b));
						mesh.addVertex(ofVec3f(pos + vel));

						//ofSetColor(b, b, b);
						//ofDrawLine(i, j, i + vel.x, j + vel.y);

						//ofSetPolyMode(OF_POLY_WINDING_POSITIVE);
						//ofNoFill();
						//ofBeginShape();
						//ofSetColor(0, 0, 0);
						//ofVertex(i, j);
						//ofSetColor(b, b, b);
						//ofVertex(i + vel.x, j + vel.y);
						//ofEndShape();


					}
                }
            }
			mesh.setMode(OF_PRIMITIVE_LINES);
			mesh.drawWireframe();
            ofPopMatrix();
            ofPopStyle();
        }
        
        
        
        //--------------------------------------------------------------
        void DrawerBase::deleteFluidSolver() {
            //	printf("DrawerBase::deleteFluidSolver()\n");
            if(_fluidSolver && _didICreateTheFluid) {
                delete _fluidSolver;
                _fluidSolver = NULL;
                
                if(_pixels) delete []_pixels;
                _pixels = NULL;
                
                deleteTexture();
            }
        }
        
        //--------------------------------------------------------------
        bool DrawerBase::isFluidReady() {
            if(!_fluidSolver) {
                printf("DrawerBase::isFluidReady() - No fluid solver\n");
                return false;
            }
            
            if(!_fluidSolver->isInited()) {
                printf("DrawerBase::isFluidReady() - Fluid solver not initialized yet, call init()\n");
                return false;
            }
            
            return true;
        }
    }
}


================================================
FILE: src/MSAFluidDrawerBase.h
================================================
/***********************************************************************
 
 This class is for drawing a fluidsolver using the OpenFrameworks texture
 
 ************************************************************************/

#pragma once

#include "MSACore.h"
#include "MSAFluidSolver.h"

namespace msa {
	namespace fluid {
        
        typedef enum {
            kDrawColor,
            kDrawMotion,
            kDrawSpeed,
            kDrawVectors,
            kDrawCount
        } DrawMode;
        
        
        vector<string>& getDrawModeTitles();
        
        class DrawerBase
#ifdef MSA_HOST_OPENFRAMEWORKS
        : public ofBaseDraws
#endif
        {
        public:
            bool	enabled;
            bool	doInvert;
            bool	useAdditiveBlending;
            float	brightness;
            float	velDrawThreshold;
            float	velDrawMult;
            int		vectorSkipCount;
            
            DrawMode		drawMode;
            
            DrawerBase();
            virtual ~DrawerBase();
            
            Solver* setup(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);
            Solver* setup(Solver* f);
            Solver* getFluidSolver();
            
            void enableAlpha(bool b);
            
            void update();
            
            void draw(float x, float y) const override;
            void draw(float x, float y, float renderWidth, float renderHeight) const override;				// this one does chooses one of the below based on drawmode
            void drawColor(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;
            void drawMotion(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;
            void drawSpeed(float x, float y, float renderWidth, float renderHeight, bool withAlpha = false) const;
            void drawVectors(float x, float y, float renderWidth, float renderHeight) const;
            void reset();
            
           // float getWidth() const override {}
            //float getHeight() const override {}
            
            void setDrawMode(DrawMode newDrawMode);
            void incDrawMode();
            void decDrawMode();
            DrawMode getDrawMode();
            string getDrawModeName();
            
        protected:
            unsigned char		*_pixels;						// pixels array to be drawn
            
            int					_glType;						// GL_RGB or GL_RGBA
            bool				_alphaEnabled;
            int					_bpp;							// 3 or 4
            
            Solver              *_fluidSolver;
            bool				_didICreateTheFluid;    // TODO: replace with shared pointer
            
            void				allocatePixels();
            
            virtual void		createTexture() = 0;									// override to create a texture
            virtual void		updateTexture() const = 0;									// override to update the texture from the pixels array
            virtual void		deleteTexture() = 0;									// override to delete the texture
            virtual void		drawTexture(float x, float y, float w, float h) const = 0;	// override to draw texture
            
            void				deleteFluidSolver();
            bool				isFluidReady();
            
        };
    }
}


================================================
FILE: src/MSAFluidDrawerGl-Cinder.h
================================================
/***********************************************************************
 
 This class is for drawing a fluidsolver using the OpenFrameworks texture
 
 /***********************************************************************
 
 Copyright (c) 2008, 2009, 2010, Memo Akten, www.memo.tv
 *** The Mega Super Awesome Visuals Company ***
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of MSA Visuals nor the names of its contributors 
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 *
 * ***********************************************************************/ 

#pragma once

#include "MSAFluidDrawerBase.h"
#include "cinder/Surface.h"
#include "cinder/gl/Texture.h"

namespace msa {
	
	class FluidDrawerGl : public FluidDrawerBase {
	public:
		
		float getWidth() {
			return tex.getWidth();
		}
		
		float getHeight() {
			return tex.getHeight();
		}
		
	protected:	
		ci::Surface8u		surface;
		ci::gl::Texture		tex;

		void createTexture() {
			int texWidth = _fluidSolver->getWidth()-2;
			int texHeight =_fluidSolver->getHeight()-2;
			
			surface = ci::Surface8u( _pixels, texWidth, texHeight, false, ci::SurfaceChannelOrder::RGB );
			
			ci::gl::Texture::Format format;
			format.setInternalFormat( _glType );
			tex = ci::gl::Texture( texWidth, texHeight, format );
		}
		
		
		void updateTexture() {
			tex.update( surface );
		}
		
		void deleteTexture() {
			tex.reset();
		}
		
		void drawTexture(float x, float y, float w, float h) {
			ci::gl::draw( tex, ci::Rectf( x, y, x + w, y + h ) );
		}
	};
}


================================================
FILE: src/MSAFluidDrawerGl-OF.h
================================================
/***********************************************************************
 
 This class is for drawing a fluidsolver using the OpenFrameworks texture
 
 ************************************************************************/

#pragma once

#include "MSAFluidDrawerBase.h"

namespace msa {
    namespace fluid {
        
        class DrawerGl : public DrawerBase {
        public:
            float getWidth() const override {
                return tex.getWidth();
            }
            
            float getHeight() const override {
                return tex.getHeight();
            }
            
            ofTexture&	getTextureReference() {
                return tex;
            }
            
            
        protected:
            mutable ofTexture			tex;
            
            void createTexture() override {
                int texWidth = _fluidSolver->getWidth()-2;
                int texHeight =_fluidSolver->getHeight()-2;
                tex.allocate(texWidth, texHeight, _glType);
            }
            
            
            void updateTexture() const override {
                tex.loadData(_pixels, (int)tex.getWidth(), (int)tex.getHeight(), _glType);
            }
            
            void deleteTexture() override {
                tex.clear();
            }
            
            void drawTexture(float x, float y, float w, float h) const override {
                tex.draw(x, y, w, h);
            }		
        };
    }
}


================================================
FILE: src/MSAFluidParticleUpdater.h
================================================
/***********************************************************************
 
 This class interfaces the fluid solver with ofxMSAPhysics (applies fluid velocity as forces to particles)
 
 ***********************************************************************/

// only include this if you have MSAPhysics as well


#pragma once

#include "MSAFluid.h"
#include "MSAPhysicsParticleUpdater.h"

namespace msa {
	
	template <typename T>
	class FluidParticleUpdater : public Physics::ParticleUpdaterT<T> {
	public:
		float strength;
		Solver *fluidSolver;
		
		FluidParticleUpdater() {
			fluidSolver = NULL;
		}
		
		void update(Physics::ParticleT<T> *p) {
			if(fluidSolver) {
				Vec2f fluidVel = fluidSolver->getVelocityAtPos(p->getPosition()* p->getParams()->worldSizeInv);
				float invMass = p->getInvMass();
				p->addVelocity(fluidVel.x * invMass * strength, fluidVel.y * invMass * strength, 0);
			}
		}
		
	};
	
}


================================================
FILE: src/MSAFluidSolver.cpp
================================================
/***********************************************************************
 
 This class is for the actual solver (doesn't draw anything)
 
 ************************************************************************/

#include "MSAFluidSolver.h"

namespace msa {
    namespace fluid {
        
        Solver::Solver()
        :density(NULL)
        ,densityOld(NULL)
        ,uv(NULL)
        ,uvOld(NULL)
        ,color(NULL)
        ,colorOld(NULL)
        ,curl(NULL)
        ,_isInited(false)
        {
        }
        
        //--------------------------------------------------------------
        Solver& Solver::setSize(int NX, int NY)
        {
            _NX = NX;
            _NY = NY;
            _numCells = (_NX + 2) * (_NY + 2);
            
            _invNX = 1.0f / _NX;
            _invNY = 1.0f / _NY;
            _invNumCells = 1.0f / _numCells;
            
            width           = getWidth();
            height          = getHeight();
            invWidth        = 1.0f/width;
            invHeight       = 1.0f/height;
            
            reset();
            return *this;
        }
        
        
        //--------------------------------------------------------------
        Solver& Solver::setup(int NX, int NY)
        {
            setDeltaT();
            setFadeSpeed();
            setSolverIterations();
            enableVorticityConfinement(false);
            setWrap(false, false);
            
            //maa
            viscocity =  FLUID_DEFAULT_VISC;
            colorDiffusion = FLUID_DEFAULT_COLOR_DIFFUSION;
            
            return setSize(NX, NY);
        }
        
        //--------------------------------------------------------------
        Solver&  Solver::setDeltaT(float deltaT) {
            this->deltaT = deltaT;
            return *this;
        }
        
        //--------------------------------------------------------------
        Solver&  Solver::setFadeSpeed(float fadeSpeed) {
            this->fadeSpeed = fadeSpeed;
            return *this;
        }
        
        //--------------------------------------------------------------
        Solver&  Solver::setSolverIterations(int solverIterations) {
            this->solverIterations = solverIterations;
            return *this;
        }
        
        
        //--------------------------------------------------------------
        // whether fluid is RGB or monochrome (if only pressure / velocity is needed no need to update 3 channels)
        Solver&  Solver::enableRGB(bool doRGB) {
            this->doRGB = doRGB;
            return *this;
        }
        
        //--------------------------------------------------------------
        Solver&  Solver::enableVorticityConfinement(bool b) {
            doVorticityConfinement = b;
            return *this;
        }
        
        //--------------------------------------------------------------
        bool Solver::getVorticityConfinement() {
            return doVorticityConfinement;
        }
        
        //--------------------------------------------------------------
        Solver& Solver::setWrap(bool bx, bool by) {
            wrap_x = bx;
            wrap_y = by;
            return *this;
        }
        
        //--------------------------------------------------------------
        bool Solver::isInited() const {
            return _isInited;
        }
        
        //--------------------------------------------------------------
        Solver::~Solver() {
            destroy();
        }
        
        //--------------------------------------------------------------
        void Solver::destroy() {
            _isInited = false;
            
            if(density)		delete []density;
            if(densityOld)	delete []densityOld;
            if(color)		delete []color;
            if(colorOld)	delete []colorOld;
            if(uv)		delete []uv;
            if(uvOld)	delete []uvOld;
            if(curl)       delete []curl;
        }
        
        
        //--------------------------------------------------------------
        void Solver::reset() {
            destroy();
            _isInited = true;
            
            density		= new float[_numCells];
            densityOld	= new float[_numCells];
            color		= new Vec3f[_numCells];
            colorOld	= new Vec3f[_numCells];
            uv    = new Vec2f[_numCells];
            uvOld = new Vec2f[_numCells];
            curl = new float[_numCells];
            
            for (int i = _numCells-1; i>=0; --i) {
                density[i] = 0;
                densityOld[i] = 0;
                color[i] = Vec3f::zero();
                colorOld[i] = Vec3f::zero();
                uv[i] = Vec2f::zero();
                uvOld[i] = Vec2f::zero();
                curl[i] = 0.0f;
            }
        }
        
        //--------------------------------------------------------------
        // return total number of cells (_NX+2) * (_NY+2)
        int Solver::getNumCells() const {
            return _numCells;
        }
        
        //--------------------------------------------------------------
        int Solver::getWidth() const {
            return _NX + 2;
        }
        
        
        //--------------------------------------------------------------
        int Solver::getHeight() const {
            return _NY + 2;
        }
        
        //--------------------------------------------------------------
        float Solver::getInvWidth() const {
            return invWidth;
        }
        
        
        //--------------------------------------------------------------
        float Solver::getInvHeight() const {
            return invHeight;
        }
        
        //--------------------------------------------------------------
        Vec2f Solver::getSize() {
            return Vec2f(getWidth(), getHeight());
        }
        
        //--------------------------------------------------------------
        Vec2f Solver::getInvSize() {
            return Vec2f(invWidth, invHeight);
        }
        
        
        
        //--------------------------------------------------------------
        Solver& Solver::setVisc(float newVisc) {
            viscocity = newVisc;
            return *this;
        }
        
        //--------------------------------------------------------------
        // returns current viscocity
        float Solver::getVisc() const {
            return viscocity;
        }
        
        //--------------------------------------------------------------
        Solver& Solver::setColorDiffusion(float diff)
        {
            colorDiffusion = diff;
            return *this;
        }
        
        //--------------------------------------------------------------
        float	Solver::getColorDiffusion()
        {
            return colorDiffusion;
        }
        
        //--------------------------------------------------------------
        // returns average density of fluid
        float Solver::getAvgDensity() const {
            return _avgDensity;
        }
        
        //--------------------------------------------------------------
        // returns average uniformity
        float Solver::getUniformity() const {
            return _uniformity;
        }
        
        //--------------------------------------------------------------
        float Solver::getAvgSpeed() const {
            return _avgSpeed;
        }
        
        //--------------------------------------------------------------
        // Curl and vorticityConfinement based on code by Alexander McKenzie
        float Solver::calcCurl(int i, int j)
        {
            float du_dy = uv[FLUID_IX(i, j + 1)].x - uv[FLUID_IX(i, j - 1)].x;
            float dv_dx = uv[FLUID_IX(i + 1, j)].y - uv[FLUID_IX(i - 1, j)].y;
            return (du_dy - dv_dx) * 0.5f;	// for optimization should be moved to later and done with another operation
        }
        
        //--------------------------------------------------------------
        void Solver::vorticityConfinement(Vec2f* Fvc_xy) {
            float dw_dx, dw_dy;
            float length;
            float v;
            
            // Calculate magnitude of calcCurl(u,v) for each cell. (|w|)
            for (int j = _NY; j > 0; --j)
            {
                for (int i = _NX; i > 0; --i)
                {
                    curl[FLUID_IX(i, j)] = fabs(calcCurl(i, j));
                }
            }
            
            for (int j = _NY-1; j > 1; --j)	//for (int j = 2; j < _NY; j++)
            {
                for (int i = _NX-1; i > 1; --i)		//for (int i = 2; i < _NX; i++)
                {
                    // Find derivative of the magnitude (_N = del |w|)
                    dw_dx = (curl[FLUID_IX(i + 1, j)] - curl[FLUID_IX(i - 1, j)]);	// was * 0.5f; now done later with 2./lenght
                    dw_dy = (curl[FLUID_IX(i, j + 1)] - curl[FLUID_IX(i, j - 1)]);	// was * 0.5f;
                    
                    // Calculate vector length. (|_N|)
                    // Add small factor to prevent divide by zeros.
                    length = (float) sqrt(dw_dx * dw_dx + dw_dy * dw_dy) + 0.000001f;
                    
                    // N = (_N/|_N|)
                    length = 2./length;	// the 2. come from the previous * 0.5
                    dw_dx *= length;
                    dw_dy *= length;
                    
                    v = calcCurl(i, j);
                    
                    // N x w
                    Fvc_xy[FLUID_IX(i, j)].x = dw_dy * -v;
                    Fvc_xy[FLUID_IX(i, j)].y = dw_dx *  v;
                }
            }
        }
        
        //--------------------------------------------------------------
        void Solver::update() {
            addSource(uv, uvOld);
            
            if(doVorticityConfinement)
            {
                vorticityConfinement(uvOld);
                addSource(uv, uvOld);
            }
            
            SWAP(uv, uvOld);
            
            diffuseUV(viscocity);
            
            project(uv, uvOld);
            
            SWAP(uv, uvOld);
            
            advect2d(uv, uvOld);
            
            project(uv, uvOld);
            
            if(doRGB)
            {
                addSource(color, colorOld);
                SWAP(color, colorOld);
                
                if(colorDiffusion!=0. && deltaT!=0.)
                {
                    diffuseRGB(0, colorDiffusion);
                    SWAP(color, colorOld);
                }
                
                advectRGB(0, uv);
                fadeRGB();
            }
            else
            {
                addSource(density, densityOld);
                SWAP(density, densityOld);
                
                if(colorDiffusion!=0. && deltaT!=0.) {
                    diffuse(0, density, densityOld, colorDiffusion);
                    SWAP(density, densityOld);
                }
                
                advect(0, density, densityOld, uv);
                fadeDensity();
            }
        }
        
#define ZERO_THRESH		1e-9			// if value falls under this, set to zero (to avoid denormal slowdown)
#define CHECK_ZERO(p)	if(fabsf(p)<ZERO_THRESH) p = 0
        
        //--------------------------------------------------------------
        void Solver::fadeDensity() {
            // 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...
            //		float holdAmount = 1 - _avgDensity * _avgDensity * fadeSpeed;	// this is how fast the density will decay depending on how full the screen currently is
            float holdAmount = 1 - fadeSpeed;
            
            _avgDensity = 0;
            _avgSpeed = 0;
            
            float totalDeviations = 0;
            float currentDeviation;
            float tmp;
            _avgSpeed = 0;
            
            for (int i = _numCells-1; i >=0; --i) {
                
                // clear old values
                uvOld[i] = Vec2f::zero();
                densityOld[i] = 0;
                
                // calc avg speed
                _avgSpeed += uv[i].x * uv[i].x + uv[i].y * uv[i].y;
                
                // calc avg density
                tmp = min(1.0f, density[i]);
                _avgDensity += tmp;	// add it up
                
                // calc deviation (for uniformity)
                currentDeviation = tmp - _avgDensity;
                totalDeviations += currentDeviation * currentDeviation;
                
                // fade out old
                density[i] = tmp * holdAmount;
                
                CHECK_ZERO(density[i]);
                CHECK_ZERO(uv[i].x);
                CHECK_ZERO(uv[i].y);
                if(doVorticityConfinement) CHECK_ZERO(curl[i]);
                
            }
            _avgDensity *= _invNumCells;
            _avgSpeed *= _invNumCells;
            
            //	println("%.3f\n", _avgSpeed);
            _uniformity = 1.0f / (1 + totalDeviations * _invNumCells);		// 0: very wide distribution, 1: very uniform
        }
        
        
        //--------------------------------------------------------------
        void Solver::fadeRGB() {
            // 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...
            //		float holdAmount = 1 - _avgDensity * _avgDensity * fadeSpeed;	// this is how fast the density will decay depending on how full the screen currently is
            float holdAmount = 1 - fadeSpeed;
            
            _avgDensity = 0;
            _avgSpeed = 0;
            
            float totalDeviations = 0;
            float currentDeviation;
            Vec3f tmp;
            _avgSpeed = 0;
            
            for (int i = _numCells-1; i >=0; --i)
            {
                // clear old values
                uvOld[i] = Vec2f::zero();
                colorOld[i] = Vec3f::zero();
                
                // calc avg speed
                _avgSpeed += uv[i].x * uv[i].x + uv[i].y * uv[i].y;
                
                // calc avg density
                tmp.x = min(1.0f, color[i].x);
                tmp.y = min(1.0f, color[i].y);
                tmp.z = min(1.0f, color[i].z);
                //			tmp.a = min(1.0f, color[i].a);
                
                //			float density = max(tmp.a, max(tmp.r, max(tmp.g, tmp.b)));
                //			float density = max(tmp.r, max(tmp.g, tmp.b));
                float density = max(tmp.x, max(tmp.y, tmp.z));
                _avgDensity += density;	// add it up
                
                // calc deviation (for _uniformity)
                currentDeviation = density - _avgDensity;
                totalDeviations += currentDeviation * currentDeviation;
                
                // fade out old
                color[i] = tmp * holdAmount;
                
                CHECK_ZERO(color[i].x);
                CHECK_ZERO(color[i].y);
                CHECK_ZERO(color[i].z);
                //			CHECK_ZERO(color[i].a);
                CHECK_ZERO(uv[i].x);
                CHECK_ZERO(uv[i].y);
                if(doVorticityConfinement) CHECK_ZERO(curl[i]);
            }
            _avgDensity *= _invNumCells;
            _avgSpeed *= _invNumCells;
            
            //println("%.3f\n", _avgDensity);
            _uniformity = 1.0f / (1 + totalDeviations * _invNumCells);		// 0: very wide distribution, 1: very uniform
        }
        
        
        //	void Solver::addSourceUV()
        //	{
        //		for (int i = _numCells-1; i >=0; --i) {
        //			uv[i] += deltaT * uvOld[i];
        //		}
        //	}
        //
        //	void Solver::addSourceRGB()
        //	{
        //		for (int i = _numCells-1; i >=0; --i) {
        //			color[i] += deltaT * colorOld[i];
        //		}
        //	}
        //
        //	void Solver::addSource(float* x, float* x0) {
        //		for (int i = _numCells-1; i >=0; --i) {
        //			x[i] += deltaT * x0[i];
        //		}
        //	}
        
        //--------------------------------------------------------------
        void Solver::advect(int bound, float* d, const float* d0, const Vec2f* duv) {
            int i0, j0, i1, j1;
            float x, y, s0, t0, s1, t1;
            int	index;
            
            const float dt0x = deltaT * _NX;
            const float dt0y = deltaT * _NY;
            
            for (int j = _NY; j > 0; --j)
            {
                for (int i = _NX; i > 0; --i)
                {
                    index = FLUID_IX(i, j);
                    x = i - dt0x * duv[index].x;
                    y = j - dt0y * duv[index].y;
                    
                    if (x > _NX + 0.5) x = _NX + 0.5f;
                    if (x < 0.5)     x = 0.5f;
                    
                    i0 = (int) x;
                    i1 = i0 + 1;
                    
                    if (y > _NY + 0.5) y = _NY + 0.5f;
                    if (y < 0.5)     y = 0.5f;
                    
                    j0 = (int) y;
                    j1 = j0 + 1;
                    
                    s1 = x - i0;
                    s0 = 1 - s1;
                    t1 = y - j0;
                    t0 = 1 - t1;
                    
                    d[index] = s0 * (t0 * d0[FLUID_IX(i0, j0)] + t1 * d0[FLUID_IX(i0, j1)])
                    + s1 * (t0 * d0[FLUID_IX(i1, j0)] + t1 * d0[FLUID_IX(i1, j1)]);
                    
                }
            }
            setBoundary(bound, d);
        }
        
        //--------------------------------------------------------------
        //          d    d0    du    dv
        // advect(1, u, uOld, uOld, vOld);
        // advect(2, v, vOld, uOld, vOld);
        void Solver::advect2d(Vec2f *uv, const Vec2f *duv) {
            int i0, j0, i1, j1;
            float s0, t0, s1, t1;
            int	index;
            
            const float dt0x = deltaT * _NX;
            const float dt0y = deltaT * _NY;
            
            for (int j = _NY; j > 0; --j)
            {
                for (int i = _NX; i > 0; --i)
                {
                    index = FLUID_IX(i, j);
                    float x = i - dt0x * duv[index].x;
                    float y = j - dt0y * duv[index].y;
                    
                    if (x > _NX + 0.5) x = _NX + 0.5f;
                    if (x < 0.5)     x = 0.5f;
                    
                    i0 = (int) x;
                    i1 = i0 + 1;
                    
                    if (y > _NY + 0.5) y = _NY + 0.5f;
                    if (y < 0.5)     y = 0.5f;
                    
                    j0 = (int) y;
                    j1 = j0 + 1;
                    
                    s1 = x - i0;
                    s0 = 1 - s1;
                    t1 = y - j0;
                    t0 = 1 - t1;
                    
                    uv[index].x = s0 * (t0 * duv[FLUID_IX(i0, j0)].x + t1 * duv[FLUID_IX(i0, j1)].x)
                    + s1 * (t0 * duv[FLUID_IX(i1, j0)].x + t1 * duv[FLUID_IX(i1, j1)].x);
                    uv[index].y = s0 * (t0 * duv[FLUID_IX(i0, j0)].y + t1 * duv[FLUID_IX(i0, j1)].y)
                    + s1 * (t0 * duv[FLUID_IX(i1, j0)].y + t1 * duv[FLUID_IX(i1, j1)].y);
                    
                }
            }
            setBoundary2d(1, uv);
            setBoundary2d(2, uv);
        }
        
        //--------------------------------------------------------------
        void Solver::advectRGB(int bound, const Vec2f* duv) {
            int i0, j0;
            float x, y, s0, t0, s1, t1, dt0x, dt0y;
            int	index;
            
            dt0x = deltaT * _NX;
            dt0y = deltaT * _NY;
            
            for (int j = _NY; j > 0; --j)
            {
                for (int i = _NX; i > 0; --i)
                {
                    index = FLUID_IX(i, j);
                    x = i - dt0x * duv[index].x;
                    y = j - dt0y * duv[index].y;
                    
                    if (x > _NX + 0.5) x = _NX + 0.5f;
                    if (x < 0.5)     x = 0.5f;
                    
                    i0 = (int) x;
                    
                    if (y > _NY + 0.5) y = _NY + 0.5f;
                    if (y < 0.5)     y = 0.5f;
                    
                    j0 = (int) y;
                    
                    s1 = x - i0;
                    s0 = 1 - s1;
                    t1 = y - j0;
                    t0 = 1 - t1;
                    
                    i0 = FLUID_IX(i0, j0);	//we don't need col/row index any more but index in 1 dimension
                    j0 = i0 + (_NX + 2);
                    color[index] = (colorOld[i0] * t0 + colorOld[j0] * t1) * s0 + (colorOld[i0+1] * t0 + colorOld[j0+1] * t1) * s1;
                }
            }
            setBoundaryRGB();
        }
        
        //--------------------------------------------------------------
        void Solver::diffuse(int bound, float* c, float* c0, float diff)
        {
            float a = deltaT * diff * _NX * _NY;	//todo find the exact strategy for using _NX and _NY in the factors
            linearSolver(bound, c, c0, a, 1.0 + 4 * a);
        }
        
        //--------------------------------------------------------------
        void Solver::diffuseRGB(int bound, float diff)
        {
            float a = deltaT * diff * _NX * _NY;
            linearSolverRGB(a, 1.0 + 4 * a);
        }
        
        //--------------------------------------------------------------
        void Solver::diffuseUV(float diff)
        {
            float a = deltaT * diff * _NX * _NY;
            linearSolverUV(a, 1.0 + 4 * a);
        }
        
        //--------------------------------------------------------------
        void Solver::project(Vec2f* xy, Vec2f* pDiv)
        {
            float	h;
            int		index;
            int		step_x = _NX + 2;
            
            h = - 0.5f / _NX;
            for (int j = _NY; j > 0; --j)
            {
                index = FLUID_IX(_NX, j);
                for (int i = _NX; i > 0; --i)
                {
                    pDiv[index].x = h * (xy[index+1].x - xy[index-1].x + xy[index+step_x].y - xy[index-step_x].y);
                    pDiv[index].y = 0;
                    --index;
                }
            }
            
            setBoundary02d(reinterpret_cast<Vec2f*>(&pDiv[0].x));
            setBoundary02d(reinterpret_cast<Vec2f*>(&pDiv[0].y));
            
            linearSolverProject(pDiv);
            
            float fx = 0.5f * _NX;
            float fy = 0.5f * _NY;	//maa	change it from _NX to _NY
            for (int j = _NY; j > 0; --j)
            {
                index = FLUID_IX(_NX, j);
                for (int i = _NX; i > 0; --i)
                {
                    xy[index].x -= fx * (pDiv[index+1].x - pDiv[index-1].x);
                    xy[index].y -= fy * (pDiv[index+step_x].x - pDiv[index-step_x].x);
                    --index;
                }
            }
            
            setBoundary2d(1, xy);
            setBoundary2d(2, xy);
        }
        
        
        //--------------------------------------------------------------
        //	Gauss-Seidel relaxation
        void Solver::linearSolver(int bound, float* __restrict x, const float* __restrict x0, float a, float c)
        {
            int	step_x = _NX + 2;
            int index;
            c = 1. / c;
            for (int k = solverIterations; k > 0; --k)	// MEMO
            {
                for (int j = _NY; j > 0 ; --j)
                {
                    index = FLUID_IX(_NX, j);
                    for (int i = _NX; i > 0 ; --i)
                    {
                        x[index] = ((x[index-1] + x[index+1] + x[index - step_x] + x[index + step_x]) * a + x0[index]) * c;
                        --index;
                    }
                }
                setBoundary(bound, x);
            }
        }
        
        //--------------------------------------------------------------
        void Solver::linearSolverProject(Vec2f* __restrict pdiv)
        {
            int	step_x = _NX + 2;
            int index;
            for (int k = solverIterations; k > 0; --k) {
                for (int j = _NY; j > 0 ; --j) {
                    index = FLUID_IX(_NX, j);
                    float prev = pdiv[index+1].x;
                    for (int i = _NX; i > 0 ; --i)
                    {
                        prev = (pdiv[index-1].x + prev + pdiv[index - step_x].x + pdiv[index + step_x].x + pdiv[index].y) * .25;
                        pdiv[index].x = prev;
                        --index;
                    }
                }
                setBoundary02d(reinterpret_cast<Vec2f*>(&pdiv[0].x));
            }
        }
        
        //--------------------------------------------------------------
        void Solver::linearSolverRGB(float a, float c)
        {
            int index3, index4, index;
            int	step_x = _NX + 2;
            c = 1. / c;
            for (int k = solverIterations; k > 0; --k)	// MEMO
            {           
                for (int j = _NY; j > 0 ; --j)
                {
                    index = FLUID_IX(_NX, j);
                    //index1 = index - 1;		//FLUID_IX(i-1, j);
                    //index2 = index + 1;		//FLUID_IX(i+1, j);
                    index3 = index - step_x;	//FLUID_IX(i, j-1);
                    index4 = index + step_x;	//FLUID_IX(i, j+1);
                    for (int i = _NX; i > 0 ; --i)
                    {	
                        color[index] = ((color[index-1] + color[index+1]  +  color[index3] + color[index4]) * a  +  colorOld[index]) * c;                                
                        --index;
                        --index3;
                        --index4;
                    }
                }
                setBoundaryRGB();	
            }
        }
        
        //--------------------------------------------------------------
        void Solver::linearSolverUV(float a, float c)
        {
            int index;
            int	step_x = _NX + 2;
            c = 1. / c;
            Vec2f* __restrict localUV = uv;
            const Vec2f* __restrict localOldUV = uvOld;
            
            for (int k = solverIterations; k > 0; --k)	// MEMO
            {           
                for (int j = _NY; j > 0 ; --j)
                {
                    index = FLUID_IX(_NX, j);
                    float prevU = localUV[index+1].x;
                    float prevV = localUV[index+1].y;
                    for (int i = _NX; i > 0 ; --i)
                    {
                        prevU = ((localUV[index-1].x + prevU + localUV[index - step_x].x + localUV[index + step_x].x) * a  + localOldUV[index].x) * c;
                        prevV = ((localUV[index-1].y + prevV + localUV[index - step_x].y + localUV[index + step_x].y) * a  + localOldUV[index].y) * c;
                        localUV[index].x = prevU;
                        localUV[index].y = prevV;
                        --index;
                    }
                }
                setBoundary2d(1, uv);
            }
        }
        
        //--------------------------------------------------------------
        void Solver::setBoundary(int bound, float* x)
        {
            int dst1, dst2, src1, src2;
            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);
            
            dst1 = FLUID_IX(0, 1);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(_NX+1, 1);
            src2 = FLUID_IX(_NX, 1);
            if(wrap_x)
                SWAP(src1, src2);
            if(bound == 1 && !wrap_x)
                for (int i = _NY; i > 0; --i)
                {
                    x[dst1] = -x[src1];	dst1 += step;	src1 += step;	
                    x[dst2] = -x[src2];	dst2 += step;	src2 += step;	
                }
            else
                for (int i = _NY; i > 0; --i)
                {
                    x[dst1] = x[src1];	dst1 += step;	src1 += step;	
                    x[dst2] = x[src2];	dst2 += step;	src2 += step;	
                }
            
            dst1 = FLUID_IX(1, 0);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(1, _NY+1);
            src2 = FLUID_IX(1, _NY);
            if(wrap_y)
                SWAP(src1, src2);
            if(bound == 2 && !wrap_y)
                for (int i = _NX; i > 0; --i)
                {
                    x[dst1++] = -x[src1++];	
                    x[dst2++] = -x[src2++];	
                }
            else
                for (int i = _NX; i > 0; --i)
                {
                    x[dst1++] = x[src1++];
                    x[dst2++] = x[src2++];	
                }
            
            x[FLUID_IX(0,   0)] = 0.5f * (x[FLUID_IX(1, 0)] + x[FLUID_IX(0, 1)]);
            x[FLUID_IX(0, _NY+1)] = 0.5f * (x[FLUID_IX(1, _NY+1)] + x[FLUID_IX(0, _NY)]);
            x[FLUID_IX(_NX+1,   0)] = 0.5f * (x[FLUID_IX(_NX, 0)] + x[FLUID_IX(_NX+1, 1)]);
            x[FLUID_IX(_NX+1, _NY+1)] = 0.5f * (x[FLUID_IX(_NX, _NY+1)] + x[FLUID_IX(_NX+1, _NY)]);
        }
        
        //--------------------------------------------------------------
        void Solver::setBoundary02d(Vec2f* x)
        {
            int dst1, dst2, src1, src2;
            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);
            
            dst1 = FLUID_IX(0, 1);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(_NX+1, 1);
            src2 = FLUID_IX(_NX, 1);
            if(wrap_x)
                SWAP(src1, src2);
            for (int i = _NY; i > 0; --i)
            {
                x[dst1].x = x[src1].x;	dst1 += step;	src1 += step;	
                x[dst2].x = x[src2].x;	dst2 += step;	src2 += step;	
            }
            
            dst1 = FLUID_IX(1, 0);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(1, _NY+1);
            src2 = FLUID_IX(1, _NY);
            if(wrap_y)
                SWAP(src1, src2);
            for (int i = _NX; i > 0; --i)
            {
                x[dst1++] = x[src1++];
                x[dst2++] = x[src2++];	
            }
            
            x[FLUID_IX(0,   0)].x = 0.5f * (x[FLUID_IX(1, 0)].x + x[FLUID_IX(0, 1)].x);
            x[FLUID_IX(0, _NY+1)].x = 0.5f * (x[FLUID_IX(1, _NY+1)].x + x[FLUID_IX(0, _NY)].x);
            x[FLUID_IX(_NX+1,   0)].x = 0.5f * (x[FLUID_IX(_NX, 0)].x + x[FLUID_IX(_NX+1, 1)].x);
            x[FLUID_IX(_NX+1, _NY+1)].x = 0.5f * (x[FLUID_IX(_NX, _NY+1)].x + x[FLUID_IX(_NX+1, _NY)].x);
        }
        
        //--------------------------------------------------------------
        void Solver::setBoundary2d(int bound, Vec2f *xy)
        {
            int dst1, dst2, src1, src2;
            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);
            
            dst1 = FLUID_IX(0, 1);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(_NX+1, 1);
            src2 = FLUID_IX(_NX, 1);
            if(wrap_x)
                SWAP(src1, src2);
            if(bound == 1 && !wrap_x)
                for (int i = _NY; i > 0; --i)
                {
                    xy[dst1].x = -xy[src1].x;	dst1 += step;	src1 += step;	
                    xy[dst2].x = -xy[src2].x;	dst2 += step;	src2 += step;	
                }
            else
                for (int i = _NY; i > 0; --i)
                {
                    xy[dst1].x = xy[src1].x;	dst1 += step;	src1 += step;	
                    xy[dst2].x = xy[src2].x;	dst2 += step;	src2 += step;	
                }
            
            dst1 = FLUID_IX(1, 0);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(1, _NY+1);
            src2 = FLUID_IX(1, _NY);
            if(wrap_y)
                SWAP(src1, src2);
            if(bound == 2 && !wrap_y)
                for (int i = _NX; i > 0; --i)
                {
                    xy[dst1++].y = -xy[src1++].y;	
                    xy[dst2++].y = -xy[src2++].y;	
                }
            else
                for (int i = _NX; i > 0; --i)
                {
                    xy[dst1++].y = xy[src1++].y;
                    xy[dst2++].y = xy[src2++].y;	
                }
            
            xy[FLUID_IX(0,   0)][bound-1] = 0.5f * (xy[FLUID_IX(1, 0)][bound-1] + xy[FLUID_IX(0, 1)][bound-1]);
            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]);
            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]);
            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]);
        }
        
        //#define CPY_RGB(d, s)		{	r[d] = r[s];	g[d] = g[s];	b[d] = b[s]; }
        //#define CPY_RGB_NEG(d, s)	{	r[d] = -r[s];	g[d] = -g[s];	b[d] = -b[s]; }
        
        //--------------------------------------------------------------
        void Solver::setBoundaryRGB()
        {
            int dst1, dst2, src1, src2;
            int step = FLUID_IX(0, 1) - FLUID_IX(0, 0);
            
            dst1 = FLUID_IX(0, 1);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(_NX+1, 1);
            src2 = FLUID_IX(_NX, 1);
            if(wrap_x)
                SWAP(src1, src2);
            for (int i = _NY; i > 0; --i)
            {
                color[dst1] = color[src1];
                dst1 += step;
                src1 += step;	
                
                color[dst2] = color[src2];
                dst2 += step;
                src2 += step;	
            }
            
            dst1 = FLUID_IX(1, 0);
            src1 = FLUID_IX(1, 1);
            dst2 = FLUID_IX(1, _NY+1);
            src2 = FLUID_IX(1, _NY);
            if(wrap_y)
                SWAP(src1, src2);
            for (int i = _NX; i > 0; --i)
            {
                color[dst1] = color[src1];
                ++dst1;
                ++src1;	
                
                color[dst2] = color[src2];
                ++dst2;
                ++src2;	
            }
		}
		
        
        //--------------------------------------------------------------
        void Solver::randomizeColor() {
            for (int i = getWidth()-1; i > 0; --i)
            {
                for (int j = getHeight()-1; j > 0; --j)
                {
                    int index = FLUID_IX(i, j);
                    color[index] = Vec3f(Rand::randFloat(), Rand::randFloat(), Rand::randFloat());
                    density[index] = Rand::randFloat();
                }
            }
        }
        
    }
}


================================================
FILE: src/MSAFluidSolver.h
================================================
/***********************************************************************
 
 This class is for the actual solver (doesn't draw anything)
 
 ************************************************************************/

#pragma once

#include "MSACore.h"

namespace msa {
	namespace fluid {
        
        // do not change these values, you can override them using the solver methods
#define		FLUID_DEFAULT_NX					100
#define		FLUID_DEFAULT_NY					100
#define     FLUID_DEFAULT_DT					0.04f	//Maa	25fps
#define		FLUID_DEFAULT_VISC					0.0001f
#define     FLUID_DEFAULT_COLOR_DIFFUSION		0.0f
#define     FLUID_DEFAULT_FADESPEED				0.03f
#define		FLUID_DEFAULT_SOLVER_ITERATIONS		10
        
#define		FLUID_IX(i, j)		((i) + (_NX + 2)  *(j))
        
        class Solver {
        public:
            Solver();
            virtual ~Solver();
            
            Solver& setup(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);
            Solver& setSize(int NX = FLUID_DEFAULT_NX, int NY = FLUID_DEFAULT_NY);
            
            // solve one step of the fluid solver
            void update();
            
            // clear all forces in fluid and reset
            void reset();
            
            // get fluid cell index for cell coordinates or normalized position
            inline int getIndexForCell(int i, int j) const;
            inline int getIndexForPos(const Vec2f &pos) const;
            
            
            // get color and/or vel at any point in the fluid.
            // pass pointers to Vec2f (for velocity) and Color (for color) and they get filled with the info
            // leave any pointer NULL if you don't want that info
            inline void getInfoAtIndex(int index, Vec2f *vel, Color *color = NULL) const;
            inline void getInfoAtCell(int i, int j, Vec2f *vel, Color *color = NULL) const;
            inline void getInfoAtPos(const Vec2f &pos, Vec2f *vel, Color *color = NULL) const;
            
            
            // get just velocity
            inline Vec2f getVelocityAtIndex(int index) const;
            inline Vec2f getVelocityAtCell(int i, int j) const;
            inline Vec2f getVelocityAtPos(const Vec2f &pos) const;
            
            
            // get just color
            inline Color getColorAtIndex(int index) const;
            inline Color getColorAtCell(int i, int j) const;
            inline Color getColorAtPos(const Vec2f &pos) const;
            
            
            // add force (at cell index, cell coordinates, or normalized position)
            inline void addForceAtIndex(int index, const Vec2f &force);
            inline void addForceAtCell(int i, int j, const Vec2f &force);
            inline void addForceAtPos(const Vec2f &pos, const Vec2f &force);
            
            
            // add color (at cell index, cell coordinates, or normalized position)
            inline void addColorAtIndex(int index, const Color &color);
            inline void addColorAtCell(int i, int j, const Color &color);
            inline void addColorAtPos(const Vec2f &pos, const Color &color);
            
            
            // fill with random color at every cell
            void randomizeColor();
            
            // return number of cells and dimensions
            int getNumCells() const;
            int getWidth() const;
            int getHeight() const;
            float getInvWidth() const;
            float getInvHeight() const;
            Vec2f getSize();
            Vec2f getInvSize();
            
            bool isInited() const;
            
            // accessors for  viscocity, it will lerp to the target at lerpspeed
            Solver& setVisc(float newVisc);
            float getVisc() const;
            
            // accessors for  color diffusion
            // if diff == 0, color diffusion is not performed
            // ** COLOR DIFFUSION IS SLOW!
            Solver& setColorDiffusion(float diff);
            float	getColorDiffusion();
            
            Solver& enableRGB(bool isRGB);
            Solver& setDeltaT(float deltaT = FLUID_DEFAULT_DT);
            Solver& setFadeSpeed(float fadeSpeed = FLUID_DEFAULT_FADESPEED);
            Solver& setSolverIterations(int solverIterations = FLUID_DEFAULT_SOLVER_ITERATIONS);
            Solver& enableVorticityConfinement(bool b);
            bool getVorticityConfinement();
            Solver& setWrap(bool bx, bool by);
            
            // returns average density of fluid
            float getAvgDensity() const;
            
            // returns average _uniformity
            float getUniformity() const;
            
            // returns average speed of fluid
            float getAvgSpeed() const;
            
            // allocate an array large enough to hold information for u, v, r, g, OR b
            float* alloc()	{ return new float[_numCells];	}
            
            
            float	*density, *densityOld;		// used if not RGB
            Vec3f	*color, *colorOld;			// used for RGB
            Vec2f	*uv, *uvOld;
            
            float	*curl;
            
            bool	doRGB;				// for monochrome, update only density
            bool	doVorticityConfinement;
            int		solverIterations;
            
            float	colorDiffusion;
            float	viscocity;
            float	fadeSpeed;
            float	deltaT;
            bool	wrap_x;
            bool	wrap_y;
            
        protected:
            
            float width;
            float height;
            float invWidth;
            float invHeight;
            
            int		_NX, _NY, _numCells;
            float	_invNX, _invNY, _invNumCells;
            bool	_isInited;
            float	*_tmp;
            
            float	_avgDensity;			// this will hold the average color of the last frame (how full it is)
            float	_uniformity;			// this will hold the _uniformity of the last frame (how uniform the color is);
            float	_avgSpeed;
            
            void	destroy();
            
            inline	float	calcCurl(int i, int j);
            void	vorticityConfinement(Vec2f *Fvc_xy);
            
            template<typename T>
            void	addSource(T *x, T *x0);
            
            void	advect(int b, float *d, const float *d0, const Vec2f *duv);
            void	advect2d(Vec2f *uv, const Vec2f *duv);
            void	advectRGB(int b, const Vec2f *duv);
            
            void	diffuse(int b, float *c, float *c0, float diff);
            void	diffuseRGB(int b, float diff);
            void	diffuseUV(float diff);
            
            void	project(Vec2f *xy, Vec2f *pDiv);
            void	linearSolver(int b, float *x, const float *x0, float a, float c);
            void	linearSolverProject(Vec2f *pdiv);
            void	linearSolverRGB(float a, float c);
            void	linearSolverUV(float a, float c);
            
            void	setBoundary(int b, float *x);
            void	setBoundary02d(Vec2f* x);
            void	setBoundary2d(int b, Vec2f *xy);
            void	setBoundaryRGB();
            
            void	fadeDensity();
            void	fadeRGB();
        };
        
        
        //-------- get index
        inline int Solver::getIndexForCell(int i, int j) const {
            i = clamp(i, 1, _NX);
            j = clamp(j, 1, _NY);
            return FLUID_IX(i, j);
        }
        
        inline int Solver::getIndexForPos(const Vec2f &pos) const {
            return getIndexForCell((int)floor(pos.x * width), (int)floor(pos.y * height));
        }
        
        
        
        //-------- get info
        inline	void Solver::getInfoAtIndex(int index, Vec2f *vel, Color *color) const {
            if(vel) *vel = getVelocityAtIndex(index);
            if(color) *color = getColorAtIndex(index);
        }
        
        inline void Solver::getInfoAtCell(int i, int j, Vec2f *vel, Color *color) const {
            getInfoAtIndex(getIndexForCell(i, j), vel, color);
        }
        
        
        inline void Solver::getInfoAtPos(const Vec2f &pos, Vec2f *vel, Color *color) const {
            getInfoAtIndex(getIndexForPos(pos), vel, color);
        }
        
        
        //-------- get velocity
        inline Vec2f Solver::getVelocityAtIndex(int index) const {
            return uv[index];
        }
        
        inline Vec2f Solver::getVelocityAtCell(int i, int j) const {
            return getVelocityAtIndex(getIndexForCell(i, j));
        }
        
        inline Vec2f Solver::getVelocityAtPos(const Vec2f &pos) const {
            return getVelocityAtIndex(getIndexForPos(pos));
        }
        
        
        //-------- get color
        inline Color Solver::getColorAtIndex(int index) const {
            if(doRGB) {
                return Color(this->color[index].x, this->color[index].y, this->color[index].z);
            } else {
                return Color(density[index], density[index], density[index]);
            }
        }
        
        inline Color Solver::getColorAtCell(int i, int j) const {
            return getColorAtIndex(getIndexForCell(i, j));
        }
        
        inline Color Solver::getColorAtPos(const Vec2f &pos) const {
            return getColorAtIndex(getIndexForPos(pos));
        }
        
        
        //-------- add force
        inline void Solver::addForceAtIndex(int index, const Vec2f &force) {
            uv[index] += force;
        }
        
        inline void Solver::addForceAtCell(int i, int j, const Vec2f &force) {
            addForceAtIndex(getIndexForCell(i, j), force);
        }
        
        inline void Solver::addForceAtPos(const Vec2f &pos, const Vec2f &force) {
            addForceAtIndex(getIndexForPos(pos), force);
        }
        
        
        //-------- add color
        inline void Solver::addColorAtIndex(int index, const Color &color) {
            if(doRGB) {
                colorOld[index] += Vec3f(color.r, color.g, color.b);
            } else {
                density[index] += color.r;
            }
        }
        
        inline void Solver::addColorAtCell(int i, int j, const Color &color) {
            addColorAtIndex(getIndexForCell(i, j), color);
        }
        
        inline void Solver::addColorAtPos(const Vec2f &pos, const Color &color) {
            addColorAtIndex(getIndexForPos(pos), color);
        }
        
        template<typename T>
        void Solver::addSource(T *x, T *x0) {
            for(int i = _numCells-1; i >=0; --i) {
                x[i] += x0[i] * deltaT;
            }
        }
    }
}
Download .txt
gitextract_0z8_2c1k/

├── .gitignore
├── README.md
├── addon_config.mk
├── example/
│   ├── Makefile
│   ├── addons.make
│   ├── config.make
│   ├── example.qbs
│   ├── example.sln
│   ├── example.vcxproj
│   └── src/
│       ├── Particle.cpp
│       ├── Particle.h
│       ├── ParticleSystem.cpp
│       ├── ParticleSystem.h
│       ├── main.cpp
│       ├── testApp.cpp
│       └── testApp.h
├── license.md
└── src/
    ├── MSAFluid.h
    ├── MSAFluidDrawerBase.cpp
    ├── MSAFluidDrawerBase.h
    ├── MSAFluidDrawerGl-Cinder.h
    ├── MSAFluidDrawerGl-OF.h
    ├── MSAFluidParticleUpdater.h
    ├── MSAFluidSolver.cpp
    └── MSAFluidSolver.h
Download .txt
SYMBOL INDEX (30 symbols across 11 files)

FILE: example/src/Particle.h
  function class (line 15) | class Particle {

FILE: example/src/ParticleSystem.h
  function class (line 15) | class ParticleSystem {

FILE: example/src/main.cpp
  function main (line 4) | int main( ){

FILE: example/src/testApp.h
  function class (line 30) | class testApp : public ofBaseApp {

FILE: src/MSAFluidDrawerBase.cpp
  type msa (line 10) | namespace msa {
    type fluid (line 11) | namespace fluid {
      function Solver (line 51) | Solver* DrawerBase::setup(int NX, int NY) {
      function Solver (line 63) | Solver* DrawerBase::setup(Solver* f) {
      function Solver (line 73) | Solver* DrawerBase::getFluidSolver() {
      function DrawMode (line 141) | DrawMode DrawerBase::getDrawMode() {
      function string (line 146) | string DrawerBase::getDrawModeName() {

FILE: src/MSAFluidDrawerBase.h
  function namespace (line 12) | namespace msa {

FILE: src/MSAFluidDrawerGl-Cinder.h
  function namespace (line 42) | namespace msa {

FILE: src/MSAFluidDrawerGl-OF.h
  function namespace (line 11) | namespace msa {

FILE: src/MSAFluidParticleUpdater.h
  function namespace (line 15) | namespace msa {

FILE: src/MSAFluidSolver.cpp
  type msa (line 9) | namespace msa {
    type fluid (line 10) | namespace fluid {
      function Solver (line 25) | Solver& Solver::setSize(int NX, int NY)
      function Solver (line 46) | Solver& Solver::setup(int NX, int NY)
      function Solver (line 62) | Solver&  Solver::setDeltaT(float deltaT) {
      function Solver (line 68) | Solver&  Solver::setFadeSpeed(float fadeSpeed) {
      function Solver (line 74) | Solver&  Solver::setSolverIterations(int solverIterations) {
      function Solver (line 82) | Solver&  Solver::enableRGB(bool doRGB) {
      function Solver (line 88) | Solver&  Solver::enableVorticityConfinement(bool b) {
      function Solver (line 99) | Solver& Solver::setWrap(bool bx, bool by) {
      function Vec2f (line 182) | Vec2f Solver::getSize() {
      function Vec2f (line 187) | Vec2f Solver::getInvSize() {
      function Solver (line 194) | Solver& Solver::setVisc(float newVisc) {
      function Solver (line 206) | Solver& Solver::setColorDiffusion(float diff)

FILE: src/MSAFluidSolver.h
  function namespace (line 11) | namespace msa {
Condensed preview — 25 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (124K chars).
[
  {
    "path": ".gitignore",
    "chars": 2756,
    "preview": "#########################\n# openFrameworks patterns\n#########################\n\n# build files\nopenFrameworks.a\nopenFramew"
  },
  {
    "path": "README.md",
    "chars": 2818,
    "preview": "ofxMSAFluid\n=====================================\n\nIntroduction\n------------\nC++ openFrameworks addon for solving and dr"
  },
  {
    "path": "addon_config.mk",
    "chars": 359,
    "preview": "meta:\n\tADDON_NAME = ofxMSAFluid\n\tADDON_DESCRIPTION = C++ openFrameworks addon for Stam style Fluid Solver\n\tADDON_AUTHOR "
  },
  {
    "path": "example/Makefile",
    "chars": 391,
    "preview": "# Attempt to load a config.make file.\n# If none is found, project defaults in config.project.make will be used.\nifneq ($"
  },
  {
    "path": "example/addons.make",
    "chars": 78,
    "preview": "ofxMSACore\nofxMSAFluid\nofxMSAInteractiveObject\nofxSimpleGuiToo\nofxXmlSettings\n"
  },
  {
    "path": "example/config.make",
    "chars": 6504,
    "preview": "################################################################################\n# CONFIGURE PROJECT MAKEFILE (optional)"
  },
  {
    "path": "example/example.qbs",
    "chars": 2359,
    "preview": "import qbs\nimport qbs.Process\nimport qbs.File\nimport qbs.FileInfo\nimport qbs.TextFile\nimport \"../../../libs/openFramewor"
  },
  {
    "path": "example/example.sln",
    "chars": 2012,
    "preview": "Microsoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91"
  },
  {
    "path": "example/example.vcxproj",
    "chars": 17341,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microso"
  },
  {
    "path": "example/src/Particle.cpp",
    "chars": 2410,
    "preview": "/*\n *  Particle.cpp\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Lt"
  },
  {
    "path": "example/src/Particle.h",
    "chars": 582,
    "preview": "/*\n *  Particle.h\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visuals Ltd."
  },
  {
    "path": "example/src/ParticleSystem.cpp",
    "chars": 1410,
    "preview": "/*\n *  ParticleSystem.cpp\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visu"
  },
  {
    "path": "example/src/ParticleSystem.h",
    "chars": 616,
    "preview": "/*\n *  ParticleSystem.h\n *  ofxMSAFluid Demo\n *\n *  Created by Mehmet Akten on 02/05/2009.\n *  Copyright 2009 MSA Visual"
  },
  {
    "path": "example/src/main.cpp",
    "chars": 136,
    "preview": "\n#include \"testApp.h\"\n\nint main( ){\n\tofSetupOpenGL(1024, 768, OF_WINDOW);\t\t\t// <-------- setup the GL context\n\tofRunApp("
  },
  {
    "path": "example/src/testApp.cpp",
    "chars": 6140,
    "preview": "#include \"testApp.h\"\n\n\nfloat tuioXScaler = 1;\nfloat tuioYScaler = 1;\n\n//------------------------------------------------"
  },
  {
    "path": "example/src/testApp.h",
    "chars": 1736,
    "preview": "#pragma once\n\n#include \"MSAFluid.h\"\n//#include \"MSATimer.h\"\n#include \"ParticleSystem.h\"\n\n#include \"ofMain.h\"\n\n// comment"
  },
  {
    "path": "license.md",
    "chars": 1442,
    "preview": "The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_lice"
  },
  {
    "path": "src/MSAFluid.h",
    "chars": 194,
    "preview": "#pragma once\n\n#include \"MSAFluidSolver.h\"\n\n#if defined( MSA_HOST_OPENFRAMEWORKS )\n#include \"MSAFluidDrawerGl-OF.h\"\n\n#eli"
  },
  {
    "path": "src/MSAFluidDrawerBase.cpp",
    "chars": 13906,
    "preview": "/***********************************************************************\n \n This class is for drawing a fluidsolver usin"
  },
  {
    "path": "src/MSAFluidDrawerBase.h",
    "chars": 3279,
    "preview": "/***********************************************************************\n \n This class is for drawing a fluidsolver usin"
  },
  {
    "path": "src/MSAFluidDrawerGl-Cinder.h",
    "chars": 2919,
    "preview": "/***********************************************************************\n \n This class is for drawing a fluidsolver usin"
  },
  {
    "path": "src/MSAFluidDrawerGl-OF.h",
    "chars": 1478,
    "preview": "/***********************************************************************\n \n This class is for drawing a fluidsolver usin"
  },
  {
    "path": "src/MSAFluidParticleUpdater.h",
    "chars": 917,
    "preview": "/***********************************************************************\n \n This class interfaces the fluid solver with "
  },
  {
    "path": "src/MSAFluidSolver.cpp",
    "chars": 34959,
    "preview": "/***********************************************************************\n \n This class is for the actual solver (doesn't"
  },
  {
    "path": "src/MSAFluidSolver.h",
    "chars": 10624,
    "preview": "/***********************************************************************\n \n This class is for the actual solver (doesn't"
  }
]

About this extraction

This page contains the full source code of the memo/ofxMSAFluid GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 25 files (114.6 KB), approximately 29.9k tokens, and a symbol index with 30 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!