Saxum/extern/bullet/Extras/sph/common/geomx.cpp
Fabian Klemp aeb6218d2d Renaming.
2014-10-24 11:49:46 +02:00

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;
}