Added initial Smoothed Particle Hydrodynamics implementation (SPH), for CPU and CUDA.
This software is contributed under the ZLib license by Rama Hoetzlein, http://www.rchoetzlein.com We plan to integrate the SPH into the core Bullet library, including interaction with rigid bodies and soft bodies.
This commit is contained in:
443
Extras/sph/common/geomx.cpp
Normal file
443
Extras/sph/common/geomx.cpp
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
FLUIDS v.1 - SPH Fluid Simulator for CPU and GPU
|
||||
Copyright (C) 2008. Rama Hoetzlein, http://www.rchoetzlein.com
|
||||
|
||||
ZLib license
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
#include <vector.h>
|
||||
#include "geomx.h"
|
||||
#include "mdebug.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
GeomX::GeomX ()
|
||||
{
|
||||
mHeap = 0x0;
|
||||
}
|
||||
|
||||
void GeomX::FreeBuffers ()
|
||||
{
|
||||
for (int n=0; n < (int) mBuf.size(); n++) {
|
||||
free ( mBuf[n].data );
|
||||
mBuf[n].data = 0x0;
|
||||
}
|
||||
mBuf.clear ();
|
||||
|
||||
if ( mHeap != 0x0 ) free ( mHeap );
|
||||
mHeap = 0x0;
|
||||
mHeapNum = 0;
|
||||
mHeapMax = 0;
|
||||
}
|
||||
|
||||
void GeomX::ResetHeap ()
|
||||
{
|
||||
mHeapNum = 0;
|
||||
mHeapFree = -1;
|
||||
}
|
||||
|
||||
int GeomX::GetSize ()
|
||||
{
|
||||
int sum = mHeapNum * sizeof(hval) ;
|
||||
for (int n=0; n < (int) mBuf.size(); n++)
|
||||
sum += mBuf[n].size;
|
||||
sum += (int) mAttribute.size() * sizeof(GeomAttr);
|
||||
return sum;
|
||||
}
|
||||
|
||||
void GeomX::ClearAttributes ()
|
||||
{
|
||||
mAttribute.clear ();
|
||||
}
|
||||
|
||||
int GeomX::CopyBuffer ( uchar bdest, uchar bsrc, GeomX& src )
|
||||
{
|
||||
if ( bsrc >= src.GetNumBuf() ) return -1;
|
||||
|
||||
if ( bdest >= GetNumBuf() ) {
|
||||
for (int n=0; n <= bdest - GetNumBuf(); n++ )
|
||||
AddBuffer ( 0, 0, 0 );
|
||||
}
|
||||
if ( mBuf[bdest].data != 0x0 ) {
|
||||
free ( mBuf[bdest].data );
|
||||
mBuf[bdest].data = 0x0;
|
||||
}
|
||||
|
||||
GeomBuf* buf = src.GetBuffer( bsrc );
|
||||
mBuf[bdest].dtype = buf->dtype;
|
||||
mBuf[bdest].max = buf->max;
|
||||
mBuf[bdest].num = buf->num;
|
||||
mBuf[bdest].stride = buf->stride;
|
||||
mBuf[bdest].size = buf->size;
|
||||
mBuf[bdest].data = (char*) malloc ( mBuf[bdest].max * mBuf[bdest].stride );
|
||||
memcpy ( mBuf[bdest].data, buf->data, mBuf[bdest].num * mBuf[bdest].stride );
|
||||
|
||||
return bdest;
|
||||
}
|
||||
|
||||
|
||||
void GeomX::CopyBuffers ( GeomX& src )
|
||||
{
|
||||
FreeBuffers ();
|
||||
for (int n = 0; n < src.GetNumBuf(); n++)
|
||||
CopyBuffer ( n, n, src );
|
||||
CopyHeap ( src );
|
||||
}
|
||||
|
||||
void GeomX::CopyHeap ( GeomX& src )
|
||||
{
|
||||
hpos num, max, freepos;
|
||||
hval* src_data = src.GetHeap ( num, max, freepos );
|
||||
|
||||
if ( mHeap != 0x0 ) {
|
||||
free ( mHeap );
|
||||
mHeap = 0x0;
|
||||
}
|
||||
|
||||
mHeap = (hval*) malloc ( max * sizeof(hval) );
|
||||
mHeapMax = max;
|
||||
mHeapNum = num;
|
||||
mHeapFree = freepos;
|
||||
|
||||
memcpy ( mHeap, src_data, mHeapNum * sizeof(hval) );
|
||||
}
|
||||
|
||||
hval* GeomX::GetHeap ( hpos& num, hpos& max, hpos& free )
|
||||
{
|
||||
num = mHeapNum;
|
||||
max = mHeapMax;
|
||||
free = mHeapFree;
|
||||
return mHeap;
|
||||
}
|
||||
|
||||
void GeomX::CopyAttributes ( GeomX& src )
|
||||
{
|
||||
GeomAttr* attr;
|
||||
ClearAttributes ();
|
||||
int a;
|
||||
for (int n = 0; n < src.GetNumAttr(); n++) {
|
||||
attr = src.GetAttribute ( n );
|
||||
a = AddAttribute ( (uchar) attr->buf, attr->name, attr->stride, false );
|
||||
mAttribute[a].offset = attr->offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GeomX::AddHeap ( int max )
|
||||
{
|
||||
mHeap = (hval*) malloc ( max * sizeof(hval ) );
|
||||
mHeapMax = max;
|
||||
mHeapNum = 0;
|
||||
mHeapFree = -1;
|
||||
}
|
||||
|
||||
int GeomX::AddAttribute ( uchar b, std::string name, ushort stride )
|
||||
{
|
||||
return AddAttribute ( b, name, stride, true );
|
||||
}
|
||||
|
||||
int GeomX::AddAttribute ( uchar b, std::string name, ushort stride, bool bExtend )
|
||||
{
|
||||
GeomBuf* buf = &mBuf[b];
|
||||
GeomAttr attr;
|
||||
|
||||
attr.buf = b;
|
||||
attr.name = name;
|
||||
attr.offset = buf->stride;
|
||||
attr.stride = stride;
|
||||
|
||||
if ( bExtend ) {
|
||||
int new_stride = buf->stride + attr.stride;
|
||||
char* new_data = (char*) malloc ( buf->max * new_stride );
|
||||
char* old_data = buf->data;
|
||||
for (int n=0; n < buf->num; n++) {
|
||||
memcpy ( new_data, old_data, buf->stride );
|
||||
old_data += buf->stride;
|
||||
new_data += new_stride;
|
||||
}
|
||||
free ( buf->data );
|
||||
buf->data = new_data;
|
||||
buf->stride = new_stride;
|
||||
}
|
||||
mAttribute.push_back ( attr );
|
||||
return (int) mAttribute.size()-1;
|
||||
}
|
||||
|
||||
int GeomX::GetAttribute ( std::string name )
|
||||
{
|
||||
for (int n=0; n < (int) mAttribute.size(); n++) {
|
||||
if ( mAttribute[n].name.compare ( name ) == 0 )
|
||||
return n;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GeomX::GetAttrOffset ( std::string name )
|
||||
{
|
||||
for (int n=0; n < (int) mAttribute.size(); n++) {
|
||||
if ( mAttribute[n].name.compare ( name ) == 0 )
|
||||
return mAttribute[n].offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GeomX::AddBuffer ( uchar typ, ushort stride, int max )
|
||||
{
|
||||
GeomBuf buf;
|
||||
buf.dtype = typ;
|
||||
buf.stride = stride;
|
||||
buf.max = max;
|
||||
buf.num = 0;
|
||||
buf.size = 0;
|
||||
buf.data = (char*) malloc ( buf.max * buf.stride );
|
||||
mBuf.push_back ( buf );
|
||||
return (int) mBuf.size()-1;
|
||||
}
|
||||
void GeomX::ResetBuffer ( uchar b, int n )
|
||||
{
|
||||
mBuf[b].max = n;
|
||||
|
||||
if ( mBuf[b].data != 0x0 ) free ( mBuf[b].data );
|
||||
|
||||
char* new_data = (char*) malloc ( mBuf[b].max * mBuf[b].stride );
|
||||
|
||||
mBuf[b].data = new_data;
|
||||
|
||||
mBuf[b].num = 0;
|
||||
mBuf[b].size = mBuf[b].num*mBuf[b].stride;
|
||||
}
|
||||
|
||||
char* GeomX::AddElem ( uchar b, href& ndx )
|
||||
{
|
||||
if ( mBuf[b].num >= mBuf[b].max ) {
|
||||
if ( long(mBuf[b].max) * 2 > ELEM_MAX ) {
|
||||
error.PrintF ( "geom", "Maximum number of elements reached.\n" );
|
||||
error.Exit ();
|
||||
}
|
||||
mBuf[b].max *= 2;
|
||||
char* new_data = (char*) malloc ( mBuf[b].max * mBuf[b].stride );
|
||||
memcpy ( new_data, mBuf[b].data, mBuf[b].num*mBuf[b].stride );
|
||||
free ( mBuf[b].data );
|
||||
mBuf[b].data = new_data;
|
||||
}
|
||||
mBuf[b].num++;
|
||||
mBuf[b].size += mBuf[b].stride;
|
||||
ndx = mBuf[b].num-1;
|
||||
return mBuf[b].data + ndx*mBuf[b].stride;
|
||||
}
|
||||
|
||||
char* GeomX::RandomElem ( uchar b, href& ndx )
|
||||
{
|
||||
ndx = mBuf[b].num * rand() / RAND_MAX;
|
||||
return mBuf[b].data + ndx*mBuf[b].stride;
|
||||
}
|
||||
|
||||
int GeomX::AddElem ( uchar b, char* data )
|
||||
{
|
||||
if ( mBuf[b].num >= mBuf[b].max ) {
|
||||
mBuf[b].max *= 2;
|
||||
char* new_data = (char*) malloc ( mBuf[b].max * mBuf[b].stride );
|
||||
memcpy ( new_data, mBuf[b].data, mBuf[b].num*mBuf[b].stride );
|
||||
free ( mBuf[b].data );
|
||||
mBuf[b].data = new_data;
|
||||
}
|
||||
memcpy ( mBuf[b].data + mBuf[b].num*mBuf[b].stride, data, mBuf[b].stride );
|
||||
mBuf[b].num++;
|
||||
mBuf[b].size += mBuf[b].stride;
|
||||
return mBuf[b].num-1;
|
||||
}
|
||||
|
||||
bool GeomX::DelElem ( uchar b, int n )
|
||||
{
|
||||
if ( n >= 0 && n < mBuf[b].num ) {
|
||||
memcpy ( mBuf[b].data + n*mBuf[b].stride, mBuf[b].data + (mBuf[b].num-1)*mBuf[b].stride, mBuf[b].stride );
|
||||
mBuf[b].num--;
|
||||
mBuf[b].size -= mBuf[b].stride;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hpos GeomX::HeapExpand ( ushort size, ushort& ret )
|
||||
{
|
||||
mHeapMax *= 2;
|
||||
if ( mHeapMax > HEAP_MAX ) {
|
||||
error.PrintF ( "geom", "Geom heap size exceeds range of index.\n" );
|
||||
error.Exit ();
|
||||
}
|
||||
hval* pNewHeap = (hval*) malloc ( mHeapMax * sizeof(hval) );
|
||||
if ( pNewHeap == 0x0 ) {
|
||||
error.PrintF ( "geom", "Geom heap out of memory.\n" );
|
||||
error.Exit ();
|
||||
}
|
||||
memcpy ( pNewHeap, mHeap, mHeapNum*sizeof(hval) );
|
||||
free ( mHeap );
|
||||
mHeap = pNewHeap;
|
||||
ret = size;
|
||||
assert ( mHeapNum >= 0 && mHeapNum < mHeapMax );
|
||||
return mHeapNum;
|
||||
}
|
||||
|
||||
#define LIST_INIT 4
|
||||
|
||||
hpos GeomX::HeapAlloc ( ushort size, ushort& ret )
|
||||
{
|
||||
hval* pPrev = 0x0;
|
||||
hval* pCurr = mHeap + mHeapFree;
|
||||
hpos pos = -1;
|
||||
|
||||
if ( mHeapNum + size < mHeapMax ) {
|
||||
// Heap not yet full.
|
||||
pos = mHeapNum;
|
||||
ret = size;
|
||||
mHeapNum += size;
|
||||
} else {
|
||||
// Heap full, search free space
|
||||
if ( mHeapFree == -1 ) {
|
||||
pos = HeapExpand ( size, ret );
|
||||
mHeapNum += ret;
|
||||
} else {
|
||||
while ( *pCurr < size && pCurr != mHeap-1 ) {
|
||||
pPrev = pCurr;
|
||||
pCurr = mHeap + * (hpos*) (pCurr + FPOS);
|
||||
}
|
||||
if ( pCurr != mHeap-1 ) {
|
||||
// Found free space.
|
||||
if ( pPrev == 0x0 ) {
|
||||
mHeapFree = * (hpos*) (pCurr + FPOS);
|
||||
assert ( mHeapFree >= -1 );
|
||||
} else {
|
||||
* (hpos*) (pPrev+FPOS) = * (hpos*) (pCurr+FPOS);
|
||||
}
|
||||
pos = pCurr-mHeap;
|
||||
ret = *pCurr;
|
||||
} else {
|
||||
// Heap full, no free space. Expand heap.
|
||||
pos = HeapExpand ( size, ret );
|
||||
mHeapNum += ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert ( pos >= 0 && pos <= mHeapNum );
|
||||
memset ( mHeap+pos, 0, size*sizeof(hval) );
|
||||
return pos;
|
||||
}
|
||||
|
||||
void GeomX::HeapAddFree ( hpos pos, int size )
|
||||
{
|
||||
// memset ( mHeap+pos, 0xFF, size*sizeof(hval) );
|
||||
|
||||
if ( pos < mHeapFree || mHeapFree == -1 ) {
|
||||
// Lowest position. Insert at head of heap.
|
||||
* (hpos*) (mHeap+pos) = size;
|
||||
* (hpos*) (mHeap+pos + FPOS) = mHeapFree;
|
||||
mHeapFree = pos;
|
||||
if ( mHeapFree != -1 && *(hpos*) (mHeap+mHeapFree+FPOS) == 0x0 ) { error.PrintF ( "geomx", "ERROR: Heap pointer 0. pHeapFree, %d\n", pos ); error.Exit (); }
|
||||
|
||||
assert ( mHeapFree >= -1 );
|
||||
} else {
|
||||
hval* pCurr = mHeap + pos;
|
||||
hval* pPrev = 0x0;
|
||||
hval* pNext = mHeap + mHeapFree;
|
||||
|
||||
if ( pCurr == pNext ) { // Freeing the first block
|
||||
mHeapFree = * (hpos*) (pCurr + FPOS);
|
||||
* (hpos*) (mHeap+mHeapFree + FPOS) = 0xFFFFFFFF;
|
||||
* (hpos*) (pCurr + FPOS) = 0xFFFFFFFF;
|
||||
* (hpos*) pCurr = 0xFFFFFFFF;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// Find first block greater than new free pos.
|
||||
while ( pNext < pCurr && pNext != mHeap-1 ) {
|
||||
pPrev = pNext;
|
||||
pNext = mHeap + * (hpos*) (pNext + FPOS);
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
if ( pPrev + *(pPrev) == pCurr ) { // Prev block touches current one (expand previous)
|
||||
* (hpos*) pPrev += size; // - prev.size = prev.size + curr.size
|
||||
x=1;
|
||||
|
||||
} else if ( pCurr + size == pNext && pNext != mHeap-1 ) { // Curr block touches next one (expand current block)
|
||||
* (hpos*) (pPrev + FPOS) = pos; // - prev.next = curr
|
||||
* (hpos*) (pCurr + FPOS) = * (hpos*) (pNext + FPOS); // - curr.next = next.next
|
||||
* (hpos*) pCurr = size + * (hpos*) pNext; // - curr.size = size + next.size
|
||||
* (hpos*) (pNext) = 0xFFFFFFFF; // - curr = null
|
||||
* (hpos*) (pNext + FPOS) = 0xFFFFFFFF; // - curr.next = null
|
||||
x=2;
|
||||
|
||||
} else { // Otherwise (linked list insert)
|
||||
* (hpos*) (pPrev + FPOS) = pos; // - prev.next = curr
|
||||
if ( pNext != mHeap-1 )
|
||||
* (hpos*) (pCurr + FPOS) = pNext - mHeap; // - curr.next = next
|
||||
else
|
||||
* (hpos*) (pCurr + FPOS) = 0xFFFFFFFF; // - curr.next = null (no next node)
|
||||
* (hpos*) pCurr = size; // - curr.size = size
|
||||
x=3;
|
||||
}
|
||||
if ( pCurr !=mHeap-1 && *(hpos*) (pCurr+FPOS) == 0x0 ) { error.PrintF ( "geomx", "ERROR: Heap pointer 0. pCurr, %d, %d\n", x, pos ); error.Exit (); }
|
||||
if ( pPrev !=mHeap-1 && *(hpos*) (pPrev+FPOS) == 0x0 ) { error.PrintF ( "geomx", "ERROR: Heap pointer 0. pPrev, %d, %d\n", x, pos ); error.Exit (); }
|
||||
if ( pNext !=mHeap-1 && *(hpos*) (pNext+FPOS) == 0x0 ) { error.PrintF ( "geomx", "ERROR: Heap pointer 0. pNext, %d, %d\n", x, pos ); error.Exit (); }
|
||||
if ( *(hpos*) (mHeap+mHeapFree+FPOS) == 0x0 ) { error.PrintF ( "geomx", "ERROR: Heap pointer 0. pHeapFree, %d, %d\n", x, pos ); error.Exit (); }
|
||||
|
||||
// -- check for bugs (remove eventually)
|
||||
pNext = mHeap + mHeapFree;
|
||||
while ( pNext != mHeap-1 ) {
|
||||
pPrev = pNext;
|
||||
pNext = mHeap + * (hpos*) (pNext + FPOS);
|
||||
if ( pNext < pPrev && pNext != mHeap-1 ) {
|
||||
error.PrintF ( "geomx", "ERROR: Heap free space out of order. %d, %d\n", x, pos );
|
||||
error.Exit ();
|
||||
}
|
||||
}
|
||||
//---
|
||||
}
|
||||
}
|
||||
|
||||
void GeomX::ClearRefs ( hList& list )
|
||||
{
|
||||
list.cnt = 0;
|
||||
list.max = 0;
|
||||
list.pos = 0;
|
||||
}
|
||||
|
||||
hval GeomX::AddRef ( hval r, hList& list, hval delta )
|
||||
{
|
||||
if ( list.max == 0 ) {
|
||||
list.cnt = 1;
|
||||
list.pos = HeapAlloc ( LIST_INIT, list.max );
|
||||
*(mHeap + list.pos) = r+delta;
|
||||
} else {
|
||||
if ( list.cnt >= list.max ) {
|
||||
int siz = list.max;
|
||||
hpos new_pos = HeapAlloc ( siz+LIST_INIT, list.max ); // Alloc new location
|
||||
//printf ( "MOVE %d -> %d\n", list.pos, new_pos );
|
||||
memcpy ( mHeap+new_pos, mHeap+list.pos, list.cnt*sizeof(hval) ); // Copy data to new location
|
||||
HeapAddFree ( list.pos, siz ); // Free old location
|
||||
list.pos = new_pos;
|
||||
|
||||
}
|
||||
*(mHeap + list.pos + list.cnt) = r+delta;
|
||||
list.cnt++;
|
||||
}
|
||||
return list.pos;
|
||||
}
|
||||
Reference in New Issue
Block a user