443 lines
12 KiB
C++
443 lines
12 KiB
C++
/*
|
|
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;
|
|
} |