Compare commits

...
10 Commits
Author SHA1 Message Date
Clifford Yapp 4e4c445990 remove gct branch (svn branch delete)
svn:revision:63012
svn:branch:gct
svn:account:starseeker
2014-09-25 14:20:19 +00:00
Clifford Yapp e433f9c813 Sync gct with trunk up to r62968
svn:revision:62971
svn:branch:gct
svn:account:starseeker
2014-09-24 19:46:45 +00:00
Clifford Yapp eed3824da3 Sync with trunk up to r62641
svn:revision:62647
svn:branch:gct
svn:account:starseeker
2014-09-10 17:35:17 +00:00
Clifford Yapp a4825a42a4 Sync with trunk up to r62631
svn:revision:62634
svn:branch:gct
svn:account:starseeker
2014-09-10 15:28:15 +00:00
Clifford Yapp 2dad082dea Sync with trunk up to r62573
svn:revision:62632
svn:branch:gct
svn:account:starseeker
2014-09-10 15:08:56 +00:00
Clifford Yapp 5b69f1dda0 Sync with trunk up to r62473
svn:revision:62479
svn:branch:gct
svn:account:starseeker
2014-09-02 13:16:42 +00:00
Clifford Yapp fbf50e1856 Sync with trunk up to r62451
svn:revision:62456
svn:branch:gct
svn:account:starseeker
2014-08-29 15:35:43 +00:00
Clifford Yapp b2b969911c Add CMake build logic, tweaks to get things building as a sub-build in src/other with latest trunk BRL-CAD. Untested, but compilation now succeeds on Linux.
svn:revision:62425
svn:branch:gct
svn:account:starseeker
2014-08-27 16:43:54 +00:00
Clifford Yapp ba87641d27 Add initial checkin of GCT code
svn:revision:62423
svn:branch:gct
svn:account:starseeker
2014-08-27 15:46:19 +00:00
Clifford Yapp ee88483336 Create a branch for integrating GCT into the BRL-CAD build.
svn:revision:62422
svn:branch:gct
svn:account:starseeker
2014-08-27 15:23:56 +00:00
67 changed files with 216331 additions and 0 deletions
+4
View File
@@ -890,6 +890,10 @@ mark_as_advanced(P2T_SHARED)
mark_as_advanced(P2T_STATIC)
mark_as_advanced(P2T_TESTS)
# GCT is a collection of algorithms for geometry processing and conversion
add_subdirectory(gct)
CMAKEFILES(gct)
# TCLAP is used for option parsing - consists entirely of headers
# and does not need to be installed, but does need to generate a
# config file
+32
View File
@@ -0,0 +1,32 @@
set(AUX_SRCS
cc.c
cpuinfo.c
mmatomic.c
mmbinsort.c
mmbitmap.c
mm.c
mmhash.c
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(AUX SHARED ${AUX_SRCS})
set_target_properties(AUX PROPERTIES VERSION 1.1.0 SOVERSION 1)
install(TARGETS AUX
RUNTIME DESTINATION ${BIN_DIR}
LIBRARY DESTINATION ${LIB_DIR}
ARCHIVE DESTINATION ${LIB_DIR})
if(MSVC)
set_property(TARGET AUX APPEND PROPERTY COMPILE_DEFINITIONS "AUX_DLL_EXPORTS")
endif(MSVC)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+215
View File
@@ -0,0 +1,215 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
/*
Templates C style!
#include this whole file with the following definitions set:
#define MSORT_MAIN MyInlinedSortFunction
#define MSORT_CMP MyComparisonFunction
#define MSORT_TYPE int
*/
#ifndef CC_MSORT_INLINE
typedef struct
{
void *src;
void *dst;
int count;
int mergeflag;
int depthbit;
} ccMergeSortStack;
#define CC_MSORT_INLINE
#define CC_MSORT_STACK_DEPTH (512)
#endif
#ifndef MSORT_COPY
#define MSORT_COPY(d,s) (*(d)=*(s))
#define CC_MSORT_COPY
#endif
static MSORT_TYPE *MSORT_MAIN( MSORT_TYPE *src, MSORT_TYPE *tmp, int count )
{
int swapflag, depthbit, maxdepthbit;
ssize_t leftcount, rightcount;
MSORT_TYPE *dst, *sl, *sr, *dstend, *dstbase, *swap, temp;
ccMergeSortStack stack[CC_MSORT_STACK_DEPTH];
ccMergeSortStack *sp;
dst = tmp;
sp = stack;
swapflag = 0;
depthbit = 0;
if( count <= 1 )
return src;
leftcount = count;
for( maxdepthbit = 1 ; ; maxdepthbit ^= 1 )
{
leftcount = leftcount - ( leftcount >> 1 );
if( leftcount <= 4 )
break;
}
for( ; ; )
{
if( count <= 4 )
{
if( !( depthbit ^ maxdepthbit ) )
{
if( ( count == 4 ) && MSORT_CMP( &src[2], &src[3] ) )
{
MSORT_COPY( &temp, &src[2] );
MSORT_COPY( &src[2], &src[3] );
MSORT_COPY( &src[3], &temp );
}
if( MSORT_CMP( &src[0], &src[1] ) )
{
MSORT_COPY( &temp, &src[0] );
MSORT_COPY( &src[0], &src[1] );
MSORT_COPY( &src[1], &temp );
}
swapflag = 0;
}
else
{
if( count == 4 )
{
if( MSORT_CMP( &src[2], &src[3] ) )
{
MSORT_COPY( &dst[2], &src[3] );
MSORT_COPY( &dst[3], &src[2] );
}
else
{
MSORT_COPY( &dst[2], &src[2] );
MSORT_COPY( &dst[3], &src[3] );
}
}
else if( count == 3 )
MSORT_COPY( &dst[2], &src[2] );
if( MSORT_CMP( &src[0], &src[1] ) )
{
MSORT_COPY( &dst[0], &src[1] );
MSORT_COPY( &dst[1], &src[0] );
}
else
{
MSORT_COPY( &dst[0], &src[0] );
MSORT_COPY( &dst[1], &src[1] );
}
swap = src;
src = dst;
dst = swap;
swapflag = 1;
}
}
else
{
rightcount = count >> 1;
leftcount = count - rightcount;
sp->src = src;
sp->dst = dst;
sp->count = count;
sp->mergeflag = 1;
sp->depthbit = depthbit;
depthbit ^= 1;
sp++;
sp->src = src + leftcount;
sp->dst = dst + leftcount;
sp->count = rightcount;
sp->mergeflag = 0;
sp->depthbit = depthbit;
sp++;
count = leftcount;
continue;
}
for( ; ; )
{
rightcount = count >> 1;
leftcount = count - rightcount;
sl = src;
sr = src + leftcount;
dstbase = dst;
for( ; ; )
{
if( MSORT_CMP( sl, sr ) )
{
MSORT_COPY( dst++, sr++ );
if( --rightcount )
continue;
for( dstend = &dst[leftcount] ; dst < dstend ; )
MSORT_COPY( dst++, sl++ );
break;
}
else
{
MSORT_COPY( dst++, sl++ );
if( --leftcount )
continue;
for( dstend = &dst[rightcount] ; dst < dstend ; )
MSORT_COPY( dst++, sr++ );
break;
}
}
if( sp == stack )
return dstbase;
sp--;
src = sp->src;
dst = sp->dst;
count = sp->count;
depthbit = sp->depthbit;
if( !( sp->mergeflag ) )
break;
swapflag ^= 1;
if( swapflag )
{
src = sp->dst;
dst = sp->src;
}
}
}
return 0;
}
#ifndef CC_MSORT_COPY
#undef MSORT_COPY
#undef CC_MSORT_COPY
#endif
+73
View File
@@ -0,0 +1,73 @@
/* Automatically generated CPU information header */
#define CPUCONF_CHAR_SIZE (1)
#define CPUCONF_SHORT_SIZE (2)
#define CPUCONF_INT_SIZE (4)
#define CPUCONF_LONG_SIZE (8)
#define CPUCONF_LONG_LONG_SIZE (8)
#define CPUCONF_INTPTR_SIZE (8)
#define CPUCONF_POINTER_SIZE (8)
#define CPUCONF_FLOAT_SIZE (4)
#define CPUCONF_DOUBLE_SIZE (8)
#define CPUCONF_LONG_DOUBLE_SIZE (16)
#define CPUCONF_CHAR_BITS (8)
#define CPUCONF_SHORT_BITS (16)
#define CPUCONF_INT_BITS (32)
#define CPUCONF_LONG_BITS (64)
#define CPUCONF_LONG_LONG_BITS (64)
#define CPUCONF_INTPTR_BITS (64)
#define CPUCONF_POINTER_BITS (64)
#define CPUCONF_FLOAT_BITS (32)
#define CPUCONF_DOUBLE_BITS (64)
#define CPUCONF_LONG_DOUBLE_BITS (128)
#define CPUCONF_CHAR_SIZESHIFT (0)
#define CPUCONF_SHORT_SIZESHIFT (1)
#define CPUCONF_INT_SIZESHIFT (2)
#define CPUCONF_LONG_SIZESHIFT (3)
#define CPUCONF_LONG_LONG_SIZESHIFT (3)
#define CPUCONF_INTPTR_SIZESHIFT (3)
#define CPUCONF_POINTER_SIZESHIFT (3)
#define CPUCONF_FLOAT_SIZESHIFT (2)
#define CPUCONF_DOUBLE_SIZESHIFT (3)
#define CPUCONF_LONG_DOUBLE_SIZESHIFT (4)
#define CPUCONF_CHAR_BITSHIFT (3)
#define CPUCONF_SHORT_BITSHIFT (4)
#define CPUCONF_INT_BITSHIFT (5)
#define CPUCONF_LONG_BITSHIFT (6)
#define CPUCONF_LONG_LONG_BITSHIFT (6)
#define CPUCONF_INTPTR_BITSHIFT (6)
#define CPUCONF_POINTER_BITSHIFT (6)
#define CPUCONF_FLOAT_BITSHIFT (5)
#define CPUCONF_DOUBLE_BITSHIFT (6)
#define CPUCONF_LONG_DOUBLE_BITSHIFT (7)
#define CPUCONF_LITTLE_ENDIAN
#define CPUCONF_ARCH_AMD64
#define CPUCONF_VENDOR_INTEL
#define CPUCONF_IDENTIFIER "Intel(R) Core(TM) i7-2760QM CPU @ 2.40GHz"
#define CPUCONF_CLASS_CORE2
#define CPUCONF_LOGICAL_CORES_COUNT (16)
#define CPUCONF_PHYSICAL_CORES_COUNT (8)
#define CPUCONF_CORES_COUNT (8)
#define CPUCONF_SYSTEM_MEMORY (8207917056LL)
#define CPUCONF_WORD_SIZE (64)
#define CPUCONF_CACHE_LINE_SIZE (64)
#define CPUCONF_CACHE_LOAD_SIZE (64)
#define CPUCONF_CACHE_L2_SIZE (262144)
#define CPUCONF_CAP_GPREGS (16)
#define CPUCONF_CAP_FPREGS (16)
#define CPUCONF_CAP_CMOV
#define CPUCONF_CAP_MMX
#define CPUCONF_CAP_SSE
#define CPUCONF_CAP_SSE2
#define CPUCONF_CAP_SSE3
#define CPUCONF_CAP_SSSE3
#define CPUCONF_CAP_SSE4_1
#define CPUCONF_CAP_SSE4_2
#define CPUCONF_CAP_HYPERTHREADING
#define CPUCONF_CAP_MWAIT
File diff suppressed because it is too large Load Diff
+179
View File
@@ -0,0 +1,179 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#ifndef CPUINFO_H
#define CPUINFO_H
typedef struct
{
uint32_t endianness;
uint32_t intellevel;
uint32_t amdlevel;
uint32_t arch;
char vendorstring[12+1];
char identifier[48+1];
uint32_t vendor;
uint32_t class;
uint32_t family;
uint32_t model;
uint32_t cacheline;
uint32_t clflushsize;
int32_t cachelineL1code, cachesizeL1code, cacheassociativityL1code, cachesharedL1code;
int32_t cachelineL1data, cachesizeL1data, cacheassociativityL1data, cachesharedL1data;
int32_t cacheunifiedL1;
int32_t cachelineL2, cachesizeL2, cacheassociativityL2, cachesharedL2;
int32_t cachelineL3, cachesizeL3, cacheassociativityL3, cachesharedL3;
int64_t sysmemory;
uint32_t socketphysicalcores;
uint32_t socketlogicalcores;
uint32_t socketcount;
uint32_t totalcorecount;
uint32_t wordsize;
uint32_t gpregs;
uint32_t fpregs;
/* CPU capabilities */
int capcmov:1;
int capclflush:1;
int captsc:1;
int capmmx:1;
int capmmxext:1;
int cap3dnow:1;
int cap3dnowext:1;
int capsse:1;
int capsse2:1;
int capsse3:1;
int capssse3:1;
int capsse4p1:1;
int capsse4p2:1;
int capsse4a:1;
int capavx:1;
int capavx2:1;
int capxop:1;
int capfma3:1;
int capfma4:1;
int capmisalignsse:1;
int capaes:1;
int cappclmul;
int caprdrnd:1;
int capcmpxchg16b:1;
int cappopcnt:1;
int caplzcnt:1;
int capmovbe:1;
int caprdtscp:1;
int capconstanttsc:1;
int capf16c:1;
int capbmi:1;
int capbmi2:1;
int captbm:1;
int caphyperthreading:1;
int capmwait:1;
int caplongmode:1;
int capthermalsensor:1;
int capclockmodulation:1;
/* CPU capabilities */
} cpuInfo;
void cpuGetInfo( cpuInfo *cpu );
void cpuGetInfoEnv( cpuInfo *cpu );
////
enum
{
CPUINFO_LITTLE_ENDIAN,
CPUINFO_BIG_ENDIAN,
CPUINFO_MIXED_ENDIAN
};
enum
{
CPUINFO_ARCH_AMD64,
CPUINFO_ARCH_IA32,
CPUINFO_ARCH_UNKNOWN
};
enum
{
CPUINFO_VENDOR_AMD,
CPUINFO_VENDOR_INTEL,
CPUINFO_VENDOR_UNKNOWN
};
enum
{
CPUINFO_CLASS_STEAMROLLER,
CPUINFO_CLASS_JAGUAR,
CPUINFO_CLASS_PILEDRIVER,
CPUINFO_CLASS_BULLDOZER,
CPUINFO_CLASS_BOBCAT,
CPUINFO_CLASS_BARCELONA,
CPUINFO_CLASS_ATHLON64SSE3,
CPUINFO_CLASS_ATHLON64,
CPUINFO_CLASS_ATHLON,
CPUINFO_CLASS_K6_2,
CPUINFO_CLASS_K6,
CPUINFO_CLASS_COREI7AVX2,
CPUINFO_CLASS_COREI7AVX,
CPUINFO_CLASS_COREI7,
CPUINFO_CLASS_CORE2,
CPUINFO_CLASS_NOCONA,
CPUINFO_CLASS_PRESCOTT,
CPUINFO_CLASS_PENTIUM4,
CPUINFO_CLASS_PENTIUM3,
CPUINFO_CLASS_PENTIUM2,
CPUINFO_CLASS_I686,
CPUINFO_CLASS_I586,
CPUINFO_CLASS_AMD64GENERIC,
CPUINFO_CLASS_IA32GENERIC,
CPUINFO_CLASS_UNKNOWN,
CPUINFO_CLASS_COUNT
};
#endif /* CPUINFO_H */
+601
View File
@@ -0,0 +1,601 @@
/* gctcommon.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 10/03/13
*
* Authors(s):
* DRH
*
* Description:
* Any common use functions between all the tools.
*
*/
#ifndef GCTCOMMON_H
#define GCTCOMMON_H
/* Standard C/C++ libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#ifndef COMPILE_FOR_VSL
#include <ctype.h>
#include <algorithm>
#endif
/* Pthread libraries */
#include <pthread.h>
#if defined (_GNU_SOURCE)
#include <sys/sysinfo.h>
#endif
#ifndef COMPILE_FOR_VSL
extern "C" {
#include "common.h"
#include "bu.h"
#include "vmath.h"
#include "bn.h"
#include "raytrace.h"
#include "rtgeom.h"
#include "wdb.h"
}
#endif
#ifndef SQ
#define SQ(a) (a)*(a)
#endif
/* Stuff defined in BRL-CAD but might not be for others */
#ifndef X
#define X 0
#endif
#ifndef Y
#define Y 1
#endif
#ifndef Z
#define Z 2
#endif
#ifndef VINIT
#define VINIT(a,s) (a)[X] = (a)[Y] = (a)[Z] = (s)
#endif
#ifndef VSET
#define VSET(a,b,c,d) { \
(a)[X] = (b); \
(a)[Y] = (c); \
(a)[Z] = (d); }
#endif
#ifndef VADD2
#define VADD2(a, b, c) { \
(a)[X] = (b)[X] + (c)[X]; \
(a)[Y] = (b)[Y] + (c)[Y]; \
(a)[Z] = (b)[Z] + (c)[Z]; \
}
#endif
#ifndef VEQUAL
#define VEQUAL(a, b) ((a)[X]==(b)[X] && (a)[Y]==(b)[Y] && (a)[Z]==(b)[Z])
#endif
#ifndef VMOVE
#define VMOVE(a, b) { \
(a)[X] = (b)[X]; \
(a)[Y] = (b)[Y]; \
(a)[Z] = (b)[Z]; \
}
#endif
#ifndef VSCALE
#define VSCALE(a, b, c) { \
(a)[X] = (b)[X] * (c); \
(a)[Y] = (b)[Y] * (c); \
(a)[Z] = (b)[Z] * (c); \
}
#endif
#ifndef VSUB2
#define VSUB2(a, b, c) { \
(a)[X] = (b)[X] - (c)[X]; \
(a)[Y] = (b)[Y] - (c)[Y]; \
(a)[Z] = (b)[Z] - (c)[Z]; \
}
#endif
#ifndef VCROSS
#define VCROSS(a,b,c) { \
(a)[X] = (b)[Y] * (c)[Z] - (b)[Z] * (c)[Y]; \
(a)[Y] = (b)[Z] * (c)[X] - (b)[X] * (c)[Z]; \
(a)[Z] = (b)[X] * (c)[Y] - (b)[Y] * (c)[X]; }
#endif
#ifndef VMAGSQ
#define VMAGSQ(a) (SQ((a)[X]) + SQ((a)[Y]) + SQ((a)[Z]))
#endif
#ifndef VMAG
#define VMAG(a) sqrt(VMAGSQ(a))
#endif
#ifndef VUNITIZE
#define VUNITIZE(a) { \
register double _f = VMAGSQ(a); \
_f = sqrt(_f); \
if (!VM_NEAR(_f, 1.0, VM_UNITIZE_TOL)) { \
if (_f < VM_DIVIDE_TOL) { \
VINIT((a), 0.0); \
} else { \
_f = 1.0/_f; \
(a)[X] *= _f; \
(a)[Y] *= _f; \
(a)[Z] *= _f; \
} \
}\
}
#endif
#ifndef VM_NEAR
#define VM_NEAR(v1,v2,tol) ((((v2) - (tol)) <= (v1)) && ((v1) <= ((v2) + (tol))))
#endif
#ifndef VM_DIVIDE_TOL
#define VM_DIVIDE_TOL (1.0e-20)
#endif
#ifndef VM_UNITIZE_TOL
#define VM_UNITIZE_TOL (1.0e-15)
#endif
#ifndef DIST_PT_PT_SQ
#define DIST_PT_PT_SQ(_a,_b) \
SQ((_a)[X] - (_b)[X]) + \
SQ((_a)[Y] - (_b)[Y]) + \
SQ((_a)[Z] - (_b)[Z])
#endif
#ifndef DIST_PT_PT
#define DIST_PT_PT(_a,_b) sqrt(DIST_PT_PT_SQ(_a, _b))
#endif
//******************************************************************************
// NAME ideal_thread_count
//
// INPUTS
// none
//
// DESCRIPTION
// Determine the ideal number of threads to create for multithreading
// applications, based on what is available on the target system.
//******************************************************************************
static inline
unsigned ideal_thread_count()
{
int count = 0;
#if defined(PTW32_VERSION) || defined(__hpux)
count = pthread_num_processors_np();
#elif defined(__APPLE__) || defined(__FreeBSD__)
size_t size=sizeof(count);
count = (sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count);
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
count = sysconf(_SC_NPROCESSORS_ONLN);
#elif defined(_GNU_SOURCE)
count = get_nprocs();
#elif defined(WIN32)
SYSTEM_INFO info={{0}};
GetSystemInfo(&info);
count = info.dwNumberOfProcessors;
#endif
return (unsigned) (count>0)?count:1;
}
#ifndef COMPILE_FOR_VSL
//******************************************************************************
// NAME output_obj
//
// INPUTS
// fp - file pointer to write
// vertex - list of vertices
// normal - list of normals
// indices - list of indices that make up triangles
// gnames - list of geometry names
// offsets - list of offsets between geometry items
//
// DESCRIPTION
// Runs the given lists and creates an OBJ file that holds all the data.
//******************************************************************************
static inline
void output_obj (FILE *fp,
std::vector<float> &vertex,
std::vector<float> &normal,
std::vector<long> &indices,
std::vector<std::string> &gnames,
std::vector<long> &offsets)
{
long i;
/* output vertices */
fprintf (fp, "g\n");
for (i = 0; i < (long)vertex.size(); i += 3)
fprintf (fp, "v %.4f %.4f %.4f\n",
vertex[i], vertex[i+1], vertex[i+2]);
fprintf (fp, "\n# %d vertices\n", (int)vertex.size()/3);
fprintf (fp, "\n# 0 vertex parms\n");
fprintf (fp, "\n# 0 texture vertices\n");
fprintf (fp, "\n");
/* output normals */
fprintf (fp, "g\n");
for (i = 0; i < (long)normal.size(); i += 3)
fprintf (fp, "vn %.4f %.4f %.4f\n",
normal[i], normal[i+1], normal[i+2]);
fprintf (fp, "\n# %d normals\n", (int)normal.size()/3);
fprintf (fp, "\n");
/* out geometries */
for (i = 0; i < (long)gnames.size(); i++)
{
fprintf (fp, "g %s\n", gnames.at(i).c_str());
fprintf (fp, "s off\n");
long end = (long)indices.size();
if (i < ((long)gnames.size() -1))
end = offsets[i+1];
/* add 1 to everything because OBJ indices are 1 based, not 0 */
for (long j = offsets[i]; j < end; j += 3)
fprintf (fp, "f %ld//%ld %ld//%ld %ld//%ld\n",
(indices[j+0] +1), (indices[j+0] +1),
(indices[j+1] +1), (indices[j+1] +1),
(indices[j+2] +1), (indices[j+2] +1));
fprintf (fp, "\n# %ld facets\n", end - offsets[i]);
}
fprintf (fp, "\n# %d elements\n", (int)gnames.size());
}
//******************************************************************************
// NAME output_brlcad
//
// INPUTS
// ofile - BRL-CAD database file name
// vertex - list of vertices
// normal - list of normals
// indices - list of indices that make up triangles
// gnames - list of geometry names
// offsets - list of offsets between geometry items
//
// DESCRIPTION
// Runs the given lists and creates a BRLCAD database that holds all the data.
//******************************************************************************
static inline
void output_brlcad (char *ofile,
std::vector<float> &vertex,
std::vector<float> &normal,
std::vector<long> &indices,
std::vector<std::string> &gnames,
std::vector<long> &offsets)
{
struct rt_wdb *db_fp;
struct wmember wm_hd; /* defined in wdb.h */
long i;
unsigned char rgb[3]; /* region color (red) */
if ((db_fp = wdb_fopen(ofile)) == NULL)
{
perror(ofile);
return;
}
VSET(rgb, 255, 0, 0);
mk_id(db_fp, ofile); /* create the database header record */
/* assume everything is in mm at this point */
/* output components (i.e. Primitives/Regions pairs) */
for (i = 0; i < (long)gnames.size(); i++)
{
char name[255];
fastf_t *vertices = NULL;
fastf_t *normals = NULL;
int *faces = NULL;
int nverts = 0, nnrmls = 0, nfaces = 0;
std::string gname = gnames.at(i).c_str();
std::size_t pos = gname.find(".");
/* remove '.r', if it exists */
if (pos != std::string::npos)
gname = gname.substr(0, pos);
memset (name, 0, sizeof (char) * 255);
sprintf (name, "%s.s", gname.c_str());
long end = (long)indices.size();
if (i < ((long)gnames.size() -1))
end = offsets[i+1];
/* allocate array to hold face combinations */
nfaces = (int) (end - offsets[i]);
faces = (int *) malloc (sizeof (int) * nfaces);
memset (faces, 0, sizeof (int) * nfaces);
/* vector to tell if index is already added to vert/nrml lists */
std::vector<long> already;
/* add vertices, normals, and indices */
for (long j = offsets[i]; j < end; j++)
{
long index = indices[j];
long myidx = j - offsets[i];
if (std::find(already.begin(),
already.end(), index) == already.end())
{
vertices = (fastf_t*) realloc ((void *) vertices, sizeof(fastf_t) * (nverts + 3));
normals = (fastf_t*) realloc ((void *) normals, sizeof(fastf_t) * (nnrmls + 3));
vertices[nverts] = vertex[index*3+0]; ++nverts;
vertices[nverts] = vertex[index*3+1]; ++nverts;
vertices[nverts] = vertex[index*3+2]; ++nverts;
normals[nnrmls] = normal[index*3+0]; ++nnrmls;
normals[nnrmls] = normal[index*3+1]; ++nnrmls;
normals[nnrmls] = normal[index*3+2]; ++nnrmls;
already.push_back(index);
faces[myidx] = (nverts / 3) -1;
}
else
{
for (long k = 0; k < (long)already.size(); k++)
if (already.at(k) == index)
{
faces[myidx] = k;
break;
}
}
}
already.clear();
/* make a BOT primitive */
mk_bot_w_normals(db_fp, name, RT_BOT_SOLID, RT_BOT_UNORIENTED, 0,
(nverts / 3), (nfaces / 3), vertices, faces,
(fastf_t *)NULL, (struct bu_bitv *)NULL,
(nnrmls / 3), normals, faces);
/* Make a region that is the union of this one BOT object.
* To accomplish this, we need to create a linked list of items
* that make up the combination. The wm_hd structure serves as
* the head of the list items.
*/
BU_LIST_INIT(&wm_hd.l);
/* Create a wmember structure for the item that we want
* in the combination. The return from mk_addmember is a pointer
* to the wmember structure.
*/
(void)mk_addmember(name, &wm_hd.l, NULL, WMOP_UNION);
/* Create the combination. In this case we are going to make it
* a region, hence the is_region flag is set, and we provide shader
* parameter information.
*/
memset (name, 0, sizeof (char) * 255);
sprintf (name, "%s.r", gname.c_str());
mk_lcomb(db_fp,
name, /* name of db region */
&wm_hd, /* list of elements & boolean operations */
1, /* is_region flag */
"plastic", /* optical shader (just guessed) */
"di=.8 sp=.2", /* shader params (again guessing) */
rgb, /* item color */
0); /* inherit (override) flag */
if (vertices) free (vertices);
if (normals) free (normals);
if (faces) free (faces);
}
wdb_close(db_fp);
}
//******************************************************************************
// NAME output_fastgen
//
// INPUTS
// fp - file pointer to write
// vertex - list of vertices
// indices - list of indices that make up triangles
// gnames - list of geometry names
// offsets - list of offsets between geometry items
// modes - list of geometry modes
// materials - list of geometry materials
// thicknesses - list of geometry thicknesses
// positions - list of geometry positions
//
// DESCRIPTION
// Runs the given lists and creates a FASTGEN file that holds all the data.
//******************************************************************************
static inline
void output_fastgen (FILE *fp,
std::vector<float> &vertex,
std::vector<long> &indices,
std::vector<std::string> &gnames,
std::vector<long> &offsets,
std::vector<int> &modes,
std::vector<int> &materials,
std::vector<float> &thicknesses,
std::vector<int> &positions)
{
long i;
int cID = 0;
/* output components (i.e. SECTIONs) */
for (i = 0; i < (long)gnames.size(); i++)
{
std::string gname = gnames.at(i).c_str();
std::size_t pos = gname.find(".");
/* pick 1st comp ID as the one to use */
if (pos != std::string::npos)
gname = gname.substr(0, pos);
/* convert name to number */
if (isdigit (gname.c_str()[0]))
cID = (int) atoi (gname.c_str());
else cID++;
/* print SECTION card */
fprintf (fp, "%-8s%8d%8d%8d%8d\n", "SECTION", (cID / 1000),
(cID % 1000), modes.at(i), 1);
long end = (long) indices.size();
if (i < ((long) gnames.size() -1))
end = offsets[i+1];
/* print GRID cards */
for (long j = 0, id = 1; j < (long)vertex.size(); j+=3, id++)
{
float x = vertex[j+0];
float y = vertex[j+1];
float z = vertex[j+2];
fprintf (fp, "%-8s%8d%8s%8.2f%8.2f%8.2f\n", "GRID", (int) id, " ",
x, y, z);
}
/* print CTRI cards */
/* add 1 to everything because FASTGEN indices are 1 based, not 0 */
for (long j = offsets[i], id = 1; j < end; j += 3, id++)
{
fprintf (fp, "%-8s%8d%8d%8ld%8ld%8ld%8s%8.2f%8d\n", "CTRI", (int) id,
materials.at(i),
indices[j+0] +1,
indices[j+1] +1,
indices[j+2] +1,
" ", thicknesses.at(i),
positions.at(i));
}
}
fprintf (fp, "%-8s\n", "ENDDATA");
}
//******************************************************************************
// NAME output_vrml
//
// INPUTS
// fp - file pointer to write
// vertex - list of vertices
// normal - list of normals
// indices - list of indices that make up triangles
// gnames - list of geometry names
// offsets - list of offsets between geometry items
//
// DESCRIPTION
// Runs the given lists and creates a VRML file that holds all the data.
//******************************************************************************
static inline
void output_vrml (FILE *fp,
std::vector<float> &vertex,
std::vector<float> &normal,
std::vector<long> &indices,
std::vector<std::string> &gnames,
std::vector<long> &offsets)
{
long i;
int cID = 0;
fprintf (fp, "#VRML V2.0 utf8\n");
/* output components (i.e. Shapes) */
for (i = 0; i < (long)gnames.size(); i++)
{
std::string gname = gnames.at(i).c_str();
std::size_t pos = gname.find(".");
/* pick 1st comp ID as the one to use */
if (pos != std::string::npos)
gname = gname.substr(0, pos);
/* convert name to number */
if (isdigit (gname.c_str()[0]))
cID = (int) atoi (gname.c_str());
else cID++;
/* print Shape header */
fprintf (fp, "DEF comp_%d Shape {\n", cID);
fprintf (fp, "\t# Component_ID: %s\n\n", gname.c_str());
/* print Geometry header */
fprintf (fp, "\tgeometry IndexedFaceSet {\n");
fprintf (fp, "\t\tcoord Coordinate {\n");
fprintf (fp, "\t\t\tpoint [\n");
long end = (long) indices.size();
if (i < ((long) gnames.size() -1))
end = offsets[i+1];
/* print points */
for (long j = 0, id = 0; j < (long)vertex.size(); j+=3, id++)
{
float x = vertex[j+0];
float y = vertex[j+1];
float z = vertex[j+2];
fprintf (fp, "\t\t\t\t%.3f %.3f %.3f, # point %d\n", x, y, z, (int) id);
}
fprintf (fp, "\t\t\t]\n"); /* close point */
fprintf (fp, "\t\t}\n"); /* close coord */
fprintf (fp, "\t\tcoordIndex [\n");
for (long j = offsets[i]; j < end; j += 3)
{
fprintf (fp, "\t\t\t%ld, %ld, %ld, -1\n",
indices[j+0], indices[j+1], indices[j+2]);
}
fprintf (fp, "\t\t]\n"); /* close coordIndex */
fprintf (fp, "\t\tnormalPerVertex FALSE\n");
fprintf (fp, "\t\tconvex TRUE\n");
fprintf (fp, "\t\tcreaseAngle 0.5\n");
fprintf (fp, "\t\tsolid FALSE\n");
fprintf (fp, "\t}\n"); /* close geometry */
fprintf (fp, "}\n"); /* close Shape */
}
}
#endif // COMPILE_FOR_VSL
#endif
+79
View File
@@ -0,0 +1,79 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#define M3D_VectorZero(x) ({(x)[0]=0.0;(x)[1]=0.0;(x)[2]=0.0;})
#define M3D_VectorMagnitude(x) (sqrt((x)[0]*(x)[0]+(x)[1]*(x)[1]+(x)[2]*(x)[2]))
#define M3D_VectorCopy(x,y) ({(x)[0]=(y)[0];(x)[1]=(y)[1];(x)[2]=(y)[2];})
#define M3D_VectorAdd(x,y) (x)[0]+=(y)[0];(x)[1]+=(y)[1];(x)[2]+=(y)[2]
#define M3D_VectorAddStore(x,y,z) (x)[0]=(y)[0]+(z)[0];(x)[1]=(y)[1]+(z)[1];(x)[2]=(y)[2]+(z)[2]
#define M3D_VectorAddMulScalar(x,y,z) (x)[0]+=(y)[0]*(z);(x)[1]+=(y)[1]*(z);(x)[2]+=(y)[2]*(z)
#define M3D_VectorAddMul(x,y,z) (x)[0]+=(y)[0]*(z)[0];(x)[1]+=(y)[1]*(z)[1];(x)[2]+=(y)[2]*(z)[2]
#define M3D_VectorSub(x,y) (x)[0]-=(y)[0];(x)[1]-=(y)[1];(x)[2]-=(y)[2]
#define M3D_VectorSubStore(x,y,z) (x)[0]=(y)[0]-(z)[0];(x)[1]=(y)[1]-(z)[1];(x)[2]=(y)[2]-(z)[2]
#define M3D_VectorSubMulScalar(x,y,z) (x)[0]-=(y)[0]*(z);(x)[1]-=(y)[1]*(z);(x)[2]-=(y)[2]*(z)
#define M3D_VectorSubMul(x,y,z) (x)[0]-=(y)[0]*(z)[0];(x)[1]-=(y)[1]*(z)[1];(x)[2]-=(y)[2]*(z)[2]
#define M3D_VectorMul(x,y) (x)[0]*=(y)[0];(x)[1]*=(y)[1];(x)[2]*=(y)[2]
#define M3D_VectorMulStore(x,y,z) (x)[0]=(y)[0]*(z)[0];(x)[1]=(y)[1]*(z)[1];(x)[2]=(y)[2]*(z)[2]
#define M3D_VectorMulScalar(x,y) (x)[0]*=(y);(x)[1]*=(y);(x)[2]*=(y)
#define M3D_VectorMulScalarStore(x,y,z) (x)[0]=(y)[0]*(z);(x)[1]=(y)[1]*(z);(x)[2]=(y)[2]*(z)
#define M3D_VectorDiv(x,y) (x)[0]/=(y)[0];(x)[1]/=(y)[1];(x)[2]/=(y)[2]
#define M3D_VectorDivStore(x,y,z) (x)[0]=(y)[0]/(z)[0];(x)[1]=(y)[1]/(z)[1];(x)[2]=(y)[2]/(z)[2]
#define M3D_VectorDotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2])
#define M3D_PlanePoint(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3])
#define M3D_VectorNormalize(x) ({typeof(*(x)) _f;_f=1.0/sqrt((x)[0]*(x)[0]+(x)[1]*(x)[1]+(x)[2]*(x)[2]);(x)[0]*=_f;(x)[1]*=_f;(x)[2]*=_f;})
#define M3D_VectorCrossProduct(x,y,z) ({(x)[0]=((y)[1]*(z)[2])-((y)[2]*(z)[1]);(x)[1]=((y)[2]*(z)[0])-((y)[0]*(z)[2]);(x)[2]=((y)[0]*(z)[1])-((y)[1]*(z)[0]);})
#define M3D_VectorAddCrossProduct(x,y,z) ({(x)[0]+=((y)[1]*(z)[2])-((y)[2]*(z)[1]);(x)[1]+=((y)[2]*(z)[0])-((y)[0]*(z)[2]);(x)[2]+=((y)[0]*(z)[1])-((y)[1]*(z)[0]);})
#define M3D_VectorSubCrossProduct(x,y,z) ({(x)[0]-=((y)[1]*(z)[2])-((y)[2]*(z)[1]);(x)[1]-=((y)[2]*(z)[0])-((y)[0]*(z)[2]);(x)[2]-=((y)[0]*(z)[1])-((y)[1]*(z)[0]);})
#define M3D_MatrixMulVector(d,p,m) ({ \
(d)[0]=(p)[0]*(m)[0*4+0]+(p)[1]*(m)[1*4+0]+(p)[2]*(m)[2*4+0]; \
(d)[1]=(p)[0]*(m)[0*4+1]+(p)[1]*(m)[1*4+1]+(p)[2]*(m)[2*4+1]; \
(d)[2]=(p)[0]*(m)[0*4+2]+(p)[1]*(m)[1*4+2]+(p)[2]*(m)[2*4+2]; })
#define M3D_MatrixTransMulVector(d,p,m) ({ \
(d)[0]=(p)[0]*(m)[0*4+0]+(p)[1]*(m)[0*4+1]+(p)[2]*(m)[0*4+2]; \
(d)[1]=(p)[0]*(m)[1*4+0]+(p)[1]*(m)[1*4+1]+(p)[2]*(m)[1*4+2]; \
(d)[2]=(p)[0]*(m)[2*4+0]+(p)[1]*(m)[2*4+1]+(p)[2]*(m)[2*4+2]; })
#define M3D_MatrixMulVectorSelf(p,m) ({ \
typeof(*(p)) _n[3] = { p[0], p[1], p[2] }; \
(p)[0]=(_n)[0]*(m)[0*4+0]+(_n)[1]*(m)[1*4+0]+(_n)[2]*(m)[2*4+0]; \
(p)[1]=(_n)[0]*(m)[0*4+1]+(_n)[1]*(m)[1*4+1]+(_n)[2]*(m)[2*4+1]; \
(p)[2]=(_n)[0]*(m)[0*4+2]+(_n)[1]*(m)[1*4+2]+(_n)[2]*(m)[2*4+2]; })
#define M3D_MatrixMulPoint(d,p,m) ({ \
(d)[0]=(p)[0]*(m)[0*4+0]+(p)[1]*(m)[1*4+0]+(p)[2]*(m)[2*4+0]+(m)[3*4+0]; \
(d)[1]=(p)[0]*(m)[0*4+1]+(p)[1]*(m)[1*4+1]+(p)[2]*(m)[2*4+1]+(m)[3*4+1]; \
(d)[2]=(p)[0]*(m)[0*4+2]+(p)[1]*(m)[1*4+2]+(p)[2]*(m)[2*4+2]+(m)[3*4+2]; })
#define M3D_MatrixMulPointSelf(p,m) ({ \
typeof(*(p)) _n[3] = { p[0], p[1], p[2] }; \
(p)[0]=(_n)[0]*(m)[0*4+0]+(_n)[1]*(m)[1*4+0]+(_n)[2]*(m)[2*4+0]+(m)[3*4+0]; \
(p)[1]=(_n)[0]*(m)[0*4+1]+(_n)[1]*(m)[1*4+1]+(_n)[2]*(m)[2*4+1]+(m)[3*4+1]; \
(p)[2]=(_n)[0]*(m)[0*4+2]+(_n)[1]*(m)[1*4+2]+(_n)[2]*(m)[2*4+2]+(m)[3*4+2]; })
File diff suppressed because it is too large Load Diff
+776
View File
@@ -0,0 +1,776 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
/**
* @file
*
* Global memory management header.
*/
#ifndef MM_H
#define MM_H
#ifdef __cplusplus
extern "C" {
#endif
#define MM_DEBUG 0
#define MM_INLINE_LIST_FUNCTIONS
#define MM_ALLOC_CHECK
#define MM_DEBUG_GUARD_BYTES (32)
#define MM_DEBUG_MMAP (1)
/* Enabling this will lead to ever growing memory usage! Strictly for debugging. */
#define MM_DEBUG_MMAP_LINGERING (0)
////
#ifdef MM_NUMA
#include <numa.h>
#endif
#if defined(__linux__) || defined(__gnu_linux__) || defined(__linux) || defined(__linux)
#define MM_LINUX (1)
#define MM_UNIX (1)
#elif defined(__APPLE__)
#define MM_OSX (1)
#define MM_UNIX (1)
#elif defined(__unix__) || defined(__unix) || defined(unix)
#define MM_UNIX (1)
#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64)
#define MM_WIN64 (1)
#define MM_WIN32 (1)
#define MM_WINDOWS (1)
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#define MM_WIN32 (1)
#define MM_WINDOWS (1)
#endif
#if __MINGW64__
#define MM_MINGW32 (1)
#define MM_MINGW64 (1)
#elif __MINGW32__
#define MM_MINGW32 (1)
#endif
#if !MM_UNIX
#undef MM_DEBUG_MMAP
#define MM_DEBUG_MMAP (0)
#endif
#define MM_CPU_COUNT_MAXIMUM (1024)
#define MM_NODE_COUNT_MAXIMUM (256)
#ifndef CPUCONF_CACHE_LINE_SIZE
#define CPUCONF_CACHE_LINE_SIZE 64
#endif
#if defined(__GNUC__)
#define MM_CACHE_ALIGN __attribute__((aligned(CPUCONF_CACHE_LINE_SIZE)))
#define MM_RESTRICT __restrict
#define MM_NOINLINE __attribute__((noinline))
#else
#define MM_CACHE_ALIGN
#define MM_RESTRICT
#define MM_NOINLINE
#endif
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define MM_ALIGN16 __attribute__((aligned(16)))
#define MM_ALIGN16_SAFE (1)
#elif defined(_MSC_VER)
#define MM_ALIGN16 __declspec(align(16))
#define MM_ALIGN16_SAFE (1)
#else
#define MM_ALIGN16
#define MM_ALIGN16_SAFE (0)
#endif
#define MM_ERROR() {printf("MM Error at %s:%d\n",file,line);exit(1)}
#ifndef ADDRESS
#define ADDRESS(p,o) ((void *)(((char *)p)+(o)))
#endif
#ifndef ADDRESSDIFF
#define ADDRESSDIFF(a,b) (((char *)a)-((char *)b))
#endif
#include <sys/time.h>
#ifdef __WIN32__
int mmGetTimeOfDay( struct timeval *tv );
#define gettimeofday(a,b) mmGetTimeOfDay(a)
#endif
typedef struct
{
int numaflag;
int pagesize;
int cpucount;
int nodecount;
int cpunode[MM_CPU_COUNT_MAXIMUM];
int64_t nodesize[MM_NODE_COUNT_MAXIMUM];
int nodecpucount[MM_NODE_COUNT_MAXIMUM];
int64_t sysmemory;
} mmContext;
extern mmContext mmcontext;
#include "mmatomic.h"
#include "mmthread.h"
#if MM_DEBUG
#define MM_FUNC(n) mm##n##Debug
#define MM_PARAMS , char *file, int line
#else
#define MM_FUNC(n) mm##n
#define MM_PARAMS
#endif
////
void mmInit();
void mmEnd();
void mmThreadBindToNode( int nodeindex );
void mmThreadBindToNode( int nodeindex );
void mmThreadBindToCpu( int cpuindex );
int mmCpuGetNode( int cpuindex );
void *mmNodeAlloc( int nodeindex, size_t size );
void mmNodeFree( int nodeindex, void *v, size_t size );
void mmNodeMap( int nodeindex, void *start, size_t bytes );
void *mmNodeAlignAlloc( int nodeindex, size_t size, intptr_t align );
void mmNodeAlignFree( int nodeindex, void *v, size_t size );
////
typedef struct
{
void **prev;
void *next;
} mmListNode;
typedef struct
{
void *first;
void **last;
} mmListDualHead;
typedef struct
{
void *first;
void *last;
} mmListLoopHead;
#ifndef MM_INLINE_LIST_FUNCTIONS
void mmListAdd( void **list, void *item, intptr_t offset );
void mmListRemove( void *item, intptr_t offset );
void mmListMergeList( void **listdst, void **listsrc, intptr_t offset );
void mmListMoveList( void **listdst, void **listsrc, intptr_t offset );
void mmListDualInit( mmListDualHead *head );
void mmListDualAddFirst( mmListDualHead *head, void *item, intptr_t offset );
void mmListDualAddLast( mmListDualHead *head, void *item, intptr_t offset );
void mmListDualRemove( mmListDualHead *head, void *item, intptr_t offset );
void *mmListDualLast( mmListDualHead *head, intptr_t offset );
#else
static inline void mmListAdd( void **list, void *item, intptr_t offset )
{
mmListNode *node, *next;
node = ADDRESS( item, offset );
node->prev = list;
node->next = *list;
if( *list )
{
next = ADDRESS( *list, offset );
next->prev = &(node->next);
}
*list = item;
return;
}
static inline void mmListRemove( void *item, intptr_t offset )
{
mmListNode *node, *next;
node = ADDRESS( item, offset );
*(node->prev) = (void *)node->next;
if( node->next )
{
next = ADDRESS( node->next, offset );
next->prev = node->prev;
}
return;
}
static inline void mmListMergeList( void **listdst, void **listsrc, intptr_t offset )
{
void *item;
mmListNode *node;
if( !( *listsrc ) )
return;
for( item = *listdst ; item ; item = node->next )
{
node = ADDRESS( item, offset );
listdst = &node->next;
}
item = *listsrc;
node = ADDRESS( item, offset );
node->prev = listdst;
*listdst = item;
*listsrc = 0;
return;
}
static inline void mmListMoveList( void **listdst, void **listsrc, intptr_t offset )
{
void *item;
mmListNode *node;
if( !( *listsrc ) )
{
*listdst = 0;
return;
}
item = *listsrc;
node = ADDRESS( item, offset );
node->prev = listdst;
*listdst = item;
*listsrc = 0;
return;
}
static inline void mmListDualInit( mmListDualHead *head )
{
head->first = 0;
head->last = &head->first;
return;
}
static inline void mmListDualAddFirst( mmListDualHead *head, void *item, intptr_t offset )
{
mmListNode *node, *next;
node = ADDRESS( item, offset );
node->prev = &head->first;
node->next = head->first;
if( node->next )
{
next = ADDRESS( node->next, offset );
next->prev = &(node->next);
}
else
head->last = &(node->next);
head->first = item;
return;
}
static inline void mmListDualAddLast( mmListDualHead *head, void *item, intptr_t offset )
{
mmListNode *node;
void **prev;
prev = head->last;
*prev = item;
node = ADDRESS( item, offset );
node->prev = head->last;
head->last = &(node->next);
node->next = 0;
return;
}
static inline void mmListDualRemove( mmListDualHead *head, void *item, intptr_t offset )
{
mmListNode *node, *next;
node = ADDRESS( item, offset );
*(node->prev) = (void *)node->next;
if( node->next )
{
next = ADDRESS( node->next, offset );
next->prev = node->prev;
}
else
head->last = node->prev;
return;
}
static inline void *mmListDualLast( mmListDualHead *head, intptr_t offset )
{
if( !( head->first ) )
return 0;
return ADDRESS( head->last, -( offset + offsetof(mmListNode,next) ) );
}
#endif
void mmListLoopInit( mmListLoopHead *head );
void mmListLoopAddFirst( mmListLoopHead *head, void *item, intptr_t offset );
void mmListLoopAddLast( mmListLoopHead *head, void *item, intptr_t offset );
void mmListLoopInsert( mmListLoopHead *head, void *previtem, void *item, intptr_t offset );
void mmListLoopRemove( mmListLoopHead *head, void *item, intptr_t offset );
void *mmListLoopLast( mmListLoopHead *head, intptr_t offset );
////
typedef struct
{
void *child[2];
void *parent;
int flags;
} mmBTreeNode;
#define MM_BTREE_FLAGS_LEFT (0)
#define MM_BTREE_FLAGS_RIGHT (1)
#define MM_BTREE_FLAGS_DIRECTION_MASK (1)
#define MM_BTREE_FLAGS_STEP (2)
void mmBTreeInsert( void *item, void *parent, int itemflag, intptr_t offset, void **root );
void mmBTreeRemove( void *item, intptr_t offset, void **root );
void *mmBtreeMostLeft( void *root, intptr_t offset );
void *mmBtreeMostRight( void *root, intptr_t offset );
void *mmBtreeNeighbourLeft( void *item, intptr_t offset );
void *mmBtreeNeighbourRight( void *item, intptr_t offset );
intptr_t mmBtreeItemCount( void *root, intptr_t offset );
int mmBtreeListOrdered( void *root, intptr_t offset, int (*callback)( void *item, void *v ), void *v );
int mmBtreeListBalanced( void *root, intptr_t offset, int (*callback)( void *item, void *v ), void *v );
////
typedef struct
{
mmListNode listnode;
mmBTreeNode node;
int freecount;
int blockindex;
} mmBlock;
typedef struct
{
void *blocklist;
void *freelist;
size_t chunksize;
int chunkperblock;
int alignment;
size_t allocsize;
int keepfreecount;
int chunkfreecount;
void *treeroot;
void *(*relayalloc)( void *head, size_t bytes MM_PARAMS );
void (*relayfree)( void *head, void *v, size_t bytes MM_PARAMS );
void *relayvalue;
mtSpin spinlock;
} mmBlockHead;
void MM_FUNC(BlockInit)( mmBlockHead *head, size_t chunksize, int chunkperblock, int keepfreecount, int alignment MM_PARAMS );
void MM_FUNC(BlockNodeInit)( mmBlockHead *head, int nodeindex, size_t chunksize, int chunkperblock, int keepfreecount, int alignment MM_PARAMS );
void *MM_FUNC(BlockAlloc)( mmBlockHead *head MM_PARAMS );
void MM_FUNC(BlockRelease)( mmBlockHead *head, void *v MM_PARAMS );
void MM_FUNC(BlockFree)( mmBlockHead *head, void *v MM_PARAMS );
void MM_FUNC(BlockFreeAll)( mmBlockHead *head MM_PARAMS );
void MM_FUNC(BlockProcessList)( mmBlockHead *head, void *userpointer, int (*processchunk)( void *chunk, void *userpointer ) MM_PARAMS );
int MM_FUNC(BlockUseCount)( mmBlockHead *head MM_PARAMS );
int MM_FUNC(BlockFreeCount)( mmBlockHead *head MM_PARAMS );
#if MM_DEBUG
#define mmBlockInit(v,w,x,y,z) MM_FUNC(BlockInit)(v,w,x,y,z,__FILE__,__LINE__)
#define mmBlockNodeInit(u,v,w,x,y,z) MM_FUNC(BlockNodeInit)(u,v,w,x,y,z,__FILE__,__LINE__)
#define mmBlockAlloc(x) MM_FUNC(BlockAlloc)(x,__FILE__,__LINE__)
#define mmBlockRelease(x,y) MM_FUNC(BlockRelease)(x,y,__FILE__,__LINE__)
#define mmBlockFree(x,y) MM_FUNC(BlockFree)(x,y,__FILE__,__LINE__)
#define mmBlockFreeAll(x) MM_FUNC(BlockFreeAll)(x,__FILE__,__LINE__)
#define mmBlockProcessList(x,y,z) MM_FUNC(BlockProcessList)(x,y,z,__FILE__,__LINE__)
#define mmBlockUseCount(x) MM_FUNC(BlockProcessList)(x,__FILE__,__LINE__)
#define mmBlockFreeCount(x) MM_FUNC(BlockProcessList)(x,__FILE__,__LINE__)
#endif
/*
void mmBlockRelayByVolume( mmBlockHead *head, void *volumehead );
void mmBlockRelayByZone( mmBlockHead *head, void *zonehead );
*/
////
typedef struct
{
mmBlockHead indexblock;
void *indextree;
intptr_t indexlimit;
mtSpin spinlock;
} mmIndexHead;
void mmIndexInit( mmIndexHead *head, int indexesperblock );
void mmIndexFreeAll( mmIndexHead *head );
void mmIndexAdd( mmIndexHead *head, intptr_t index );
intptr_t mmIndexGet( mmIndexHead *head );
int mmIndexRemove( mmIndexHead *head, intptr_t index );
size_t mmIndexCount( mmIndexHead *head );
////
typedef struct
{
uintptr_t bitmask;
int bitshift;
uintptr_t countalign;
uintptr_t indexshift;
uintptr_t indexmask;
uintptr_t initmask;
size_t mapsize;
uintptr_t *map;
mtSpin spinlock;
} mmBitTableHead;
void mmBitTableInit( mmBitTableHead *head, int bitsperentry, int chunksize, int initmask );
void mmBitTableFreeAll( mmBitTableHead *head );
void mmBitTableSet( mmBitTableHead *head, uintptr_t index, int flags, int editmask );
uintptr_t mmBitTableGet( mmBitTableHead *head, uintptr_t index );
////
typedef struct
{
size_t size;
size_t used;
void *next;
} mmGrowNode;
typedef struct
{
mmGrowNode *first;
size_t nodesize;
mtSpin spinlock;
} mmGrow;
int MM_FUNC(GrowInit)( mmGrow *mgrow, size_t nodesize MM_PARAMS );
void MM_FUNC(GrowFreeAll)( mmGrow *mgrow MM_PARAMS );
void *MM_FUNC(GrowAlloc)( mmGrow *mgrow, size_t bytes MM_PARAMS );
#if MM_DEBUG
#define mmGrowInit(x,y) MM_FUNC(GrowInit)(x,y,__FILE__,__LINE__)
#define mmGrowFreeAll(x) MM_FUNC(GrowFreeAll)(x,__FILE__,__LINE__)
#define mmGrowAlloc(x,y) MM_FUNC(GrowAlloc)(x,y,__FILE__,__LINE__)
#endif
////
#if 0
typedef struct
{
void ***table;
intptr_t pagecount;
intptr_t pagesize;
intptr_t pagemask;
intptr_t pageshift;
mtSpin spinlock;
} mmDirectory;
#define MM_DIR_ENTRY(dir,index) ( (dir)->table[ index >> (dir)->pageshift ][ index & (dir)->pagemask ] )
int MM_FUNC(DirInit)( mmDirectory *dir, intptr_t pageshift, intptr_t pagecount MM_PARAMS );
void MM_FUNC(DirSize)( mmDirectory *dir, intptr_t size MM_PARAMS );
void MM_FUNC(DirSet)( mmDirectory *dir, intptr_t index, void *entry MM_PARAMS );
void *MM_FUNC(DirGet)( mmDirectory *dir, intptr_t index MM_PARAMS );
void MM_FUNC(DirSetFast)( mmDirectory *dir, intptr_t index, void *entry MM_PARAMS );
void *MM_FUNC(DirGetFast)( mmDirectory *dir, intptr_t index MM_PARAMS );
void MM_FUNC(DirFree)( mmDirectory *dir MM_PARAMS );
#if MM_DEBUG
#define mmDirInit(x,y,z) MM_FUNC(DirInit)(x,y,z,__FILE__,__LINE__)
#define mmDirSize(x,y) MM_FUNC(DirSize)(x,y,__FILE__,__LINE__)
#define mmDirSet(x,y,z) MM_FUNC(DirSet)(x,y,z,__FILE__,__LINE__)
#define mmDirGet(x,y) MM_FUNC(DirGet)(x,y,__FILE__,__LINE__)
#define mmDirSetFast(x,y,z) MM_FUNC(DirSetFast)(x,y,z,__FILE__,__LINE__)
#define mmDirGetFast(x,y) MM_FUNC(DirGetFast)(x,y,__FILE__,__LINE__)
#define mmDirFree(x) MM_FUNC(DirFree)(x,__FILE__,__LINE__)
#endif
#endif
////
void *MM_FUNC(AlignAlloc)( size_t bytes, intptr_t align MM_PARAMS );
void MM_FUNC(AlignFree)( void *v MM_PARAMS );
void *MM_FUNC(AlignGrow)( void *v, size_t bytes, size_t copybytes, intptr_t align MM_PARAMS );
void *MM_FUNC(AlignRelayAlloc)( void *(*relayalloc)( void *head, size_t bytes MM_PARAMS ), void *relayvalue, size_t bytes, intptr_t align, size_t displacement MM_PARAMS );
void MM_FUNC(AlignRelayFree)( void (*relayfree)( void *head, void *v, size_t bytes MM_PARAMS ), void *relayvalue, void *v, size_t bytes MM_PARAMS );
#if MM_DEBUG
#define mmAlignAlloc(x,y) MM_FUNC(AlignAlloc)(x,y,__FILE__,__LINE__)
#define mmAlignFree(x) MM_FUNC(AlignFree)(x,__FILE__,__LINE__)
#define mmAlignGrow(x) MM_FUNC(AlignGrow)(x,__FILE__,__LINE__)
#define mmAlignRelayAlloc(v,w,x,y,z) MM_FUNC(AlignRelayAlloc)(v,w,x,y,z,__FILE__,__LINE__)
#define mmAlignRelayFree(w,x,y,z) MM_FUNC(AlignRelayFree)(w,x,y,z,__FILE__,__LINE__)
#endif
////
typedef struct
{
size_t volumesize;
size_t volumeblocksize;
size_t minchunksize;
size_t volumechunksize;
size_t keepfreesize;
size_t totalfreesize;
size_t alignment;
void *freeroot;
void *volumelist;
void *(*relayalloc)( void *head, size_t bytes MM_PARAMS );
void (*relayfree)( void *head, void *v, size_t bytes MM_PARAMS );
void *relayvalue;
mtSpin spinlock;
} mmVolumeHead;
void MM_FUNC(VolumeInit)( mmVolumeHead *head, size_t volumesize, size_t minchunksize, size_t keepfreesize, size_t alignment MM_PARAMS );
void MM_FUNC(VolumeNodeInit)( mmVolumeHead *head, int nodeindex, size_t volumesize, size_t minchunksize, size_t keepfreesize, size_t alignment MM_PARAMS );
void *MM_FUNC(VolumeAlloc)( mmVolumeHead *head, size_t bytes MM_PARAMS );
void MM_FUNC(VolumeRelease)( mmVolumeHead *head, void *v MM_PARAMS );
void MM_FUNC(VolumeFree)( mmVolumeHead *head, void *v MM_PARAMS );
void MM_FUNC(VolumeShrink)( mmVolumeHead *head, void *v, size_t bytes MM_PARAMS );
size_t MM_FUNC(VolumeGetAllocSize)( mmVolumeHead *head, void *v );
void MM_FUNC(VolumeClean)( mmVolumeHead *head MM_PARAMS );
void MM_FUNC(VolumeFreeAll)( mmVolumeHead *head MM_PARAMS );
void *MM_FUNC(VolumeRealloc)( mmVolumeHead *head, void *v, size_t bytes MM_PARAMS );
#if MM_DEBUG
#define mmVolumeInit(w,x,y,z,a) MM_FUNC(VolumeInit)(w,x,y,z,a,__FILE__,__LINE__);
#define mmVolumeNodeInit(v,w,x,y,z) MM_FUNC(VolumeNodeInit)(v,w,x,y,z,__FILE__,__LINE__);
#define mmVolumeAlloc(x,y) MM_FUNC(VolumeAlloc)(x,y,__FILE__,__LINE__);
#define mmVolumeRelease(x,y) MM_FUNC(VolumeRelease)(x,y,__FILE__,__LINE__);
#define mmVolumeFree(x,y) MM_FUNC(VolumeFree)(x,y,__FILE__,__LINE__);
#define mmVolumeShrink(x,y,z) MM_FUNC(VolumeShrink)(x,y,z,__FILE__,__LINE__);
#define mmVolumeGetAllocSize(x) MM_FUNC(VolumeGetAllocSize)(x,y,__FILE__,__LINE__);
#define mmVolumeClean(x) MM_FUNC(VolumeClean)(x,__FILE__,__LINE__);
#define mmVolumeFreeAll(x) MM_FUNC(VolumeFreeAll)(x,__FILE__,__LINE__);
#define mmVolumeRealloc(x) MM_FUNC(VolumeRealloc)(x,y,z,__FILE__,__LINE__);
#define mmVolumeAlloc MM_FUNC(VolumeAlloc)
#define mmVolumeRelease MM_FUNC(VolumeRelease)
#define mmVolumeFree MM_FUNC(VolumeFree)
#endif
/*
void mmVolumeRelayByZone( mmVolumeHead *head, void *zonehead );
*/
////
typedef struct
{
void *address;
size_t pagesize;
size_t pagealignment;
size_t zonesize;
size_t alignment;
size_t chunkheadersize;
void *chunklist;
mtSpin spinlock;
} mmZoneHead;
int MM_FUNC(ZoneInit)( mmZoneHead *head, size_t zonesize, intptr_t alignment MM_PARAMS );
void *MM_FUNC(ZoneAlloc)( mmZoneHead *head, size_t bytes MM_PARAMS );
void MM_FUNC(ZoneFree)( mmZoneHead *head, void *v MM_PARAMS );
void MM_FUNC(ZoneFreeAll)( mmZoneHead *head MM_PARAMS );
#if MM_DEBUG
#define mmZoneInit(x,y,z) MM_FUNC(ZoneInit)(x,y,z,__FILE__,__LINE__);
#define mmZoneAlloc(x,y) MM_FUNC(ZoneAlloc)(x,y,__FILE__,__LINE__);
#define mmZoneFree(x,y) MM_FUNC(ZoneFree)(x,y,__FILE__,__LINE__);
#define mmZoneFreeAll(x) MM_FUNC(ZoneFreeAll)(x,__FILE__,__LINE__);
#endif
////
void *mmAlloc( void *unused, size_t bytes MM_PARAMS );
void *mmRealloc( void *unused, void *v, size_t bytes MM_PARAMS );
void mmFree( void *unused, void *v, size_t bytes MM_PARAMS );
void *mmDebugAlloc( size_t bytes, char *file, int line );
void *mmDebugRealloc( void *v, size_t bytes, char *file, int line );
void mmDebugFree( void *v, char *file, int line );
#define mmDebugAlloc(x) mmDebugAlloc(x,__FILE__,__LINE__)
#define mmDebugFree(x) mmDebugFree(x,__FILE__,__LINE__)
#define mmDebugRealloc(x,y) mmDebugRealloc(x,y,__FILE__,__LINE__)
void mmListUses( char *file, int line );
#define mmListUses() mmListUses(__FILE__,__LINE__);
////
#if MM_DEBUG
#define malloc(x) mmAlloc(0,(x),__FILE__,__LINE__)
#define realloc(x,y) mmRealloc(0,(x),(y),__FILE__,__LINE__)
#define free(x) mmFree(0,(x),0,__FILE__,__LINE__)
#elif defined(MM_ALLOC_CHECK)
static inline void *mmAllocCheck( size_t size, char *file, int line )
{
void *p;
p = malloc( size );
#if MM_WINDOWS
if( !( p ) )
fprintf( stderr, "WARNING : Denied memory allocation ( %ld bytes ) at %s:%d\n", (long)size, file, line );
#else
if( !( p ) )
fprintf( stderr, "WARNING : Denied memory allocation ( %lld bytes ) at %s:%d\n", (long long)size, file, line );
#endif
return p;
}
static inline void *mmReallocCheck( void *p, size_t size, char *file, int line )
{
p = realloc( p, size );
#if MM_WINDOWS
if( !( p ) )
fprintf( stderr, "WARNING : Denied memory allocation ( %ld bytes ) at %s:%d\n", (long)size, file, line );
#else
if( !( p ) )
fprintf( stderr, "WARNING : Denied memory allocation ( %lld bytes ) at %s:%d\n", (long long)size, file, line );
#endif
return p;
}
#define malloc(x) mmAllocCheck((x),__FILE__,__LINE__)
#define realloc(x,y) mmReallocCheck((x),(y),__FILE__,__LINE__)
#endif
////
static inline uint64_t mmGetMillisecondsTime()
{
struct timeval lntime;
gettimeofday( &lntime, 0 );
return ( (uint64_t)lntime.tv_sec * 1000 ) + ( (uint64_t)lntime.tv_usec / 1000 );
}
static inline uint64_t mmGetMicrosecondsTime()
{
struct timeval lntime;
gettimeofday( &lntime, 0 );
return ( (uint64_t)lntime.tv_sec * 1000000 ) + (uint64_t)lntime.tv_usec;
}
static inline uint64_t mmGetNanosecondsTime()
{
struct timeval lntime;
gettimeofday( &lntime, 0 );
return ( (uint64_t)lntime.tv_sec * 1000000000 ) + ( (uint64_t)lntime.tv_usec * 1000 );
}
////
#ifdef __cplusplus
}
#endif
#endif
+529
View File
@@ -0,0 +1,529 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include "cpuconfig.h"
#include "mm.h"
void mmAtomicListAdd( mmAtomicP *list, void *item, intptr_t offset )
{
mmAtomicListNode *node, *nextnode;
void *nextitem;
node = ADDRESS( item, offset );
mmAtomicWriteP( &node->prev, list );
for( ; ; )
{
/* Mark prev->next as busy */
nextitem = mmAtomicReadP( list );
if( ( nextitem == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( list, nextitem, MM_ATOMIC_LIST_BUSY ) ) )
continue;
mmAtomicWriteP( &node->next, nextitem );
if( nextitem )
{
nextnode = ADDRESS( nextitem, offset );
/* Set next->prev to node->next */
if( !( mmAtomicCmpReplaceP( &nextnode->prev, list, &(node->next) ) ) )
{
mmAtomicWriteP( list, nextitem );
continue;
}
}
mmAtomicWrite32( &node->status, MM_ATOMIC_LIST_VALID );
/* Finally set prev->next to point to the item */
mmAtomicWriteP( list, item );
break;
}
return;
}
void mmAtomicListRemove( void *item, intptr_t offset )
{
mmAtomicListNode *node, *nextnode;
mmAtomicP *prevnext;
void *nextitem;
node = ADDRESS( item, offset );
if( !( mmAtomicCmpReplace32( &node->status, MM_ATOMIC_LIST_VALID, MM_ATOMIC_LIST_DELETED ) ) )
return;
for( ; ; )
{
/* Mark item->next as busy */
nextitem = mmAtomicReadP( &node->next );
if( ( nextitem == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &node->next, nextitem, MM_ATOMIC_LIST_BUSY ) ) )
continue;
/* Mark item->prev as busy */
prevnext = mmAtomicReadP( &node->prev );
if( ( prevnext == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &node->prev, prevnext, MM_ATOMIC_LIST_BUSY ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
continue;
}
/* Mark prev->next as busy */
if( !( mmAtomicCmpReplaceP( prevnext, item, MM_ATOMIC_LIST_BUSY ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
mmAtomicWriteP( &node->prev, prevnext );
continue;
}
/* Fix next item */
if( nextitem )
{
nextnode = ADDRESS( nextitem, offset );
if( !( mmAtomicCmpReplaceP( &nextnode->prev, &node->next, prevnext ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
mmAtomicWriteP( &node->prev, prevnext );
mmAtomicWriteP( prevnext, item );
continue;
}
}
/* Finally set prev->next to point to the next item */
mmAtomicWriteP( prevnext, nextitem );
break;
}
return;
}
void mmAtomicListDualInit( mmAtomicListDualHead *head )
{
mmAtomicWriteP( &head->first, 0 );
mmAtomicWriteP( &head->last, &head->first );
return;
}
void mmAtomicListDualAddFirst( mmAtomicListDualHead *head, void *item, intptr_t offset )
{
mmAtomicListNode *node, *nextnode;
mmAtomicP *nextprev;
void *nextitem;
node = ADDRESS( item, offset );
mmAtomicWriteP( &node->prev, &head->first );
for( ; ; )
{
/* Mark prev->next as busy */
nextitem = mmAtomicReadP( &head->first );
if( ( nextitem == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &head->first, nextitem, MM_ATOMIC_LIST_BUSY ) ) )
continue;
mmAtomicWriteP( &node->next, nextitem );
nextprev = &head->last;
if( nextitem )
{
nextnode = ADDRESS( nextitem, offset );
nextprev = &nextnode->prev;
}
/* Set next->prev to node->next */
if( !( mmAtomicCmpReplaceP( nextprev, &head->first, &(node->next) ) ) )
{
mmAtomicWriteP( &head->first, nextitem );
continue;
}
mmAtomicWrite32( &node->status, MM_ATOMIC_LIST_VALID );
/* Finally set prev->next to point to the item */
mmAtomicWriteP( &head->first, item );
break;
}
return;
}
void mmAtomicListDualAddLast( mmAtomicListDualHead *head, void *item, intptr_t offset )
{
mmAtomicListNode *node;
mmAtomicP *lastnext;
node = ADDRESS( item, offset );
mmAtomicWriteP( &node->next, 0 );
for( ; ; )
{
/* Mark head->last as busy */
lastnext = mmAtomicReadP( &head->last );
if( ( lastnext == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &head->last, lastnext, MM_ATOMIC_LIST_BUSY ) ) )
continue;
mmAtomicWriteP( &node->prev, lastnext );
/* Mark last->next as busy */
if( !( mmAtomicCmpReplaceP( lastnext, 0, MM_ATOMIC_LIST_BUSY ) ) )
{
mmAtomicWriteP( &head->last, lastnext );
continue;
}
/* Set head->first to item if the list is empty */
/*
TODO TODO
firstitem = mmAtomicReadP( &head->first );
if( ( firstitem == MM_ATOMIC_LIST_BUSY ) || ( !( firstitem ) && !( mmAtomicCmpReplaceP( &head->last, MM_ATOMIC_LIST_BUSY, &(node->next) ) ) ) )
{
mmAtomicWriteP( &head->last, lastnext );
mmAtomicWriteP( lastnext, 0 );
continue;
}
*/
mmAtomicWrite32( &node->status, MM_ATOMIC_LIST_VALID );
/* Set prev->next to item */
mmAtomicWriteP( lastnext, item );
/* Finally set head->last to point to node->next */
mmAtomicWriteP( &head->last, &(node->next) );
break;
}
return;
}
void mmAtomicListDualRemove( mmAtomicListDualHead *head, void *item, intptr_t offset )
{
mmAtomicListNode *node, *nextnode;
mmAtomicP *prevnext, *nextprev;
void *nextitem;
node = ADDRESS( item, offset );
if( !( mmAtomicCmpReplace32( &node->status, MM_ATOMIC_LIST_VALID, MM_ATOMIC_LIST_DELETED ) ) )
return;
for( ; ; )
{
/* Mark item->next as busy */
nextitem = mmAtomicReadP( &node->next );
if( ( nextitem == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &node->next, nextitem, MM_ATOMIC_LIST_BUSY ) ) )
continue;
/* Mark item->prev as busy */
prevnext = mmAtomicReadP( &node->prev );
if( ( prevnext == MM_ATOMIC_LIST_BUSY ) || !( mmAtomicCmpReplaceP( &node->prev, prevnext, MM_ATOMIC_LIST_BUSY ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
continue;
}
/* Mark prev->next as busy */
if( !( mmAtomicCmpReplaceP( prevnext, item, MM_ATOMIC_LIST_BUSY ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
mmAtomicWriteP( &node->prev, prevnext );
continue;
}
/* Fix next item */
nextprev = &head->last;
if( nextitem )
{
nextnode = ADDRESS( nextitem, offset );
nextprev = &nextnode->prev;
}
if( !( mmAtomicCmpReplaceP( nextprev, &node->next, prevnext ) ) )
{
mmAtomicWriteP( &node->next, nextitem );
mmAtomicWriteP( &node->prev, prevnext );
mmAtomicWriteP( prevnext, item );
continue;
}
/* Finally set prev->next to point to the next item */
mmAtomicWriteP( prevnext, nextitem );
break;
}
return;
}
////
void mmAtomicBarrierBuild( mmAtomicBarrier *barrier, int childcount, mmAtomicBarrier *parent )
{
mmAtomicWrite32( &barrier->flag, 0 );
barrier->flagref = 0;
barrier->resetvalue = childcount;
mmAtomicWrite32( &barrier->counter, childcount );
barrier->parent = parent;
return;
}
#ifdef CPUCONF_STORE_REODERING_AFTER_STORE
#ifndef MM_ATOMIC_BARRIER_DELAYED_RESET
#undef MM_ATOMIC_BARRIER_DELAYED_RESET
#endif
#endif
#define MM_ATOMIC_BARRIER_NEXTFLAGREF(x) (x+1)
/*
int fooooooo = 0;
*/
int mmAtomicBarrierWait( mmAtomicBarrier *barrier, int32_t spinwaitcounter, mmAtomicBarrierStat *barrierstat )
{
int32_t flagref, nextflagref, spincountdown;
mmAtomicBarrier *leaf;
leaf = barrier;
flagref = barrier->flagref;
#ifdef MM_ATOMIC_BARRIER_DEBUG
if( mmAtomicRead32( &barrier->flag ) != flagref )
printf( "Error, %d != %d\n", mmAtomicRead32( &barrier->flag ), flagref );
#endif
nextflagref = MM_ATOMIC_BARRIER_NEXTFLAGREF( flagref );
for( ; ; )
{
if( !( mmAtomicAddTestZero32( &barrier->counter, -1 ) ) )
break;
#ifndef MM_ATOMIC_BARRIER_DELAYED_RESET
barrier->flagref = nextflagref;
MM_ATOMIC_ACCESS_32(&barrier->counter) += barrier->resetvalue;
#endif
if( barrier->parent )
barrier = barrier->parent;
else
{
/* Barrier fully cleared */
barrierstat->clearcounter++;
#ifndef MM_ATOMIC_BARRIER_DELAYED_RESET
#ifdef CPUCONF_STORE_REODERING_AFTER_STORE
mmWriteBarrier();
#endif
for( barrier = leaf ; barrier ; barrier = barrier->parent )
mmAtomicWrite32( &barrier->flag, nextflagref );
#else
for( barrier = leaf ; barrier ; barrier = barrier->parent )
{
barrier->flagref = nextflagref;
MM_ATOMIC_ACCESS_32(&barrier->counter) += barrier->resetvalue;
/* No barrier : earlier, we disallowed delayed reset if CPUCONF_STORE_REODERING_AFTER_STORE */
mmAtomicWrite32( &barrier->flag, nextflagref );
}
#endif
return 1;
}
}
/* Spin! */
if( !( spinwaitcounter ) )
goto spinyield;
if( !( spincountdown = mmAtomicSpinWaitNeq32Count( &barrier->flag, flagref, spinwaitcounter ) ) )
{
barrierstat->yieldcounter++;
spinyield:
/*
printf( "YIELD %d\n", fooooooo++ );
*/
for( ; mmAtomicRead32( &barrier->flag ) == flagref ; )
mtYield();
}
#ifndef MM_ATOMIC_BARRIER_DELAYED_RESET
#ifdef CPUCONF_STORE_REODERING_AFTER_STORE
mmWriteBarrier();
#endif
for( ; leaf != barrier ; leaf = leaf->parent )
mmAtomicWrite32( &leaf->flag, nextflagref );
#else
for( ; leaf != barrier ; leaf = leaf->parent )
{
leaf->flagref = nextflagref;
MM_ATOMIC_ACCESS_32(&leaf->counter) += leaf->resetvalue;
/* No barrier : earlier, we disallowed delayed reset if CPUCONF_STORE_REODERING_AFTER_STORE */
mmAtomicWrite32( &leaf->flag, nextflagref );
}
#endif
return 0;
}
////
static int mmAtomicCounterBuildStage( mmAtomicCounter *counter, int itembase, int itemcount, int counterstagesize, void *parent, int * const nodeindex )
{
int nodesize, nodebasesize, itemremainder, childcount, nodecount;
mmAtomicCounterNode *node;
if( itemcount == 1 )
{
counter->locknode[itembase] = parent;
return 1;
}
nodebasesize = itemcount / counterstagesize;
itemremainder = itemcount - ( nodebasesize * counterstagesize );
for( nodecount = 0 ; itemcount ; nodecount++, itemcount -= nodesize )
{
nodesize = nodebasesize;
if( nodecount < itemremainder )
nodesize++;
if( nodesize >= 2 )
{
node = &counter->nodearray[ (*nodeindex)++ ];
childcount = mmAtomicCounterBuildStage( counter, itembase, nodesize, counterstagesize, node, nodeindex );
node->resetvalue = childcount;
mmAtomicWrite32( &node->counter, childcount );
node->parent = parent;
}
else
counter->locknode[itembase] = parent;
itembase += nodesize;
}
return nodecount;
}
void mmAtomicCounterInit( mmAtomicCounter *counter, int lockcount, int stagesize )
{
int stagecount, nodecount, childcount;
void *alloc;
mmAtomicCounterNode *node;
counter->nodearray = 0;
stagecount = lockcount;
nodecount = 1;
for( ; stagecount > 1 ; )
{
stagecount = ( stagecount + (stagesize-1) ) / stagesize;
nodecount += stagecount;
}
alloc = mmAlignAlloc( nodecount * sizeof(mmAtomicCounterNode) + lockcount * sizeof(mmAtomicCounterNode *), CPUCONF_CACHE_LINE_SIZE );
counter->lockcount = lockcount;
counter->nodecount = nodecount;
counter->nodearray = alloc;
counter->locknode = ADDRESS( alloc, nodecount * sizeof(mmAtomicCounterNode) );
counter->nodecount = 0;
node = &counter->nodearray[ counter->nodecount++ ];
childcount = mmAtomicCounterBuildStage( counter, 0, lockcount, stagesize, node, &counter->nodecount );
if( counter->nodecount > nodecount )
{
printf( "What the hell?\n" );
exit( 1 );
}
node->resetvalue = childcount;
mmAtomicWrite32( &node->counter, childcount );
node->parent = 0;
return;
}
void mmAtomicCounterDestroy( mmAtomicCounter *counter )
{
if( counter->nodearray )
{
mmAlignFree( counter->nodearray );
counter->nodearray = 0;
}
return;
}
int mmAtomicCounterHit( mmAtomicCounter *counter, int lockindex )
{
mmAtomicCounterNode *node;
node = counter->locknode[lockindex];
for( ; ; )
{
if( !( mmAtomicAddTestZero32( &node->counter, -1 ) ) )
break;
MM_ATOMIC_ACCESS_32(&node->counter) += node->resetvalue;
/*
printf( "Node %d ; %d\n", (int)( node - counter->nodearray ), MM_ATOMIC_ACCESS_32(&node->counter) );
*/
if( node->parent )
node = node->parent;
else
return 1;
}
return 0;
}
/*
Implement a counter without all threads trashing each other's cache
*/
File diff suppressed because it is too large Load Diff
+526
View File
@@ -0,0 +1,526 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include "cpuconfig.h"
#include "cc.h"
#include "mm.h"
#include "mmbinsort.h"
/*
#define MM_BINSORT_INSERTION_SORT
*/
typedef float mmbsf;
#define mmbsffloor(x) floorf(x)
#define mmbsfceil(x) ceilf(x)
typedef struct
{
int itemcount;
int flags;
mmbsf min, max;
void *p;
void **last;
} mmBinSortBucket;
#define MM_BINSORT_BUCKET_FLAGS_SUBGROUP (0x1)
typedef struct
{
mmbsf groupbase, groupmax, bucketrange;
int bucketmax;
mmBinSortBucket bucket[];
} mmBinSortGroup;
typedef struct
{
int numanodeindex;
size_t memsize;
size_t itemlistoffset;
int rootbucketcount; /* Count of buckets for root */
int groupbucketcount; /* Count of buckets per group */
int groupthreshold; /* Count of items required in a bucket */
int collapsethreshold;
int maxdepth;
/* Callback to user code to obtain the value of an item */
double (*itemvalue)( void *item );
/* Memory management */
mmBlockHead bucketblock;
mmBlockHead groupblock;
/* Top-level group, *MUST* be at end of struct due to bucket[] zero-length array */
mmBinSortGroup root;
} mmBinSortHead;
/****/
void *mmBinSortInit( size_t itemlistoffset, int rootbucketcount, int groupbucketcount, double rootmin, double rootmax, int groupthreshold, double (*itemvaluecallback)( void *item ), int maxdepth, int numanodeindex )
{
int bucketindex;
size_t memsize;
mmBinSortHead *bsort;
mmBinSortGroup *group;
mmBinSortBucket *bucket;
if( !( mmcontext.numaflag ) )
numanodeindex = -1;
memsize = sizeof(mmBinSortHead) + ( rootbucketcount * sizeof(mmBinSortBucket) );
if( numanodeindex >= 0 )
{
bsort = mmNodeAlloc( numanodeindex, memsize );
mmBlockNodeInit( &bsort->bucketblock, numanodeindex, sizeof(mmBinSortBucket), 1024, 1024, 0x40 );
mmBlockNodeInit( &bsort->groupblock, numanodeindex, sizeof(mmBinSortGroup) + ( groupbucketcount * sizeof(mmBinSortBucket) ), 16, 16, 0x40 );
}
else
{
bsort = malloc( memsize );
mmBlockInit( &bsort->bucketblock, sizeof(mmBinSortBucket), 1024, 1024, 0x40 );
mmBlockInit( &bsort->groupblock, sizeof(mmBinSortGroup) + ( groupbucketcount * sizeof(mmBinSortBucket) ), 16, 16, 0x40 );
}
bsort->numanodeindex = numanodeindex;
bsort->memsize = memsize;
bsort->itemlistoffset = itemlistoffset;
bsort->rootbucketcount = rootbucketcount;
bsort->groupbucketcount = groupbucketcount;
bsort->groupthreshold = groupthreshold;
bsort->collapsethreshold = groupthreshold >> 2;
bsort->maxdepth = maxdepth;
bsort->itemvalue = itemvaluecallback;
group = &bsort->root;
group->groupbase = rootmin;
group->groupmax = rootmax;
group->bucketrange = ( rootmax - rootmin ) / (double)rootbucketcount;
group->bucketmax = rootbucketcount - 1;
bucket = group->bucket;
for( bucketindex = 0 ; bucketindex < rootbucketcount ; bucketindex++ )
{
bucket->flags = 0;
bucket->itemcount = 0;
bucket->min = FLT_MAX;
bucket->max = -FLT_MAX;
bucket->p = 0;
bucket++;
}
return bsort;
}
void mmBinSortFree( void *binsort )
{
mmBinSortHead *bsort;
bsort = binsort;
mmBlockFreeAll( &bsort->bucketblock );
mmBlockFreeAll( &bsort->groupblock );
if( bsort->numanodeindex >= 0 )
mmNodeFree( bsort->numanodeindex, bsort, bsort->memsize );
else
free( bsort );
return;
}
static int MM_NOINLINE mmBinSortBucketIndex( mmBinSortGroup *group, mmbsf value )
{
int bucketindex = (int)mmbsffloor( ( value - group->groupbase ) / group->bucketrange );
if( bucketindex < 0 )
bucketindex = 0;
if( bucketindex > group->bucketmax )
bucketindex = group->bucketmax;
return bucketindex;
}
/****/
static mmBinSortGroup *mmBinSortSpawnGroup( mmBinSortHead *bsort, void *itembase, mmbsf base, mmbsf range )
{
int bucketindex;
mmbsf value;
void *item, *itemnext;
mmBinSortGroup *group;
mmBinSortBucket *bucket;
group = mmBlockAlloc( &bsort->groupblock );
group->groupbase = base;
group->groupmax = base + range;
group->bucketrange = range / (mmbsf)bsort->groupbucketcount;
group->bucketmax = bsort->groupbucketcount - 1;
bucket = group->bucket;
for( bucketindex = 0 ; bucketindex < bsort->groupbucketcount ; bucketindex++ )
{
bucket->flags = 0;
bucket->itemcount = 0;
bucket->min = FLT_MAX;
bucket->max = -FLT_MAX;
bucket->p = 0;
bucket->last = &bucket->p;
bucket++;
}
for( item = itembase ; item ; item = itemnext )
{
itemnext = ((mmListNode *)ADDRESS( item, bsort->itemlistoffset ))->next;
value = bsort->itemvalue( item );
bucketindex = mmBinSortBucketIndex( group, value );
if( value < bucket->min )
bucket->min = value;
if( value > bucket->max )
bucket->max = value;
bucket = &group->bucket[ bucketindex ];
bucket->itemcount++;
mmListAdd( bucket->last, item, bsort->itemlistoffset );
bucket->last = &((mmListNode *)ADDRESS( item, bsort->itemlistoffset ))->next;
}
return group;
}
/* Debugging */
/*
static int mmBinSortBucketCount( mmBinSortHead *bsort, mmBinSortBucket *bucket )
{
int itemcount;
void *item;
itemcount = 0;
for( item = bucket->p ; item ; item = ((mmListNode *)ADDRESS( item, bsort->itemlistoffset ))->next )
itemcount++;
return itemcount;
}
static int mmBinSortGroupCount( mmBinSortHead *bsort, mmBinSortGroup *group )
{
int itemcount, bucketindex;
mmBinSortBucket *bucket;
bucket = group->bucket;
itemcount = 0;
for( bucketindex = 0, bucket = group->bucket ; bucketindex < bsort->groupbucketcount ; bucketindex++, bucket++ )
{
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
itemcount += mmBinSortGroupCount( bsort, bucket->p );
else
itemcount += mmBinSortBucketCount( bsort, bucket );
}
return itemcount;
}
static void mmBinSortBucketCheck( mmBinSortHead *bsort, mmBinSortBucket *bucket )
{
int itemcount;
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
itemcount = mmBinSortGroupCount( bsort, bucket->p );
else
itemcount = mmBinSortBucketCount( bsort, bucket );
printf( "Countcheck (0x%x) %d ~ %d\n", bucket->flags, itemcount, bucket->itemcount );
if( itemcount != bucket->itemcount )
exit( 1 );
return;
}
*/
static void mmBinSortCollapseGroup( mmBinSortHead *bsort, mmBinSortBucket *parentbucket )
{
int bucketindex, itemcount;
mmBinSortGroup *group;
mmBinSortBucket *bucket;
void *item, *itemnext;
group = parentbucket->p;
parentbucket->p = 0;
parentbucket->last = &parentbucket->p;
itemcount = 0;
for( bucketindex = 0, bucket = group->bucket ; bucketindex < bsort->groupbucketcount ; bucketindex++, bucket++ )
{
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
mmBinSortCollapseGroup( bsort, bucket );
for( item = bucket->p ; item ; item = itemnext )
{
itemnext = ((mmListNode *)ADDRESS( item, bsort->itemlistoffset ))->next;
mmListAdd( parentbucket->last, item, bsort->itemlistoffset );
parentbucket->last = &((mmListNode *)ADDRESS( item, bsort->itemlistoffset ))->next;
itemcount++;
}
}
parentbucket->flags &= ~MM_BINSORT_BUCKET_FLAGS_SUBGROUP;
parentbucket->itemcount = itemcount;
return;
}
/****/
void mmBinSortAdd( void *binsort, void *item, double itemvalue )
{
int bucketindex, depth;
mmbsf value;
mmBinSortHead *bsort;
mmBinSortGroup *group, *subgroup;
mmBinSortBucket *bucket;
bsort = binsort;
value = itemvalue;
group = &bsort->root;
for( depth = 0 ; ; group = bucket->p, depth++ )
{
bucketindex = mmBinSortBucketIndex( group, value );
bucket = &group->bucket[ bucketindex ];
bucket->itemcount++;
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
continue;
if( ( bucket->itemcount >= bsort->groupthreshold ) && ( depth < bsort->maxdepth ) )
{
/* Build a new sub group, sort all entries into it */
subgroup = mmBinSortSpawnGroup( bsort, bucket->p, group->groupbase + ( (mmbsf)bucketindex * group->bucketrange ), group->bucketrange );
bucket->flags |= MM_BINSORT_BUCKET_FLAGS_SUBGROUP;
bucket->p = subgroup;
continue;
}
if( value < bucket->min )
bucket->min = value;
if( value > bucket->max )
bucket->max = value;
#ifdef MM_BINSORT_INSERTION_SORT
void *itemfind, *itemnext;
void **insert;
insert = &bucket->p;
for( itemfind = bucket->p ; itemfind ; itemfind = itemnext )
{
itemnext = ((mmListNode *)ADDRESS( itemfind, bsort->itemlistoffset ))->next;
if( itemvalue <= bsort->itemvalue( itemfind ) )
break;
insert = &((mmListNode *)ADDRESS( itemfind, bsort->itemlistoffset ))->next;
}
mmListAdd( insert, item, bsort->itemlistoffset );
#else
mmListAdd( &bucket->p, item, bsort->itemlistoffset );
#endif
break;
}
return;
}
void mmBinSortRemove( void *binsort, void *item, double itemvalue )
{
int bucketindex;
mmbsf value;
mmBinSortHead *bsort;
mmBinSortGroup *group;
mmBinSortBucket *bucket;
bsort = binsort;
value = itemvalue;
group = &bsort->root;
for( ; ; group = bucket->p )
{
bucketindex = mmBinSortBucketIndex( group, value );
bucket = &group->bucket[ bucketindex ];
bucket->itemcount--;
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
{
if( bucket->itemcount >= bsort->collapsethreshold )
continue;
mmBinSortCollapseGroup( bsort, bucket );
}
break;
}
mmListRemove( item, bsort->itemlistoffset );
return;
}
void mmBinSortUpdate( void *binsort, void *item, double olditemvalue, double newitemvalue )
{
mmBinSortRemove( binsort, item, olditemvalue );
mmBinSortAdd( binsort, item, newitemvalue );
return;
}
/****/
void *mmBinSortGetRootBucket( void *binsort, int bucketindex, int *itemcount )
{
mmBinSortHead *bsort;
mmBinSortBucket *bucket;
bsort = binsort;
bucket = &bsort->root.bucket[ bucketindex ];
*itemcount = bucket->itemcount;
return bucket->p;
}
void *mmBinSortGetGroupBucket( void *binsortgroup, int bucketindex, int *itemcount )
{
mmBinSortGroup *group;
mmBinSortBucket *bucket;
group = binsortgroup;
bucket = &group->bucket[ bucketindex ];
*itemcount = bucket->itemcount;
return bucket->p;
}
/****/
static void *mmBinSortGroupFirstItem( mmBinSortHead *bsort, mmBinSortGroup *group, mmbsf failmax )
{
int bucketindex, topbucket;
void *item;
mmBinSortBucket *bucket;
mmBinSortGroup *subgroup;
if( failmax > group->groupmax )
topbucket = group->bucketmax;
else
{
topbucket = (int)mmbsfceil( ( failmax - group->groupbase ) / group->bucketrange );
if( ( topbucket < 0 ) || ( topbucket > group->bucketmax ) )
topbucket = group->bucketmax;
}
/*
printf( " Failmax %f ; Base %f ; Range %f ; Index %f\n", failmax, group->groupbase, group->bucketrange, mmbsfceil( failmax - group->groupbase ) / group->bucketrange );
printf( " Top bucket : %d\n", topbucket );
*/
bucket = group->bucket;
for( bucketindex = 0 ; bucketindex <= topbucket ; bucketindex++, bucket++ )
{
/*
printf( " Bucket %d ; Count %d ; Flags 0x%x ; %p\n", bucketindex, bucket->itemcount, bucket->flags, bucket->p );
*/
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
{
subgroup = bucket->p;
item = mmBinSortGroupFirstItem( bsort, subgroup, failmax );
if( item )
return item;
}
else if( bucket->p )
return bucket->p;
}
return 0;
}
void *mmBinSortGetFirstItem( void *binsort, double failmax )
{
int bucketindex, topbucket;
mmBinSortHead *bsort;
mmBinSortGroup *group;
mmBinSortBucket *bucket;
void *item;
bsort = binsort;
if( failmax > bsort->root.groupmax )
topbucket = bsort->root.bucketmax;
else
{
topbucket = (int)mmbsfceil( ( (mmbsf)failmax - bsort->root.groupbase ) / bsort->root.bucketrange );
if( ( topbucket < 0 ) || ( topbucket > bsort->root.bucketmax ) )
topbucket = bsort->root.bucketmax;
}
/*
printf( "TopBucket : %d / %d\n", topbucket, bsort->root.bucketmax );
*/
bucket = bsort->root.bucket;
for( bucketindex = 0 ; bucketindex <= topbucket ; bucketindex++, bucket++ )
{
/*
printf( " Bucket %d ; Count %d ; Flags 0x%x ; %p\n", bucketindex, bucket->itemcount, bucket->flags, bucket->p );
*/
if( bucket->flags & MM_BINSORT_BUCKET_FLAGS_SUBGROUP )
{
group = bucket->p;
item = mmBinSortGroupFirstItem( bsort, group, (mmbsf)failmax );
if( item )
return item;
}
else if( bucket->p )
return bucket->p;
}
return 0;
}
/****/
+43
View File
@@ -0,0 +1,43 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
void *mmBinSortInit( size_t itemlistoffset, int rootbucketcount, int groupbucketcount, double rootmin, double rootmax, int groupthreshold, double (*itemvaluecallback)( void *item ), int maxdepth, int numanodeindex );
void mmBinSortFree( void *binsort );
void mmBinSortAdd( void *binsort, void *item, double itemvalue );
void mmBinSortRemove( void *binsort, void *item, double itemvalue );
void mmBinSortUpdate( void *binsort, void *item, double olditemvalue, double newitemvalue );
void *mmBinSortGetRootBucket( void *binsort, int bucketindex, int *itemcount );
void *mmBinSortGetGroupBucket( void *binsortgroup, int bucketindex, int *itemcount );
void *mmBinSortGetFirstItem( void *binsort, double failmax );
+487
View File
@@ -0,0 +1,487 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "cpuconfig.h"
#include "cc.h"
#include "mm.h"
#include "mmbitmap.h"
/* Friendlier to cache on SMP systems */
#define BP_BITMAP_PREWRITE_CHECK
/*
TODO
If we don't have atomic instruction support, we need a much better mutex locking mechanism!!
*/
void mmBitMapInit( mmBitMap *bitmap, size_t entrycount, int initvalue )
{
size_t mapsize, index;
long value;
#ifdef MM_ATOMIC_SUPPORT
mmAtomicL *map;
#else
long *map;
#endif
mapsize = ( entrycount + CPUCONF_LONG_BITS - 1 ) >> CPUCONF_LONG_BITSHIFT;
bitmap->map = malloc( mapsize * sizeof(mmAtomicL) );
bitmap->mapsize = mapsize;
bitmap->entrycount = entrycount;
map = bitmap->map;
value = ( initvalue & 0x1 ? ~0x0 : 0x0 );
#ifdef MM_ATOMIC_SUPPORT
for( index = 0 ; index < mapsize ; index++ )
mmAtomicWriteL( &map[index], value );
#else
for( index = 0 ; index < mapsize ; index++ )
map[index] = value;
mtMutexInit( &bitmap->mutex );
#endif
return;
}
void mmBitMapReset( mmBitMap *bitmap, int resetvalue )
{
size_t index;
long value;
#ifdef MM_ATOMIC_SUPPORT
mmAtomicL *map;
#else
long *map;
#endif
map = bitmap->map;
value = ( resetvalue & 0x1 ? ~(long)0x0 : (long)0x0 );
#ifdef MM_ATOMIC_SUPPORT
for( index = 0 ; index < bitmap->mapsize ; index++ )
mmAtomicWriteL( &map[index], value );
#else
for( index = 0 ; index < bitmap->mapsize ; index++ )
map[index] = value;
#endif
return;
}
void mmBitMapFree( mmBitMap *bitmap )
{
free( bitmap->map );
bitmap->map = 0;
bitmap->mapsize = 0;
#ifndef MM_ATOMIC_SUPPORT
mtMutexDestroy( &bitmap->mutex );
#endif
return;
}
int mmBitMapDirectGet( mmBitMap *bitmap, size_t entryindex )
{
int value;
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = ( MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) >> shift ) & 0x1;
#else
value = ( bitmap->map[index] >> shift ) & 0x1;
#endif
return value;
}
void mmBitMapDirectSet( mmBitMap *bitmap, size_t entryindex )
{
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) |= (long)1 << shift;
#else
bitmap->map[index] |= (long)1 << shift;
#endif
return;
}
void mmBitMapDirectClear( mmBitMap *bitmap, size_t entryindex )
{
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) &= ~( (long)1 << shift );
#else
bitmap->map[index] &= ~( (long)1 << shift );
#endif
return;
}
int mmBitMapDirectMaskGet( mmBitMap *bitmap, size_t entryindex, long mask )
{
int value;
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = ( MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) >> shift ) & mask;
#else
value = ( bitmap->map[index] >> shift ) & mask;
#endif
return value;
}
void mmBitMapDirectMaskSet( mmBitMap *bitmap, size_t entryindex, long value, long mask )
{
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) = ( MM_ATOMIC_ACCESS_L( &bitmap->map[index] ) & ~( mask << shift ) ) | ( value << shift );
#else
bitmap->map[index] = ( bitmap->map[index] & ~( mask << shift ) ) | ( value << shift );
#endif
return;
}
int mmBitMapGet( mmBitMap *bitmap, size_t entryindex )
{
int value;
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = ( mmAtomicReadL( &bitmap->map[index] ) >> shift ) & 0x1;
#else
mtMutexLock( &bitmap->mutex );
value = ( bitmap->map[index] >> shift ) & 0x1;
mtMutexUnlock( &bitmap->mutex );
#endif
return value;
}
void mmBitMapSet( mmBitMap *bitmap, size_t entryindex )
{
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
#ifdef BP_BITMAP_PREWRITE_CHECK
if( !( mmAtomicReadL( &bitmap->map[index] ) & ( (long)1 << shift ) ) )
mmAtomicOrL( &bitmap->map[index], (long)1 << shift );
#else
mmAtomicOrL( &bitmap->map[index], (long)1 << shift );
#endif
#else
mtMutexLock( &bitmap->mutex );
bitmap->map[index] |= (long)1 << shift;
mtMutexUnlock( &bitmap->mutex );
#endif
return;
}
void mmBitMapClear( mmBitMap *bitmap, size_t entryindex )
{
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
#ifdef BP_BITMAP_PREWRITE_CHECK
if( mmAtomicReadL( &bitmap->map[index] ) & ( (long)1 << shift ) )
mmAtomicAndL( &bitmap->map[index], ~( (long)1 << shift ) );
#else
mmAtomicAndL( &bitmap->map[index], ~( (long)1 << shift ) );
#endif
#else
mtMutexLock( &bitmap->mutex );
bitmap->map[index] &= ~( (long)1 << shift );
mtMutexUnlock( &bitmap->mutex );
#endif
return;
}
int mmBitMapMaskGet( mmBitMap *bitmap, size_t entryindex, long mask )
{
int value;
size_t index, shift;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = ( mmAtomicReadL( &bitmap->map[index] ) >> shift ) & mask;
#else
mtMutexLock( &bitmap->mutex );
value = ( bitmap->map[index] >> shift ) & mask;
mtMutexUnlock( &bitmap->mutex );
#endif
return value;
}
void mmBitMapMaskSet( mmBitMap *bitmap, size_t entryindex, long value, long mask )
{
size_t index, shift;
long oldvalue, newvalue;
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shift = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
for( ; ; )
{
oldvalue = mmAtomicReadL( &bitmap->map[index] );
newvalue = ( oldvalue & ~( mask << shift ) ) | ( value << shift );
if( mmAtomicCmpReplaceL( &bitmap->map[index], oldvalue, newvalue ) )
break;
}
#else
mtMutexLock( &bitmap->mutex );
bitmap->map[index] = ( bitmap->map[index] & ~( mask << shift ) ) | ( value << shift );
mtMutexUnlock( &bitmap->mutex );
#endif
return;
}
/* TODO: Yeah... That code was written in one go, maybe I should test if it's working fine, just in case? */
int mmBitMapFindSet( mmBitMap *bitmap, size_t entryindex, size_t entryindexlast, size_t *retentryindex )
{
unsigned long value;
size_t index, shift, shiftbase, shiftmax, indexlast, shiftlast;
indexlast = entryindexlast >> CPUCONF_LONG_BITSHIFT;
shiftlast = entryindexlast & ( CPUCONF_LONG_BITS - 1 );
/* Leading bits search */
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shiftbase = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
mtMutexLock( &bitmap->mutex );
value = bitmap->map[index];
#endif
if( value != (unsigned long)0x0 )
{
shiftmax = CPUCONF_LONG_BITS;
if( ( index == indexlast ) && ( shiftlast > shiftbase ) )
shiftmax = shiftlast;
value >>= shiftbase;
for( shift = shiftbase ; shift < shiftmax ; shift++, value >>= 1 )
{
if( !( value & 0x1 ) )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
*retentryindex = entryindex;
return 1;
}
}
if( ( index == indexlast ) && ( shiftlast > shiftbase ) )
{
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
return 0;
}
/* Main search */
for( ; ; )
{
index = ( index + 1 ) % bitmap->mapsize;
if( index == indexlast )
break;
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
value = bitmap->map[index];
#endif
if( value != (unsigned long)0x0 )
{
for( shift = 0 ; ; shift++, value >>= 1 )
{
if( !( value & 0x1 ) )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
*retentryindex = entryindex;
return 1;
}
}
}
/* Trailing bits search */
shiftlast = entryindexlast & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
value = bitmap->map[index];
#endif
if( value != (unsigned long)0x0 )
{
for( shift = 0 ; shift < shiftlast ; shift++, value >>= 1 )
{
if( !( value & 0x1 ) )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
if( ( index == indexlast ) && ( shift >= shiftlast ) )
return 0;
*retentryindex = entryindex;
return 1;
}
}
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
return 0;
}
int mmBitMapFindClear( mmBitMap *bitmap, size_t entryindex, size_t entryindexlast, size_t *retentryindex )
{
unsigned long value;
size_t index, shift, shiftbase, shiftmax, indexlast, shiftlast;
indexlast = entryindexlast >> CPUCONF_LONG_BITSHIFT;
shiftlast = entryindexlast & ( CPUCONF_LONG_BITS - 1 );
/* Leading bits search */
index = entryindex >> CPUCONF_LONG_BITSHIFT;
shiftbase = entryindex & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
mtMutexLock( &bitmap->mutex );
value = bitmap->map[index];
#endif
if( value != ~(unsigned long)0x0 )
{
shiftmax = CPUCONF_LONG_BITS;
if( ( index == indexlast ) && ( shiftlast > shiftbase ) )
shiftmax = shiftlast;
value >>= shiftbase;
for( shift = shiftbase ; shift < shiftmax ; shift++, value >>= 1 )
{
if( value & 0x1 )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
*retentryindex = entryindex;
return 1;
}
}
if( ( index == indexlast ) && ( shiftlast > shiftbase ) )
{
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
return 0;
}
/* Main search */
for( ; ; )
{
index = ( index + 1 ) % bitmap->mapsize;
if( index == indexlast )
break;
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
value = bitmap->map[index];
#endif
if( value != ~(unsigned long)0x0 )
{
for( shift = 0 ; ; shift++, value >>= 1 )
{
if( value & 0x1 )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
*retentryindex = entryindex;
return 1;
}
}
}
/* Trailing bits search */
shiftlast = entryindexlast & ( CPUCONF_LONG_BITS - 1 );
#ifdef MM_ATOMIC_SUPPORT
value = mmAtomicReadL( &bitmap->map[index] );
#else
value = bitmap->map[index];
#endif
if( value != ~(unsigned long)0x0 )
{
for( shift = 0 ; shift < shiftlast ; shift++, value >>= 1 )
{
if( value & 0x1 )
continue;
entryindex = ( index << CPUCONF_LONG_BITSHIFT ) | shift;
if( entryindex >= bitmap->entrycount )
break;
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
if( ( index == indexlast ) && ( shift >= shiftlast ) )
return 0;
*retentryindex = entryindex;
return 1;
}
}
#ifndef MM_ATOMIC_SUPPORT
mtMutexUnlock( &bitmap->mutex );
#endif
return 0;
}
+63
View File
@@ -0,0 +1,63 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
typedef struct
{
size_t entrycount;
size_t mapsize;
#ifdef MM_ATOMIC_SUPPORT
mmAtomicL *map;
#else
long *map;
mtMutex mutex;
#endif
} mmBitMap;
void mmBitMapInit( mmBitMap *bitmap, size_t entrycount, int initvalue );
void mmBitMapReset( mmBitMap *bitmap, int resetvalue );
void mmBitMapFree( mmBitMap *bitmap );
int mmBitMapDirectGet( mmBitMap *bitmap, size_t entryindex );
void mmBitMapDirectSet( mmBitMap *bitmap, size_t entryindex );
void mmBitMapDirectClear( mmBitMap *bitmap, size_t entryindex );
int mmBitMapDirectMaskGet( mmBitMap *bitmap, size_t entryindex, long mask );
void mmBitMapDirectMaskSet( mmBitMap *bitmap, size_t entryindex, long value, long mask );
int mmBitMapGet( mmBitMap *bitmap, size_t entryindex );
void mmBitMapSet( mmBitMap *bitmap, size_t entryindex );
void mmBitMapClear( mmBitMap *bitmap, size_t entryindex );
int mmBitMapMaskGet( mmBitMap *bitmap, size_t entryindex, long mask );
void mmBitMapMaskSet( mmBitMap *bitmap, size_t entryindex, long value, long mask );
int mmBitMapFindSet( mmBitMap *bitmap, size_t entryindex, size_t entryindexlast, size_t *retentryindex );
int mmBitMapFindClear( mmBitMap *bitmap, size_t entryindex, size_t entryindexlast, size_t *retentryindex );
File diff suppressed because it is too large Load Diff
+154
View File
@@ -0,0 +1,154 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
/*
#define MM_HASH_DEBUG_STATISTICS
*/
enum
{
MM_HASH_ENTRYCMP_INVALID,
MM_HASH_ENTRYCMP_FOUND,
MM_HASH_ENTRYCMP_SKIP
};
enum
{
MM_HASH_ENTRYLIST_BREAK,
MM_HASH_ENTRYLIST_CONTINUE
};
typedef struct
{
/* Clear the entry so that entryvalid() returns zero */
void (*clearentry)( void *entry );
/* Returns non-zero if the entry is valid and existing */
int (*entryvalid)( void *entry );
/* Return key for an arbitrary set of user-defined data */
uint32_t (*entrykey)( void *entry );
/* Return MM_HASH_ENTRYCMP* to stop or continue the search */
int (*entrycmp)( void *entry, void *entryref );
/* Return MM_HASH_ENTRYLIST* to stop or continue the search */
int (*entrylist)( void *opaque, void *entry, void *entryref );
} mmHashAccess;
/* Do not keep track of entry count, table will not be able to say when it needs to shrink or grow */
#define MM_HASH_FLAGS_NO_COUNT (0x1)
size_t mmHashRequiredSize( size_t entrysize, uint32_t hashbits, uint32_t pageshift );
void mmHashInit( void *hashtable, mmHashAccess *access, size_t entrysize, uint32_t hashbits, uint32_t pageshift, uint32_t flags );
int mmHashGetStatus( void *hashtable, int *rethashbits );
enum
{
MM_HASH_STATUS_MUSTGROW,
MM_HASH_STATUS_MUSTSHRINK,
MM_HASH_STATUS_NORMAL,
MM_HASH_STATUS_UNKNOWN
};
void *mmHashDirectFindEntry( void *hashtable, mmHashAccess *access, void *findentry );
void *mmHashLockFindEntry( void *hashtable, mmHashAccess *access, void *findentry );
void mmHashDirectListEntry( void *hashtable, mmHashAccess *access, void *listentry, void *opaque );
void mmHashLockListEntry( void *hashtable, mmHashAccess *access, void *listentry, void *opaque );
int mmHashDirectReadEntry( void *hashtable, mmHashAccess *access, void *readentry );
int mmHashLockReadEntry( void *hashtable, mmHashAccess *access, void *readentry );
int mmHashDirectCallEntry( void *hashtable, mmHashAccess *access, void *callentry, void (*callback)( void *opaque, void *entry, int newflag ), void *opaque, int addflag );
int mmHashLockCallEntry( void *hashtable, mmHashAccess *access, void *callentry, void (*callback)( void *opaque, void *entry, int newflag ), void *opaque, int addflag );
/* The hash key for replaced entries must remain the same! */
int mmHashDirectReplaceEntry( void *hashtable, mmHashAccess *access, void *replaceentry, int addflag );
int mmHashLockReplaceEntry( void *hashtable, mmHashAccess *access, void *replaceentry, int addflag );
int mmHashDirectAddEntry( void *hashtable, mmHashAccess *access, void *adddentry, int nodupflag );
int mmHashLockAddEntry( void *hashtable, mmHashAccess *access, void *adddentry, int nodupflag );
int mmHashDirectDeleteEntry( void *hashtable, mmHashAccess *access, void *deleteentry, int readflag );
int mmHashLockDeleteEntry( void *hashtable, mmHashAccess *access, void *deleteentry, int readflag );
void mmHashResize( void *newtable, void *oldtable, mmHashAccess *access, uint32_t hashbits, uint32_t pageshift );
enum
{
MM_HASH_FAILURE,
MM_HASH_SUCCESS,
MM_HASH_TRYAGAIN /* Internal, can not be returned by any public call */
};
////
typedef struct
{
uint32_t hashkey;
uint32_t pagestart;
uint32_t pagefinal;
void *next;
} mmHashLockRange;
typedef struct
{
void *hashtable;
void *rangelist;
int newcount;
} mmHashLock;
void mmHashLockInit( mmHashLock *hashlock, int newcount );
void mmHashLockAdd( void *hashtable, mmHashAccess *access, void *entry, mmHashLock *hashlock, mmHashLockRange *lockrange );
void mmHashLockAcquire( void *hashtable, mmHashAccess *access, mmHashLock *hashlock );
void mmHashLockRelease( void *hashtable, mmHashLock *hashlock );
void mmHashGlobalLockEnable( void *hashtable );
void mmHashGlobalLockDisable( void *hashtable );
////
void mmHashDirectDebugDuplicate( void *hashtable, mmHashAccess *access, void (*callback)( void *opaque, void *entry0, void *entry1 ), void *opaque );
void mmHashDirectDebugPages( void *hashtable );
void mmHashStatistics( void *hashtable, long *accesscount, long *collisioncount, long *relocationcount, long *entrycount, long *entrycountmax, long *hashsizemax );
+540
View File
@@ -0,0 +1,540 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
/**
* @file
*
* Threading interface, POSIX implementation.
*/
#ifndef STAND_ALONE_MD
#if defined(COMPILE_FOR_VSL)
#define MT_QT
#endif
#endif
#if defined(MT_QT)
#include "mmthreadqt.h"
#elif defined(MT_DISABLED)
struct mtNull
{
};
typedef struct mtNull mtMutex;
typedef struct mtNull mtSpin;
typedef struct mtNull mtSignal;
#define mtMutexInit(a)
#define mtMutexDestroy(a)
#define mtMutexLock(a)
#define mtMutexUnlock(a)
#define mtMutexTryLock(a)
#define mtSpinInit(a)
#define mtSpinDestroy(a)
#define mtSpinLock(a)
#define mtSpinUnlock(a)
#define mtSpinTryLock(a)
#define mtSignalInit(a)
#define mtSignalDestroy(a)
#define mtSignalDispatch(a)
#define mtSignalBroadcast(a)
#define mtSignalMutexWait(a,b)
#else
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <limits.h>
#if _POSIX_SPIN_LOCKS > 0
#define MT_SPIN_LOCK_SUPPORT
#endif
/*
#define MT_BARRIER_SUPPORT
#define MT_RWLOCK_SUPPORT
*/
static inline void mtYield()
{
sched_yield();
return;
}
typedef struct mtThread mtThread;
struct mtThread
{
pthread_t pthread;
};
#define MT_THREAD_FLAGS_JOINABLE (0x1)
#define MT_THREAD_FLAGS_SETSTACK (0x2)
static inline void mtThreadCreate( mtThread *thread, void *(*threadmain)( void *value ), void *value, int flags, void *stack, size_t stacksize )
{
pthread_attr_t attr;
pthread_attr_init( &attr );
#if !MM_WIN32 && !MM_WIN64
if( flags & MT_THREAD_FLAGS_SETSTACK )
pthread_attr_setstack( &attr, stack, stacksize );
#endif
if( flags & MT_THREAD_FLAGS_JOINABLE )
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
else
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
pthread_create( &thread->pthread, &attr, threadmain, value );
pthread_attr_destroy( &attr );
return;
}
static inline void mtThreadExit()
{
pthread_exit( 0 );
return;
}
static inline void mtThreadJoin( mtThread *thread )
{
void *ret;
pthread_join( thread->pthread, &ret );
return;
}
static inline size_t mtGetMinimumStackSize()
{
#ifdef PTHREAD_STACK_MIN
return PTHREAD_STACK_MIN;
#else
return ( mmcontext.pagesize ? 4*mmcontext.pagesize : 16384 );
#endif
}
#ifdef MT_DEBUG
#ifndef DEBUG_WARNING()
#define DEBUG_WARNING() ({printf( "\nRF WARNING : %s %s %d\n", __FILE__, __FUNCTION__, __LINE__ ); fflush( stdout );})
#endif
#endif
typedef struct mtMutex mtMutex;
struct mtMutex
{
#ifdef MT_DEBUG
unsigned char *function;
unsigned char *file;
int line;
#endif
pthread_mutex_t pmutex;
};
static inline void mtMutexInit( mtMutex *mutex )
{
pthread_mutex_init( &mutex->pmutex, 0 );
return;
}
static inline void mtMutexDestroy( mtMutex *mutex )
{
pthread_mutex_destroy( &mutex->pmutex );
return;
}
#ifdef MT_DEBUG
#define mtMutexLock(a) mtMutexLockDebug(a,__FUNCTION__,__FILE__,__LINE__)
#define mtMutexUnlock(a) mtMutexUnlockDebug(a,__FUNCTION__,__FILE__,__LINE__)
#define mtMutexTryLock(a) mtMutexTryLockDebug(a,__FUNCTION__,__FILE__,__LINE__)
static inline void mtMutexLockDebug( mtMutex *mutex, const unsigned char *function, const unsigned char *file, const int line )
{
printf( "Mutex lock : Thread %d on %p from %s() in %s:%d\n", (int)pthread_self(), mutex, function, file, line );
fflush( stdout );
if( pthread_mutex_trylock( &mutex->pmutex ) )
{
printf( " Mutex %p locked by %s() in %s:%d\n", mutex, mutex->function, mutex->file, mutex->line );
fflush( stdout );
if( pthread_mutex_lock( &mutex->pmutex ) )
DEBUG_WARNING();
}
mutex->function = (unsigned char *)function;
mutex->file = (unsigned char *)file;
mutex->line = line;
return;
}
static inline void mtMutexUnlockDebug( mtMutex *mutex, const unsigned char *function, const unsigned char *file, const int line )
{
mutex->function = (unsigned char *)function;
mutex->file = (unsigned char *)file;
mutex->line = line;
printf( "Mutex Unlock : Thread %d on %p from %s() in %s:%d\n", (int)pthread_self(), mutex, function, file, line );
fflush( stdout );
if( pthread_mutex_unlock( &mutex->pmutex ) )
DEBUG_WARNING();
return;
}
static inline int mtMutexTryLockDebug( mtMutex *mutex, const unsigned char *function, const unsigned char *file, const int line )
{
printf( "Mutex Trylock : Thread %d on %p from %s() in %s:%d\n", (int)pthread_self(), mutex, function, file, line );
fflush( stdout );
if( !( pthread_mutex_trylock( &mutex->pmutex ) ) )
{
mutex->function = (unsigned char *)function;
mutex->file = (unsigned char *)file;
mutex->line = line;
return 1;
}
else
return 0;
}
#else
static inline void mtMutexLock( mtMutex *mutex )
{
pthread_mutex_lock( &mutex->pmutex );
return;
}
static inline void mtMutexUnlock( mtMutex *mutex )
{
pthread_mutex_unlock( &mutex->pmutex );
return;
}
static inline int mtMutexTryLock( mtMutex *mutex )
{
return !( pthread_mutex_trylock( &mutex->pmutex ) );
}
#endif
////
typedef struct mtSignal mtSignal;
struct mtSignal
{
pthread_cond_t pcond;
};
static inline void mtSignalInit( mtSignal *signal )
{
pthread_cond_init( &signal->pcond, 0 );
return;
}
static inline void mtSignalDestroy( mtSignal *signal )
{
pthread_cond_destroy( &signal->pcond );
return;
}
static inline void mtSignalWake( mtSignal *signal )
{
#ifdef MT_DEBUG
if( pthread_cond_signal( &signal->pcond ) )
DEBUG_WARNING();
#else
pthread_cond_signal( &signal->pcond );
#endif
return;
}
static inline void mtSignalBroadcast( mtSignal *signal )
{
#ifdef MT_DEBUG
if( pthread_cond_broadcast( &signal->pcond ) )
DEBUG_WARNING();
#else
pthread_cond_broadcast( &signal->pcond );
#endif
return;
}
static inline void mtSignalWait( mtSignal *signal, mtMutex *mutex )
{
#ifdef MT_DEBUG
if( pthread_cond_wait( &signal->pcond, &mutex->pmutex ) )
DEBUG_WARNING();
#else
pthread_cond_wait( &signal->pcond, &mutex->pmutex );
#endif
return;
}
static inline void mtSignalWaitTimeout( mtSignal *signal, mtMutex *mutex, long milliseconds )
{
uint64_t microsecs;
struct timespec ts;
struct timeval tp;
gettimeofday( &tp, NULL );
ts.tv_sec = tp.tv_sec + ( milliseconds / 1000 );
microsecs = tp.tv_usec + ( ( milliseconds % 1000 ) * 1000 );
if( microsecs >= 1000000 )
{
ts.tv_sec++;
microsecs -= 1000000;
}
ts.tv_nsec = microsecs * 1000;
pthread_cond_timedwait( &signal->pcond, &mutex->pmutex, &ts );
return;
}
#ifdef MT_DEBUG
#define MT_MUTEX_INITIALIZER { 0, 0, 0, PTHREAD_MUTEX_INITIALIZER }
#else
#define MT_MUTEX_INITIALIZER { PTHREAD_MUTEX_INITIALIZER }
#endif
////
#ifdef MM_ATOMIC_SUPPORT
typedef struct mtSpin mtSpin;
struct mtSpin
{
mmAtomic32 atomicspin;
};
static inline void mtSpinInit( mtSpin *spin )
{
mmAtomicWrite32( &spin->atomicspin, 0x0 );
return;
}
static inline void mtSpinDestroy( mtSpin *spin )
{
return;
}
static inline void mtSpinLock( mtSpin *spin )
{
mmAtomicSpin32( &spin->atomicspin, 0x0, 0x1 );
return;
}
static inline void mtSpinUnlock( mtSpin *spin )
{
mmAtomicWrite32( &spin->atomicspin, 0x0 );
return;
}
static inline int mtSpinTryLock( mtSpin *spin )
{
return mmAtomicCmpReplace32( &spin->atomicspin, 0x0, 0x1 );
}
#elif _POSIX_SPIN_LOCKS > 0
typedef struct mtSpin mtSpin;
struct mtSpin
{
#ifdef MT_DEBUG
unsigned char *function;
unsigned char *file;
int line;
#endif
pthread_spinlock_t pspinlock;
};
static inline void mtSpinInit( mtSpin *spin )
{
pthread_spin_init( &spin->pspinlock, PTHREAD_PROCESS_PRIVATE );
return;
}
static inline void mtSpinDestroy( mtSpin *spin )
{
pthread_spin_destroy( &spin->pspinlock );
return;
}
static inline void mtSpinLock( mtSpin *spin )
{
#ifdef MT_DEBUG
if( pthread_spin_lock( &spin->pspinlock ) )
DEBUG_WARNING();
#else
pthread_spin_lock( &spin->pspinlock );
#endif
return;
}
static inline void mtSpinUnlock( mtSpin *spin )
{
#ifdef MT_DEBUG
if( pthread_spin_unlock( &spin->pspinlock ) )
DEBUG_WARNING();
#else
pthread_spin_unlock( &spin->pspinlock );
#endif
return;
}
static inline int mtSpinTryLock( mtSpin *spin )
{
return !( pthread_spin_trylock( &spin->pspinlock ) );
}
#else
typedef struct mtMutex mtSpin;
#define mtSpinInit(a) mtMutexInit(a)
#define mtSpinDestroy(a) mtMutexDestroy(a)
#define mtSpinLock(a) mtMutexLock(a)
#define mtSpinUnlock(a) mtMutexUnlock(a)
#define mtSpinTryLock(a) mtMutexTryLock(a)
#endif
////
#ifdef MT_BARRIER_SUPPORT
typedef struct
{
pthread_barrier_t pbarrier;
} mtBarrier;
static inline void mtBarrierInit( mtBarrier *barrier, int count )
{
pthread_barrier_init( &barrier->pbarrier, 0, count );
return;
}
static inline void mtBarrierDestroy( mtBarrier *barrier )
{
pthread_barrier_destroy( &barrier->pbarrier );
return;
}
static inline int mtBarrierWait( mtBarrier *barrier )
{
return pthread_barrier_wait( &barrier->pbarrier );
}
#endif
////
#ifdef MT_RWLOCK_SUPPORT
typedef struct mtRWlock mtRWlock;
struct mtRWlock
{
pthread_rwlock_t prwlock;
};
static inline void mtRWlockInit( mtRWlock *rwlock )
{
pthread_rwlock_init( &rwlock->prwlock, 0 );
return;
}
static inline void mtRWlockDestroy( mtRWlock *rwlock )
{
pthread_rwlock_destroy( &rwlock->prwlock );
return;
}
static inline void mtRWlockRead( mtRWlock *rwlock )
{
pthread_rwlock_rdlock( &rwlock->prwlock );
return;
}
static inline void mtRWlockWrite( mtRWlock *rwlock )
{
pthread_rwlock_wrlock( &rwlock->prwlock );
return;
}
static inline void mtRWlockUnlock( mtRWlock *rwlock )
{
pthread_rwlock_unlock( &rwlock->prwlock );
return;
}
static inline int mtRWlockTryRead( mtRWlock *rwlock )
{
return pthread_rwlock_rdlock( &rwlock->prwlock );
}
static inline int mtRWlockTryWrite( mtRWlock *rwlock )
{
return pthread_rwlock_wrlock( &rwlock->prwlock );
}
#endif
#endif
+196
View File
@@ -0,0 +1,196 @@
/* BrlcadAppWalker.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the comb_pre_func, comb_post_func, and primitive_func operations
* that the BrlcadTreeWalker will call.
*/
/* Standard libraries */
#include <algorithm>
/* BRL-CAD libraries */
extern "C" {
#include "vmath.h"
#include "nmg.h"
#include "rtgeom.h"
#include "bu.h"
#include "rtfunc.h"
#include "raytrace.h"
#include "db.h"
}
/* Local headers */
#include "BrlcadAppWalker.h"
//******************************************************************************
// NAME constructor
//
// INPUTS
// none
//
// DESCRIPTION
// Construct the object.
//******************************************************************************
BrlcadAppWalker::BrlcadAppWalker()
{
regionNeedsConversion = false;
}
//******************************************************************************
// NAME destructor
//
// DESCRIPTION
// Cleanup the object.
//******************************************************************************
BrlcadAppWalker::~BrlcadAppWalker()
{
}
void BrlcadAppWalker::comb_pre_func(struct directory *dp,
BrlcadTreeWalker *btw)
{
int regCount = btw->inRegion();
//fprintf(stderr, "entering %s inRegion(%d)", dp->d_namep, regCount);
//btw->printObjStack();
//fprintf(stderr, "flags...");
//btw->printFlags();
//btw->printFlagStack();
int tf = btw->getFlags();
if (regCount == 1)
{
if (dp->d_flags & RT_DIR_REGION)
{
regionNeedsConversion = false;
}
}
else if (regCount > 1)
{
if (tf & FLAG_UNION)
{
// Should never happen. Union of region into region is bogus
regionNeedsConversion = true;
}
else if (tf & (FLAG_SUBTRACT|FLAG_INTERSECT|FLAG_NOT|FLAG_XOR))
{
regionNeedsConversion = true;
}
}
}
void BrlcadAppWalker::comb_post_func(struct directory *dp,
struct rt_comb_internal *comb,
BrlcadTreeWalker *btw)
{
int regCount = btw->inRegion();
//fprintf(stderr, "leaving %s inRegion(%d)", dp->d_namep, regCount);
//btw->printObjStack(); btw->printFlags();
//btw->printFlagStack();
//fprintf(stderr, "groupstack: %ld\n", m_groupStack.size());
int tf = btw->getFlags();
if (regCount == 1 )
{
if (dp->d_flags & RT_DIR_REGION)
{
if (regionNeedsConversion)
if (m_nonBotRegions.empty())
m_nonBotRegions.push_back(dp->d_namep);
else if (std::find(m_nonBotRegions.begin(),
m_nonBotRegions.end(),
dp->d_namep) == m_nonBotRegions.end())
m_nonBotRegions.push_back(dp->d_namep);
}
}
}
void BrlcadAppWalker::primitive_func(struct directory *dp,
BrlcadTreeWalker *btw)
{
int tf = btw->getFlags();
int inRegion = btw->inRegion();
// btw->printObjStack(); btw->printFlags();
if (inRegion > 0)
{
// if non-bot
// rnc = true
// add wireframe
// else
// add triangles
if (tf & (FLAG_SUBTRACT|FLAG_INTERSECT|FLAG_NOT|FLAG_XOR))
{
regionNeedsConversion = true;
}
struct rt_db_internal intern;
btw->brlcad_get_internal(&intern, dp, NULL);
if (intern.idb_minor_type == ID_BOT)
{
//fprintf(stderr, "%s is a bot\n", dp->d_namep);
// add a drawable for the triangles from this BOT
if (m_botRegions.empty())
m_botRegions.push_back(dp->d_namep);
else if (std::find(m_botRegions.begin(),
m_botRegions.end(),
dp->d_namep) == m_botRegions.end())
m_botRegions.push_back(dp->d_namep);
}
else
{
//fprintf(stderr, "%s is a prim in region %s\n", dp->d_namep, m_currentGeode->getName().c_str());
regionNeedsConversion = true;
}
}
else
{
// Just a primitive hanging out in space in no region?
struct rt_db_internal intern;
btw->brlcad_get_internal(&intern, dp, NULL);
if (intern.idb_minor_type == ID_BOT)
{
if (m_botRegions.empty())
m_botRegions.push_back(dp->d_namep);
else if (std::find(m_botRegions.begin(),
m_botRegions.end(),
dp->d_namep) == m_botRegions.end())
m_botRegions.push_back(dp->d_namep);
}
}
//fprintf(stderr, "%s done\n", dp->d_namep);
}
+76
View File
@@ -0,0 +1,76 @@
/* BrlcadAppWalker.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the comb_pre_func, comb_post_func, and primitive_func operations
* that the BrlcadTreeWalker will call.
*/
#ifndef BRLCADAPPWALKER_H
#define BRLCADAPPWALKER_H
/* Standard libraries */
#include <string>
#include <vector>
/* Linterface headers */
#include "Interface/AppWalkerInterface.h"
/* Local headers */
#include "BrlcadTreeWalker.h"
class BrlcadAppWalker : public AppWalkerInterface
{
public:
BrlcadAppWalker();
~BrlcadAppWalker();
virtual void comb_pre_func(struct directory *dp,
BrlcadTreeWalker *btw);
virtual void comb_post_func(struct directory *dp,
struct rt_comb_internal *comb,
BrlcadTreeWalker *btw);
virtual void primitive_func(struct directory *dp,
BrlcadTreeWalker *btw);
std::vector<std::string> getBotRegions() { return m_botRegions; }
std::vector<std::string> getNonBotRegions() { return m_nonBotRegions; }
private:
std::vector<std::string> m_botRegions;
std::vector<std::string> m_nonBotRegions;
bool regionNeedsConversion; // region needs conversion
};
#endif
+128
View File
@@ -0,0 +1,128 @@
/* BrlcadLoader.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* This class contains the functions to comb a BRL-CAD database file and
* return region names.
*/
/* Local headers */
#include "BrlcadLoader.h"
#include "BrlcadAppWalker.h"
//******************************************************************************
// NAME constructor
//
// INPUTS
// filename - target file name
//
// DESCRIPTION
// Construct the object.
//******************************************************************************
BrlcadLoader::BrlcadLoader(const std::string filename)
: GLoaderInterface(filename)
, m_dbip(NULL)
{
}
//******************************************************************************
// NAME destructor
//
// DESCRIPTION
// Cleanup the object.
//******************************************************************************
BrlcadLoader::~BrlcadLoader()
{
}
//******************************************************************************
// NAME startLoader
//
// INPUTS
// none
//
// DESCRIPTION
// Walk geometry to get all the region names within.
//******************************************************************************
void BrlcadLoader::startLoader()
{
m_status = true;
// First initialize the librt resource
if (rt_uniresource.re_magic != RESOURCE_MAGIC)
{
rt_init_resource(&rt_uniresource, 0, NULL);
}
//
// Open the database and load the geometry
//
if ((m_dbip = db_open(m_fileName.c_str(), "r")) == DBI_NULL)
{
m_status = false;
return;
}
if (db_dirbuild(m_dbip))
{
m_status = false;
return;
}
// update all objects with the correct number of
// times the object is referenced by other objects
db_update_nref(m_dbip, &rt_uniresource);
BrlcadAppWalker appWalker;
BrlcadTreeWalker tw(m_dbip, &rt_uniresource, appWalker);
struct directory *dp;
// Look at all items in the geometry file
FOR_ALL_DIRECTORY_START(dp, m_dbip) {
// if an item isn't referred to by any other object
// this is a top level object we should start traversing
// to construct the geometry
if (dp->d_nref == 0)
tw.brlcad_functree(dp); // Traverse the tree, generating geometry
} FOR_ALL_DIRECTORY_END;
//fprintf(stderr, "final\n");
// set both bot and non-bot lists
m_botRegionNames = appWalker.getBotRegions();
m_nonbotRegionNames = appWalker.getNonBotRegions();
db_close(m_dbip);
m_dbip = NULL;
}
+72
View File
@@ -0,0 +1,72 @@
/* BrlcadLoader.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* This class contains the functions to comb a BRL-CAD database file and
* return region names.
*/
#ifndef BRLCAD_LOADER_H
#define BRLCAD_LOADER_H
/* BRL-CAD libraries */
extern "C" {
#include "vmath.h"
#include "raytrace.h"
#include "rtgeom.h"
}
/* Interface headers */
#include "Interface/GLoaderInterface.h"
/* Class */
class BrlcadLoader : public GLoaderInterface
{
public:
BrlcadLoader(const std::string);
~BrlcadLoader();
std::vector<std::string> getBotRegionNames() const { return m_botRegionNames; }
std::vector<std::string> getNonbotRegionNames() const { return m_nonbotRegionNames; }
virtual std::vector<std::string> getGeomNames() { return getNonbotRegionNames(); }
virtual void startLoader();
protected:
struct db_i *m_dbip;
std::vector<std::string> m_botRegionNames;
std::vector<std::string> m_nonbotRegionNames;
};
#endif
+224
View File
@@ -0,0 +1,224 @@
/* BrlcadTreeWalker.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* This object walks a brlcad heirarchy starting at a particular
* directory entry.
*/
#include "BrlcadTreeWalker.h"
BrlcadTreeWalker::BrlcadTreeWalker(struct db_i* dbip,
struct resource *resp,
AppWalkerInterface &appWalker)
: m_dbip(dbip)
, m_resp(resp)
, m_inRegion(0)
, m_appWalker(appWalker)
{
m_treeFlags.push_back(0);
RT_CK_DBI(m_dbip);
if (m_resp)
{
RT_CK_RESOURCE(m_resp);
}
// XXX This dreck is necessary because the ft_plot() functions expect RTG to be initialized
if (BU_LIST_FIRST(bu_list, &RTG.rtg_vlfree) == 0)
{
char *envflags;
envflags = getenv("LIBRT_DEBUG");
if (envflags)
{
if (RTG.debug)
bu_log("WARNING: discarding LIBRT_DEBUG value in favor of application specified flags\n");
else
RTG.debug = strtol(envflags, NULL, 0x10);
}
BU_LIST_INIT(&RTG.rtg_vlfree);
}
}
BrlcadTreeWalker::~BrlcadTreeWalker()
{
}
int BrlcadTreeWalker::brlcad_get_internal(struct rt_db_internal *intern,
struct directory *dp,
matp_t matrix)
{
return rt_db_get_internal(intern, dp, m_dbip, matrix, m_resp);
}
void BrlcadTreeWalker::brlcad_functree(struct directory *dp)
{
RT_CK_DBI(m_dbip);
if (m_resp)
{
RT_CK_RESOURCE(m_resp);
}
if (!dp)
{
return; /* nothing to do */
}
m_objStack.push_back(StackNode(dp));
if (dp->d_flags & RT_DIR_COMB)
{
if (dp->d_flags & RT_DIR_REGION)
{
if (m_inRegion == 0)
{
m_topRegionName = dp->d_namep;
}
m_inRegion++;
}
m_appWalker.comb_pre_func(dp, this);
struct rt_db_internal in;
struct rt_comb_internal *comb = (struct rt_comb_internal *)NULL;
if (rt_db_get_internal(&in, dp, m_dbip, /*mat_t*/ NULL, m_resp) < 0)
return;
comb = (struct rt_comb_internal *)in.idb_ptr;
if (!comb)
{
bu_log("%s:%d null comb pointer for combination called %s",
__FILE__, __LINE__, dp->d_namep);
bu_bomb("");
}
m_treeFlags.push_back(FLAG_NONE);
brlcad_functree_subtree(comb->tree, dp);
m_treeFlags.pop_back();
/* Finally, the combination post process */
m_appWalker.comb_post_func(dp, comb, this);
rt_db_free_internal(&in);
if (dp->d_flags & RT_DIR_REGION)
{
m_inRegion--;
if (m_inRegion == 0)
m_topRegionName.clear();
}
}
else if (dp->d_flags & RT_DIR_SOLID || dp->d_major_type & DB5_MAJORTYPE_BINARY_MASK)
{
m_appWalker.primitive_func(dp, this);
}
else if (strcmp("_GLOBAL", dp->d_namep))
{
// This is not the _GLOBAL and isn't a solid/primtive or combination
bu_log("brlcad_functree: %s is neither COMB nor SOLID? %d %d\n",
dp->d_namep, dp->d_major_type, dp->d_minor_type);
}
m_objStack.pop_back();
}
/***
* The parent argument exists solely to be able to report error status against
* a particular object in the BRLCAD database.
*/
void BrlcadTreeWalker::brlcad_functree_subtree(union tree *tp,
struct directory *parent)
{
if (!tp)
return;
switch (tp->tr_op)
{
case OP_DB_LEAF:
{
struct directory *dp;
if (tp->tr_l.tl_mat)
{
m_objStack.push_back(StackNode(tp->tr_l.tl_mat));
m_treeFlags.push_back(m_treeFlags.back()|FLAG_MATRIX);
}
if ((dp=db_lookup(m_dbip, tp->tr_l.tl_name, LOOKUP_NOISY)) == RT_DIR_NULL)
{
break;
}
brlcad_functree(dp);
if (tp->tr_l.tl_mat)
{
m_treeFlags.pop_back();
m_objStack.pop_back();
}
break;
}
case OP_UNION:
case OP_INTERSECT:
case OP_SUBTRACT:
case OP_XOR:
m_objStack.push_back(StackNode(tp->tr_op));
// add union to treeFlags & push new value
m_treeFlags.push_back(m_treeFlags.back()|FLAG_UNION);
brlcad_functree_subtree(tp->tr_b.tb_left, parent);
m_treeFlags.pop_back();
// add flag to treeFlags & push new value
m_treeFlags.push_back(m_treeFlags.back()|op2flag(tp->tr_op));
brlcad_functree_subtree(tp->tr_b.tb_right, parent);
m_treeFlags.pop_back();
m_objStack.pop_back();
break;
case OP_SOLID:
case OP_REGION:
case OP_NOP:
case OP_NOT:
case OP_GUARD:
case OP_XNOP:
case OP_NMG_TESS:
case OP_FREE:
// These types not implemented.
break;
default:
bu_log("%s:%d brlcad_functree_subtree: unrecognized operator %d in \"%s\"\n",
__FILE__, __LINE__, tp->tr_op, parent->d_namep);
bu_bomb("");
}
}
+168
View File
@@ -0,0 +1,168 @@
/* BrlcadTreeWalker.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* This object walks a brlcad heirarchy starting at a particular
* directory entry.
*/
#ifndef BRLCADTREEWALKER_H
#define BRLCADTREEWALKER_H
/* Standard libraries */
#include <vector>
/* BRL-CAD libraries */
extern "C" {
#include "vmath.h"
#include "nmg.h"
#include "rtgeom.h"
#include "bu.h"
#include "raytrace.h"
#include "db.h"
}
/* Interface headers */
#include "Interface/AppWalkerInterface.h"
/** enumeration of all the types of operators that might be on the
* heirarchy of the graph that the BrlcadTreeWalker maintains
*
* Shared by the BrlcadTreeWalker and BrlcadBotLoader
*/
enum treeFlags { FLAG_NONE=0,
FLAG_MATRIX=1,
FLAG_SUBTRACT=2,
FLAG_INTERSECT=4,
FLAG_UNION=8,
FLAG_NOT=16,
FLAG_XOR=32,
FLAG_LEAF=64
};
/**
* HELPER CLASS: StackNode
*
* This encapsulates a single item on the directed acyclic graph of a
* BRLCAD heirarchy. The stack is maintained by the BrlcadTreeWalker to
* keep track of various states along the path.
*
* XXX This really should be private to the BrlcadTreeWalker. No-one else has
* any business looking at this.
*/
class StackNode {
public:
enum ItemType { OBJECT, OPERATION, MATRIX };
StackNode(struct directory *dp) : m_itemType(OBJECT) { m_dp = dp; }
StackNode(int op) : m_itemType(OPERATION) { m_op = op; }
StackNode(mat_t m) : m_itemType(MATRIX) { MAT_COPY(m_mat, m); }
ItemType getType() const { return m_itemType; }
struct directory *getDirectory() const
{
if (m_itemType == OBJECT) {
return m_dp;
}
abort();
return NULL; // make compiler happy
}
int getOperation() const
{
if (m_itemType == OPERATION) {
return m_op;
}
abort();
return 0; // make compiler happy
}
fastf_t * getMatrix() const
{
if (m_itemType == MATRIX) {
return (fastf_t *)m_mat;
}
abort();
return NULL; // make compiler happy
}
void print(const int depth);
private:
ItemType m_itemType;
struct directory *m_dp;
int m_op;
mat_t m_mat;
};
/* Class */
class BrlcadTreeWalker
{
public:
BrlcadTreeWalker(struct db_i* dbip,
struct resource *resp,
AppWalkerInterface &appWalker);
~BrlcadTreeWalker();
/// Start walking the heirarchy at a particular directory entry
void brlcad_functree(struct directory *);
int brlcad_get_internal(struct rt_db_internal *intern,
struct directory *dp,
mat_t matrix);
inline int inRegion() const { return m_inRegion; }
inline const char *regionName() const { return m_topRegionName.c_str(); }
inline int getFlags() const { if (m_treeFlags.size() > 0) return m_treeFlags.back(); else return 0; }
private:
// This is a helper function for brlcad_functree which
// handles walking the union tree structure for a single combination
void brlcad_functree_subtree(union tree *, struct directory *);
static inline int op2flag(int op)
{
switch (op) {
case OP_UNION : return FLAG_UNION;
case OP_SUBTRACT : return FLAG_SUBTRACT;
case OP_INTERSECT : return FLAG_INTERSECT;
case OP_XOR : return FLAG_XOR;
}
return 0;
}
struct db_i *m_dbip;
struct resource *m_resp;
int m_inRegion;
std::string m_topRegionName;
AppWalkerInterface &m_appWalker;
std::vector<StackNode>m_objStack;
std::vector<int> m_treeFlags;
};
#endif
+35
View File
@@ -0,0 +1,35 @@
set(GCT_BRLCAD_SRCS
BrlcadAppWalker.cpp
BrlcadLoader.cpp
BrlcadTreeWalker.cpp
DbGeometry.cpp
DbTracer.cpp
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
)
add_library(BrlcadGCT SHARED ${GCT_BRLCAD_SRCS})
set_target_properties(BrlcadGCT PROPERTIES VERSION 1.1.0 SOVERSION 1)
install(TARGETS BrlcadGCT
RUNTIME DESTINATION ${BIN_DIR}
LIBRARY DESTINATION ${LIB_DIR}
ARCHIVE DESTINATION ${LIB_DIR})
if(MSVC)
set_property(TARGET BrlcadGCT APPEND PROPERTY COMPILE_DEFINITIONS "BRLCADGCT_DLL_EXPORTS")
endif(MSVC)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
+190
View File
@@ -0,0 +1,190 @@
/* DbGeometry.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/20/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the INativeGeometry interface for BRL-CAD targets.
*/
// Local headers
#include "DbGeometry.h"
namespace GeomConversion {
namespace BRLCAD {
static struct resource resource[MAX_PSW];
//*******************************************************************
// NAME constructor
//
// INPUTS
// filename - target file name
//
// DESCRIPTION
// Construct the object.
//*******************************************************************
DbGeometry::DbGeometry(std::string filename)
: Interface::INativeGeometry(filename)
, m_rtip(RTI_NULL)
{
char titleBuf[1028];
m_rtip = rt_dirbuild(filename.c_str(), titleBuf, sizeof(titleBuf));
if (m_rtip == RTI_NULL)
return; // throw exception???
/* Initialize all the per-CPU memory resources. The number of
* processors can change at runtime, init them all.
*/
for (int i=0; i < MAX_PSW; i++)
{
rt_init_resource(&(resource[i]), i, m_rtip);
bn_rand_init(resource[i].re_randptr, i);
}
m_geometryType = Interface::BRLCAD;
}
//*******************************************************************
// NAME destructor
//
// DESCRIPTION
// Cleanup the object.
//*******************************************************************
DbGeometry::~DbGeometry()
{
// cleanup rt_i
if (m_rtip != RTI_NULL)
{
rt_free_rti(m_rtip);
m_rtip = RTI_NULL;
}
}
//*******************************************************************
// NAME getGeometry
//
// INPUTS
// none
//
// DESCRIPTION
// Return a reference to the internal target data.
//*******************************************************************
void* DbGeometry::getGeometry()
{
return ((void*) m_rtip);
}
//*******************************************************************
// NAME getResources
//
// INPUTS
// i - index of the desired resource
//
// DESCRIPTION
// Return a reference to CPU resource for the given index.
//*******************************************************************
struct resource* DbGeometry::getResource(int i)
{
return &(resource[i]);
}
//*******************************************************************
// NAME loadGeometry
//
// INPUTS
// rname - region name
// tcount - thread count
//
// DESCRIPTION
// Load a given piece of the geometry.
//*******************************************************************
void DbGeometry::loadGeometry(std::string rname, int tcount)
{
m_rtip->useair = 1; // convert air objects when found
if (rt_gettree(m_rtip, rname.c_str()))
{
bu_log("BRLCAD::DbGeometry::loadRegion - Error loading <%s>\n",
rname.c_str());
return;
}
rt_prep_parallel(m_rtip, tcount);
}
//*******************************************************************
// NAME cleanupGeometry
//
// INPUTS
// none
//
// DESCRIPTION
// Perform cleanup of any geometry.
//*******************************************************************
void DbGeometry::cleanupGeometry()
{
rt_clean(m_rtip);
}
//*******************************************************************
// NAME getGeometryMin
//
// INPUTS
// none
//
// DESCRIPTION
// Return minimum 3D dimension of the loaded geometry.
//*******************************************************************
double* DbGeometry::getGeometryMin()
{
return m_rtip->rti_pmin;
}
//*******************************************************************
// NAME getGeometryMax
//
// INPUTS
// none
//
// DESCRIPTION
// Return maximum 3D dimension of the loaded geometry.
//*******************************************************************
double* DbGeometry::getGeometryMax()
{
return m_rtip->rti_pmax;
}
} // namespace BRLCAD
} // namespace GeomConversion
+83
View File
@@ -0,0 +1,83 @@
/* DbGeometry.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/20/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the INativeGeometry interface for BRL-CAD targets.
*/
#ifndef BRLCADDBGEOMETRY_H
#define BRLCADDBGEOMETRY_H
// BRL-CAD headers
extern "C" {
#include "bu.h"
#include "raytrace.h"
}
// Local headers
#include "Interface/INativeGeometry.h"
namespace GeomConversion {
namespace BRLCAD {
/**
* DbGeometry
*
* Implements the INativeGeometry interface for BRL-CAD targets.
*/
class DbGeometry : public Interface::INativeGeometry
{
public:
DbGeometry(std::string);
~DbGeometry();
virtual void* getGeometry();
struct resource* getResource(int);
virtual void loadGeometry(std::string, int tcount=1);
virtual void cleanupGeometry();
virtual double* getGeometryMin();
virtual double* getGeometryMax();
private:
struct rt_i *m_rtip;
};
} // namespace DbGeometry
} // namespace GeomConversion
#endif
+203
View File
@@ -0,0 +1,203 @@
/* DbTracer.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 10/02/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the IGeometryTracer interface for shotlining BRL-CAD targets.
*/
// Local headers
#include "DbTracer.h"
namespace GeomConversion {
namespace BRLCAD {
//*******************************************************************
// NAME hit_func
//
// INPUTS
// ap - application structure
// PartHeadp - pointer to the beginning of the trace list
//
// DESCRIPTION
// Called when a shotline produces a hit. This user defined
// callback copies the in and out hit points into structures and
// stores them in the ray's result list.
//*******************************************************************
static int
hit_func(struct application *ap, struct partition *PartHeadp, struct seg *)
{
/* iterating over partitions, this will keep track of the current
* partition we're working on.
*/
struct partition *pp;
/* will serve as a pointer for the entry and exit hitpoints */
struct hit *hitp;
/* will serve as a pointer to the solid primitive we hit */
struct soltab *stp;
/* output variables */
Interface::ray_results *result = (Interface::ray_results *) ap->a_uptr;
Interface::one_hit singleHit;
VMOVE(result->origin, ap->a_ray.r_pt);
result->x = ap->a_x;
result->y = ap->a_y;
/* iterate over each partition until we get back to the head.
* each partition corresponds to a specific homogeneous region of
* material.
*/
for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw)
{
/* entry hit point, so we type less */
hitp = pp->pt_inhit;
/* primitive we encountered on entry */
stp = pp->pt_inseg->seg_stp;
/* clear data struct */
ONE_HIT_INIT(singleHit);
/* record IN hit point */
VJOIN1(singleHit.point, ap->a_ray.r_pt,
hitp->hit_dist, ap->a_ray.r_dir);
/* calculate IN normal vector */
/* compute the normal vector at the entry point, flipping the
* normal if necessary.
*/
RT_HIT_NORMAL(singleHit.normal, hitp, stp,
&(ap->a_ray), pp->pt_inflip);
/* save IN solid and surface numbers */
/* singleHit.solidNumber = stp->st_bit; */
singleHit.solidName = stp->st_dp->d_namep;
singleHit.solidSurface = hitp->hit_surfno;
/* push hit to the result list */
result->hitData.push_back(singleHit);
/* exit point, so we type less */
hitp = pp->pt_outhit;
/* primitive we exited from */
stp = pp->pt_outseg->seg_stp;
/* clear data struct */
ONE_HIT_INIT(singleHit);
/* record OUT hit point */
VJOIN1(singleHit.point, ap->a_ray.r_pt,
hitp->hit_dist, ap->a_ray.r_dir);
/* calculate OUT normal vector */
/* compute the normal vector at the exit point, flipping the
* normal if necessary.
*/
RT_HIT_NORMAL(singleHit.normal, hitp, stp,
&(ap->a_ray), pp->pt_outflip);
/* save OUT solid and surface numbers */
/* singleHit.solidNumber = stp->st_bit; */
singleHit.solidName = stp->st_dp->d_namep;
singleHit.solidSurface = hitp->hit_surfno;
/* push hit to the result list */
result->hitData.push_back(singleHit);
}
return 1;
}
//*******************************************************************
// NAME constructor
//
// INPUTS
// ti - pointer to a target
// cpuID - thread ID
//
// DESCRIPTION
// Construct the object.
//*******************************************************************
DbTracer::DbTracer(Interface::INativeGeometry *ti, int cpuID)
: Interface::IGeometryTracer(ti)
, m_cpuID(cpuID)
{
// set up the application object that will be used
RT_APPLICATION_INIT(&m_ap);
m_ap.a_rt_i = (struct rt_i *) ti->getGeometry();
m_ap.a_hit = hit_func;
m_ap.a_resource = ((DbGeometry *) ti)->getResource(cpuID);
m_ap.a_user = cpuID;
}
//*******************************************************************
// NAME destructor
//
// DESCRIPTION
// Cleanup the object.
//*******************************************************************
DbTracer::~DbTracer()
{
}
//*******************************************************************
// NAME fireRay
//
// INPUTS
// data - pointer to a tracer_ray_data
//
// DESCRIPTION
// Perform a shotline.
//*******************************************************************
void DbTracer::fireRay(Interface::trace_data *ray)
{
// set application data for this ray
VMOVE(m_ap.a_ray.r_pt, ray->point);
VMOVE(m_ap.a_ray.r_dir, ray->direc);
m_ap.a_ray_length = ray->length;
m_ap.a_uptr = (void *) &(ray->results);
m_ap.a_x = ray->results.x;
m_ap.a_y = ray->results.y;
// perform shot
(void)rt_shootray(&m_ap);
}
} // namespace BRLCAD
} // namespace GeomConversion
+80
View File
@@ -0,0 +1,80 @@
/* DbTracer.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 10/02/13
*
* Authors(s):
* DRH
*
* Description:
* Implements the IGeometryTracer interface for shotlining BRL-CAD targets.
*/
#ifndef BRLCADDBTRACER_H
#define BRLCADDBTRACER_H
// BRL-CAD libraries
extern "C" {
#include "bu.h"
#include "vmath.h"
#include "raytrace.h"
#include "rtgeom.h"
}
// Local headers
#include "Interface/IGeometryTracer.h"
#include "DbGeometry.h"
namespace GeomConversion {
namespace BRLCAD {
/**
* DbTracer
*
* Implements the IGeometryTracer interface for BRL-CAD targets.
*/
class DbTracer : public Interface::IGeometryTracer
{
public:
DbTracer(Interface::INativeGeometry*, int);
~DbTracer();
virtual void fireRay(Interface::trace_data*);
private:
int m_cpuID;
struct application m_ap;
};
} // namespace BRLCAD
} // namespace GeomConversion
#endif
+25
View File
@@ -0,0 +1,25 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../Auxiliary
)
add_library(BallPivoting SHARED ballpivoting.c)
target_link_libraries(BallPivoting AUX)
set_target_properties(BallPivoting PROPERTIES VERSION 1.0.0 SOVERSION 1)
install(TARGETS BallPivoting
RUNTIME DESTINATION ${BIN_DIR}
LIBRARY DESTINATION ${LIB_DIR}
ARCHIVE DESTINATION ${LIB_DIR})
if(MSVC)
set_property(TARGET BallPivoting APPEND PROPERTY COMPILE_DEFINITIONS "BALLPIVOTING_DLL_EXPORTS")
endif(MSVC)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
File diff suppressed because it is too large Load Diff
+202
View File
@@ -0,0 +1,202 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Define to use double floating point precision */
/*
#define BP_CONF_DOUBLE_PRECISION
*/
#ifdef BP_CONF_DOUBLE_PRECISION
typedef double bpf;
#else
typedef float bpf;
#endif
////
typedef struct
{
int orphancount;
int hingelostcount;
int conflictcount;
int pointdupcount;
} bpInfo;
typedef struct
{
double progress;
int stage;
const char *stagename;
long trianglecount;
long triangleguess;
} bpStatus;
enum
{
BP_STATUS_STAGE_INIT,
BP_STATUS_STAGE_SORT,
BP_STATUS_STAGE_MESH,
BP_STATUS_STAGE_STRIP,
BP_STATUS_STAGE_CONNECT,
BP_STATUS_STAGE_CLEAN,
BP_STATUS_STAGE_NORMALS,
BP_STATUS_STAGE_PACK,
BP_STATUS_STAGE_STORE,
BP_STATUS_STAGE_DONE,
BP_STATUS_STAGE_COUNT
};
typedef struct
{
/* Input format configuration */
size_t vertexcount;
bpf *vertex;
size_t vertexstride;
bpf *normal;
size_t normalstride;
/* Ball settings */
bpf ballradiusmin;
bpf ballradiusmax;
/* Ouput format configuration */
int trianglewinding; /* BP_TRIANGLE_WINDING_CW or BP_TRIANGLE_WINDING_CCW */
size_t trianglestride; /* Stride between triangles for indices */
size_t triangleindexsize; /* Size of index integers : 1, 2, 4 or 8 ; a value of 0 defaults to 4 */
size_t triangleoffset; /* Offset within triangle entry where to store indices sequentially */
void *(*trianglealloc)( void *allocopaque, size_t size );
void *allocopaque;
/* Vertex packing callback */
void *packopaquepointer;
void (*packcallback)( void *opaquepointer, long newvertexindex, long oldvertexindex );
/* Status callback */
long statusmiliseconds;
void *statusopaquepointer;
void (*statuscallback)( void *opaquepointer, const bpStatus *status );
/* Advanced configuration options */
int hashextrabits;
int hashlockpageshift;
bpf ballradiuspivot;
bpf ballradiusoverride;
bpf balldistmin; /* Minimum distance away from triangle's surface plane, 0.0 can cause glitches in very rare cases */
bpf pivotcosphericalrange;
bpf pivotcoplanardist;
bpf pivotjoinradiusfactor;
bpf pivotforceradiusfactor;
bpf pivotoverriderange;
bpf dupvertexdistancesoft; /* Discard any vertex closer than this distance to another vertex, stored as ratio of default ball size */
bpf dupvertexdistancehard;
bpf dupvertexnormalagreement;
bpf reductionfactor;
bpf seedballradius;
bpf seedcoplanardist;
bpf seednormalagreement;
bpf seednormalagreementsum;
bpf seedmarkradius;
bpf hingenormalagreement;
bpf pivotnormalagreementsoft; /* Normal agreement betwene vertices and created triangles */
bpf pivotnormalagreementhard;
bpf pivotnormalagreementsumsoft;
bpf pivotnormalagreementsumhard;
bpf filterplanecutdistance;
long randseed;
size_t maxmemorysize;
} bpOperation;
enum
{
BP_TRIANGLE_WINDING_CW,
BP_TRIANGLE_WINDING_CCW
};
typedef struct
{
size_t trianglecount;
size_t vertexcount; /* Final count of used vertices, if BP_FLAGS_REBUILD_VERTICES was specified */
void *triangle; /* Allocated triangle data */
/* Process information sum */
bpInfo info;
int warningcount;
int errorcount;
long msecs;
} bpOutput;
#define BP_FLAGS_NORMALIZE_NORMALS (0x1)
#define BP_FLAGS_PACK_VERTICES (0x2)
#define BP_FLAGS_ALLOW_REDUCTION (0x4)
#define BP_FLAGS_RECOMPUTE_NORMALS (0x8)
#define BP_FLAGS_SKIP_STRIP_PASS (0x10)
#define BP_FLAGS_SKIP_CONNECT_PASS (0x20)
#define BP_FLAGS_SKIP_CLEAN_PASS (0x40)
void bpOperationInit( bpOperation *op );
void bpOperationSetInput( bpOperation *op, size_t vertexcount, bpf *vertex, size_t vertexstride, bpf *normal, size_t normalstride );
void bpOperationSetBall( bpOperation *op, bpf ballradius );
void bpOperationSetBallRange( bpOperation *op, bpf ballminimum, bpf ballmaximum );
int bpOperationSetOutput( bpOperation *op, int trianglewinding, size_t trianglestride, size_t triangleindexsize, size_t triangleoffset, void *(*trianglealloc)( void *allocopaque, size_t size ), void *allocopaque );
void bpOperationNormalAgreement( bpOperation *op, bpf softstrictness, bpf hardstrictness );
void bpOperationVertexPackCallback( bpOperation *op, void (*packcallback)( void *opaquepointer, long newvertexindex, long oldvertexindex ), void *packopaquepointer );
void bpOperationStatusCallback( bpOperation *op, void (*statuscallback)( void *opaquepointer, const bpStatus *status ), void *opaquepointer, long miliseconds );
void *bpConstructMesh( bpOperation *op, bpOutput *output, int threadcount, uint32_t flags );
#ifdef __cplusplus
}
#endif
+48
View File
@@ -0,0 +1,48 @@
# Minimum required version of CMake
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
if(COMMAND CMAKE_POLICY)
CMAKE_POLICY(SET CMP0003 NEW)
CMAKE_POLICY(SET CMP0007 OLD)
if("${CMAKE_VERSION}" VERSION_GREATER 2.8.3)
CMAKE_POLICY(SET CMP0017 OLD)
endif("${CMAKE_VERSION}" VERSION_GREATER 2.8.3)
if ("${CMAKE_VERSION}" VERSION_GREATER 2.99)
CMAKE_POLICY(SET CMP0026 OLD)
endif ("${CMAKE_VERSION}"
VERSION_GREATER 2.99)
endif(COMMAND CMAKE_POLICY)
# set CMake project name
project(GCT)
# The location in which to install executables.
if(NOT BIN_DIR)
set(BIN_DIR bin)
endif(NOT BIN_DIR)
# The location in which to install libraries.
if(NOT LIB_DIR)
if(NOT WIN32)
set(LIB_DIR lib)
else(NOT WIN32)
set(LIB_DIR bin)
endif(NOT WIN32)
endif(NOT LIB_DIR)
find_package(Threads)
add_subdirectory(Auxiliary)
add_subdirectory(BRLCAD)
add_subdirectory(Sampler)
add_subdirectory(BallPivoting)
add_subdirectory(MeshDecimation)
add_subdirectory(psmain)
add_subdirectory(bpmain)
add_subdirectory(dcmain)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
@@ -0,0 +1,56 @@
/* AppWalkerInterface.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/19/13
*
* Authors(s):
* DRH
*
* Description:
* Interface class that specifies necessary functions to walk a target.
*/
#ifndef APPWALKERINTERFACE_H
#define APPWALKERINTERFACE_H
class BrlcadTreeWalker; // necessary forward declaration
class AppWalkerInterface
{
public:
virtual void comb_pre_func(struct directory *,
BrlcadTreeWalker *) = 0;
virtual void comb_post_func(struct directory *,
struct rt_comb_internal *,
BrlcadTreeWalker *) = 0;
virtual void primitive_func(struct directory *,
BrlcadTreeWalker *) = 0;
};
#endif
@@ -0,0 +1,65 @@
/* GLoaderInterface.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/20/13
*
* Authors(s):
* DRH
*
* Description:
* Interface class that specifies necessary functions to load and query
* for possible geometry names.
*/
#ifndef GLOADERINTERFACE_H
#define GLOADERINTERFACE_H
/* Standard libraries */
#include <string>
#include <vector>
class GLoaderInterface
{
public:
GLoaderInterface(const std::string filename)
: m_fileName(filename)
, m_status(true) { ; }
std::string getFileName() const { return m_fileName; }
bool getStatus() { return m_status; } // true = good, false = fail
virtual std::vector<std::string> getGeomNames() = 0;
virtual void startLoader() = 0;
protected:
std::string m_fileName;
bool m_status;
};
#endif
+154
View File
@@ -0,0 +1,154 @@
/* IGeometryTracer.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 10/02/13
*
* Authors(s):
* DRH
*
* Description:
* Interface class that specifies necessary functions to define a
* geometry tracer.
*/
#ifndef IGEOMETRYTRACER_H
#define IGEOMETRYTRACER_H
// System headers
#include <string.h>
#include <string>
#include <vector>
// Local headers
#include "INativeGeometry.h"
namespace GeomConversion {
namespace Interface {
//*******************************************************************
// NAME one_hit
//
// DESCRIPTION
// Holds data used to hold a single hit (in or out) along a ray.
//*******************************************************************
struct one_hit
{
double point[3];
double normal[3];
// long solidNumber;
std::string solidName;
long solidSurface;
};
#define ONE_HIT_INIT(onehit) { \
memset(onehit.point, 0, sizeof(double)*3); \
memset(onehit.normal, 0, sizeof(double)*3); \
onehit.solidName = ""; \
onehit.solidSurface = 0; \
}
//*******************************************************************
// NAME ray_result
//
// DESCRIPTION
// Holds data of all hits along a ray.
//*******************************************************************
struct ray_results
{
double origin[3];
double dir[3];
int x, y;
std::vector<struct one_hit> hitData;
};
#define RAY_RESULTS_INIT(rayres) { \
memset(rayres.origin, 0, sizeof(double)*3); \
memset(rayres.dir, 0, sizeof(double)*3); \
rayres.x = rayres.y = 0; \
rayres.hitData.clear(); \
}
#define RAY_RESULTS_COPY(dest, src) { \
RAY_RESULTS_INIT(dest); \
memcpy(dest.origin, src.origin, sizeof(double)*3); \
memcpy(dest.dir, src.dir, sizeof(double)*3); \
dest.x = src.x; \
dest.y = src.y; \
dest.hitData.insert(dest.hitData.end(), src.hitData.begin(), src.hitData.end()); \
}
//*******************************************************************
// NAME trace_ray_data
//
// DESCRIPTION
// Holds data info pertaining to a ray, including the results.
//*******************************************************************
struct trace_data
{
double point[3];
double direc[3];
double length;
struct ray_results results;
};
#define TRACE_DATA_INIT(trd) { \
memset(trd.point, 0, sizeof(double)*3); \
memset(trd.direc, 0, sizeof(double)*3); \
trd.length = 0; \
RAY_RESULTS_INIT(trd.results); \
}
#define TRACE_DATA_COPY(dest, src) { \
memcpy(dest.point, src.point, sizeof(double)*3); \
memcpy(dest.direc, src.direc, sizeof(double)*3); \
dest.length = src.length; \
RAY_RESULTS_COPY(dest.results, src.results); \
}
/**
* IGeometryTracer
*
* Defines an interface that specifies necessary functions to define a
* geometry tracer.
*/
class IGeometryTracer
{
public:
IGeometryTracer(INativeGeometry *ng)
: m_geometry(ng) { ; }
virtual ~IGeometryTracer() { ; }
/* User must define how to shoot a ray */
virtual void fireRay(struct trace_data*) = 0;
protected:
INativeGeometry *m_geometry; /* pointer to a geometry */
};
} // namespace Interface
} // namespace GeomConversion
#endif
+92
View File
@@ -0,0 +1,92 @@
/* INativeGeometry.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/20/13
*
* Authors(s):
* DRH
*
* Description:
* Interface class that specifies necessary functions to load and operate
* with native geometry.
*/
#ifndef INATIVEGEOMETRY_H
#define INATIVEGEOMETRY_H
// System headers
#include <string>
namespace GeomConversion {
namespace Interface {
// geometry types -- these will increase as more types are added
enum GeometryType { BRLCAD, UNKNOWN };
/**
* INativeGeometry
*
* Defines an interface to load and operate with native geometry.
*/
class INativeGeometry
{
public:
INativeGeometry(std::string filename)
: m_filename(filename)
, m_geometryType(UNKNOWN) { ; }
virtual ~INativeGeometry() { ; }
GeometryType getGeometryType () { return m_geometryType; }
virtual void* getGeometry() = 0;
std::string getGeomtryFilename() { return m_filename; }
virtual void loadGeometry(std::string, int tcount=1) = 0;
virtual void cleanupGeometry() {;}
// These are arrays of 3 elements!
virtual double* getGeometryMin() = 0;
virtual double* getGeometryMax() = 0;
// These are needed for certain geometries, ignored for others
virtual void loadGeometry(std::string, std::string, int tcount=1) {;}
virtual int getMode() {return 2;}
virtual int getMaterial() {return 1;}
virtual float getThickness() {return 1.0;}
virtual int getPosition() {return 2;}
protected:
std::string m_filename;
GeometryType m_geometryType;
};
} // namespace Interface
} // namespace GeomConversion
#endif
+159
View File
@@ -0,0 +1,159 @@
/* ISampler.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 10/09/13
*
* Authors(s):
* DRH
*
* Description:
* Interface class that specifies what is necessary to be a sampler.
*/
#ifndef ISAMPLER_H
#define ISAMPLER_H
// System headers
#include <vector>
// Qt headers
#if defined(COMPILE_FOR_VSL)
#define USE_QT 1
#else
#define USE_QT 0
#endif
#if USE_QT
#include <QObject>
#include <QList>
#include <QThread>
#include <QMutex>
#else
/* Pthread libraries */
#include <pthread.h>
#if defined (_GNU_SOURCE)
#include <sys/sysinfo.h>
#endif
#endif
// Local headers
#include "IGeometryTracer.h"
// Constructor Parameters are "defined" here (based on
// using Qt or not) so it's more readable later.
// Also, preprocessor for other things
#if USE_QT
#define SAMPLER_CONST_DEF Interface::INativeGeometry *ng, \
std::vector<Interface::IGeometryTracer *> &tracers, \
QList<QThread *> &threads, QObject *parent = NULL
#define SAMPLER_CONST_IMP Interface::INativeGeometry *ng, \
std::vector<Interface::IGeometryTracer *> &tracers, \
QList<QThread *> &threads, QObject *parent
#define SAMPLER_CONST_PARAMS ng, tracers, threads, parent
#define SAMPLER_CONST_INITS QObject(parent), \
m_threads(threads), \
m_canceled(false)
#define SAMPLER_THREAD_EXIT() { ; }
#else
#define SAMPLER_CONST_DEF Interface::INativeGeometry *ng, \
std::vector<Interface::IGeometryTracer *> &tracers
#define SAMPLER_CONST_IMP Interface::INativeGeometry *ng, \
std::vector<Interface::IGeometryTracer *>& tracers
#define SAMPLER_CONST_PARAMS ng, tracers
#define SAMPLER_THREAD_EXIT() pthread_exit(0);
#endif
namespace GeomConversion {
namespace Interface {
/**
* ISampler
*
* Defines an interface that specifies what is necessary to be a sampler.
*/
class ISampler
#if USE_QT
: public QObject
#endif
{
#if USE_QT
Q_OBJECT
#endif
public:
ISampler(SAMPLER_CONST_DEF)
:
#if USE_QT
SAMPLER_CONST_INITS,
#endif
m_geometry(ng)
, m_threadsDone(0)
, m_tracers(tracers)
, m_prepped(false)
{ m_threadCount = tracers.size(); }
virtual ~ISampler() {;}
virtual void setSpacing(float) = 0;
virtual void prepSample() = 0;
virtual void endSample() = 0;
#if USE_QT
virtual void stopSampling() = 0;
virtual float getProgress() { return 0.0; }
virtual QString getStatusString() { return QString(); }
virtual void updateProgress() { emit updateSamplerProgress(); }
signals:
void updateSamplerProgress();
void finished();
void startWorkers();
public slots:
virtual void workerFinished() = 0;
#endif
virtual void runSample() = 0;
protected:
#if USE_QT
QList<QThread *> &m_threads;
bool m_canceled;
#endif
INativeGeometry *m_geometry;
int m_threadCount;
int m_threadsDone;
std::vector<IGeometryTracer *> &m_tracers;
bool m_prepped;
};
} // namespace Interface
} // namespace GeomConversion
#endif
@@ -0,0 +1,39 @@
set(GCT_DECIMATION_SRCS
meshcorrection.c
meshdecimation.c
meshdecimationSSE2.c
meshdecimationSSE3.c
meshdecimationSSE4p1.c
meshoptimizer.c
meshoptimization.cpp
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../Auxiliary
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
)
add_library(MeshDecimation SHARED ${GCT_DECIMATION_SRCS})
target_link_libraries(MeshDecimation AUX ${CMAKE_THREAD_LIBS_INIT})
set_target_properties(MeshDecimation PROPERTIES VERSION 1.1.0 SOVERSION 1)
install(TARGETS MeshDecimation
RUNTIME DESTINATION ${BIN_DIR}
LIBRARY DESTINATION ${LIB_DIR}
ARCHIVE DESTINATION ${LIB_DIR})
if(MSVC)
set_property(TARGET MeshDecimation APPEND PROPERTY COMPILE_DEFINITIONS "DECIMATION_DLL_EXPORTS")
endif(MSVC)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,43 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int mcMeshCorrection( size_t vertexcount, void *vertex, int vertexwidth, size_t vertexstride, size_t tricount, void *indices, int indiceswidth, size_t indicesstride, long attemptcount, int flags )
;
#define MC_FLAGS_TRIANGLE_WINDING_CW (0x1)
#define MC_FLAGS_TRIANGLE_WINDING_CCW (0x2)
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,148 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
#define MD_ATTRIB_MAX (16)
typedef struct
{
void *base;
int width;
size_t count;
size_t stride;
int flags;
} mdOpAttrib;
typedef struct
{
double progress;
int stage;
const char *stagename;
long trianglecount;
} mdStatus;
enum
{
MD_STATUS_STAGE_INIT,
MD_STATUS_STAGE_BUILDVERTICES,
MD_STATUS_STAGE_BUILDTRIANGLES,
MD_STATUS_STAGE_BUILDTRIREFS,
MD_STATUS_STAGE_BUILDQUEUE,
MD_STATUS_STAGE_DECIMATION,
MD_STATUS_STAGE_STORE,
MD_STATUS_STAGE_DONE,
MD_STATUS_STAGE_COUNT
};
typedef struct
{
size_t vertexcount;
void *vertex;
int vertexwidth;
size_t vertexstride;
size_t vertexalloc;
void *indices;
int indiceswidth;
size_t indicesstride;
size_t tricount;
double decimationstrength;
int decimationcount;
int attribcount;
mdOpAttrib attrib[MD_ATTRIB_MAX];
mdOpAttrib normalattrib;
long msecs;
/* Status callback */
long statusmiliseconds;
void *statusopaquepointer;
void (*statuscallback)( void *opaquepointer, const mdStatus *status );
/* Advanced configuration options */
double compactnesstarget;
double compactnesspenalty;
int syncstepcount;
double normalsearchangle;
size_t maxmemorysize;
} mdOperation;
/*
* This function exists only to read CPUID and NUMA information once in a thread safe
* manner, in case you want to launch multiple mdMeshDecimation() simultaneously.
*/
void mdInit();
/*
* Set up the mdOperation struct to configure a mesh decimation task.
*/
void mdOperationInit( mdOperation *op );
void mdOperationData( mdOperation *op, size_t vertexcount, void *vertex, int vertexwidth, size_t vertexstride, size_t tricount, void *indices, int indiceswidth, size_t indicesstride );
int mdOperationAddAttrib( mdOperation *op, void *base, int width, size_t count, size_t stride, int flags );
void mdOperationStrength( mdOperation *op, double decimationstrength );
void mdOperationStatusCallback( mdOperation *op, void (*statuscallback)( void *opaquepointer, const mdStatus *status ), void *opaquepointer, long miliseconds );
#define MD_ATTRIB_FLAGS_NORMALIZE (0x1)
#define MD_ATTRIB_FLAGS_COMPUTE_NORMALS (0x2)
/*
* Decimate the mesh specifed by the mdOperation struct.
*/
int mdMeshDecimation( mdOperation *operation, int threadcount, int flags );
/* Slightly increases the quality of the mesh decimation */
#define MD_FLAGS_CONTINUOUS_UPDATE (0x1)
/* Do not pack vertices */
#define MD_FLAGS_NO_VERTEX_PACKING (0x2)
/* Allow cloning/splitting of vertices with diverging normals when recomputing normals */
#define MD_FLAGS_NORMAL_VERTEX_SPLITTING (0x4)
/* Define orientation of triangles when rebuilding normals */
#define MD_FLAGS_TRIANGLE_WINDING_CW (0x8)
#define MD_FLAGS_TRIANGLE_WINDING_CCW (0x10)
/* Do not actually do any decimation, in case all you actually want to do is to recompute normals */
#define MD_FLAGS_NO_DECIMATION (0x20)
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,275 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include "cpuconfig.h"
#include "cpuinfo.h"
#include "cc.h"
#include "mm.h"
#include "mmhash.h"
#include "math3d.h"
#include "mmbinsort.h"
#include "meshdecimation.h"
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#ifdef __SSE2__
#include <emmintrin.h>
#endif
#ifdef __SSE3__
#include <pmmintrin.h>
#endif
#ifdef __SSSE3__
#include <tmmintrin.h>
#endif
#ifdef __SSE4A__
#include <ammintrin.h>
#endif
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
/****/
#ifdef __SSE2__
#define MD_CONFIG_SSE2_SUPPORT
#else
#warning "SSE2 wasn't enabled to compile this file."
#endif
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define RF_ALIGN16 __attribute__((aligned(16)))
#elif defined(_MSC_VER)
#define RF_ALIGN16 __declspec(align(16))
#else
#define RF_ALIGN16
#warning "SSE Disabled: Unsupported Compiler."
#ifdef MD_CONFIG_SSE2_SUPPORT
#undef MD_CONFIG_SSE2_SUPPORT
#endif
#endif
#define MD_CONFIG_SSE_APPROX
#ifdef MD_CONFIG_SSE2_SUPPORT
typedef union
{
__m128 v;
float f[4];
} m128f;
int mdPathSSE2 = 0x1 | 0x2;
#define MD_COMPACTNESS_NORMALIZATION_FACTOR (0.5*4.0*1.732050808)
float mdEdgeCollapsePenaltyTriangleSSE2f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag, float compactnesstarget )
{
float penalty, compactness, oldcompactness, newcompactness, vectadp, norm;
__m128 left;
m128f vecta, oldvectb, oldvectc, newvectb, newvectc, oldnormal, newnormal;
/* Normal of old triangle */
left = _mm_load_ps( leftpoint );
vecta.v = _mm_sub_ps( _mm_load_ps( rightpoint ), left );
oldvectb.v = _mm_sub_ps( _mm_load_ps( oldpoint ), left );
oldnormal.v = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta.v, vecta.v, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( oldvectb.v, oldvectb.v, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta.v, vecta.v, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( oldvectb.v, oldvectb.v, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Normal of new triangle */
newvectb.v = _mm_sub_ps( _mm_load_ps( newpoint ), left );
newnormal.v = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta.v, vecta.v, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( newvectb.v, newvectb.v, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta.v, vecta.v, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( newvectb.v, newvectb.v, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Detect normal inversion */
if( M3D_VectorDotProduct( oldnormal.f, newnormal.f ) < 0.0 )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vectadp = M3D_VectorDotProduct( vecta.f, vecta.f );
newvectc.v = _mm_sub_ps( _mm_load_ps( newpoint ), _mm_load_ps( rightpoint ) );
#ifdef MD_CONFIG_SSE_APPROX
norm = vectadp + M3D_VectorDotProduct( newvectb.f, newvectb.f ) + M3D_VectorDotProduct( newvectc.f, newvectc.f );
newcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( _mm_set_ss( M3D_VectorDotProduct( newnormal.f, newnormal.f ) ) ), _mm_set_ss( norm ) ) ) ) );
if( newcompactness < compactnesstarget )
{
#else
newcompactness = MD_COMPACTNESS_NORMALIZATION_FACTOR * sqrtf( M3D_VectorDotProduct( newnormal.f, newnormal.f ) );
norm = vectadp + M3D_VectorDotProduct( newvectb.f, newvectb.f ) + M3D_VectorDotProduct( newvectc.f, newvectc.f );
if( newcompactness < ( compactnesstarget * norm ) )
{
newcompactness /= norm;
#endif
oldvectc.v = _mm_sub_ps( _mm_load_ps( oldpoint ), _mm_load_ps( rightpoint ) );
#ifdef MD_CONFIG_SSE_APPROX
norm = vectadp + M3D_VectorDotProduct( oldvectb.f, oldvectb.f ) + M3D_VectorDotProduct( oldvectc.f, oldvectc.f );
oldcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( _mm_set_ss( M3D_VectorDotProduct( oldnormal.f, oldnormal.f ) ) ), _mm_set_ss( norm ) ) ) ) );
#else
oldcompactness = ( MD_COMPACTNESS_NORMALIZATION_FACTOR * sqrtf( M3D_VectorDotProduct( oldnormal.f, oldnormal.f ) ) ) / ( vectadp + M3D_VectorDotProduct( oldvectb.f, oldvectb.f ) + M3D_VectorDotProduct( oldvectc.f, oldvectc.f ) );
#endif
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
double mdEdgeCollapsePenaltyTriangleSSE2d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag, double compactnesstarget )
{
__m128d vecta0, vecta1, oldvectb0, oldvectb1, oldvectc0, oldvectc1, newvectb0, newvectb1, newvectc0, newvectc1;
__m128d oldnormal0, oldnormal1, newnormal0, newnormal1;
__m128d dotprsum;
__m128d left0, left1;
double newcompactness, oldcompactness, compactness, penalty, norm;
static double zero = 0.0;
/* Normal of old triangle */
left0 = _mm_load_pd( leftpoint+0 );
left1 = _mm_load_sd( leftpoint+2 );
vecta0 = _mm_sub_pd( _mm_load_pd( rightpoint+0 ), left0 );
vecta1 = _mm_sub_pd( _mm_load_pd( rightpoint+2 ), left1 );
oldvectb0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), left0 );
oldvectb1 = _mm_sub_pd( _mm_load_pd( oldpoint+2 ), left1 );
oldnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( oldvectb1, oldvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( oldvectb0, oldvectb1, _MM_SHUFFLE2(0,1) ) )
);
oldnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( oldvectb0, oldvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), oldvectb0 )
);
/* Normal of new triangle */
newvectb0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), left0 );
newvectb1 = _mm_sub_pd( _mm_load_pd( newpoint+2 ), left1 );
newnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( newvectb1, newvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( newvectb0, newvectb1, _MM_SHUFFLE2(0,1) ) )
);
newnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( newvectb0, newvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), newvectb0 )
);
/* Detect normal inversion */
dotprsum = _mm_mul_pd( oldnormal0, newnormal0 );
dotprsum = _mm_add_sd( _mm_add_sd( dotprsum, _mm_unpackhi_pd( dotprsum, dotprsum ) ), _mm_mul_sd( oldnormal1, newnormal1 ) );
if( _mm_comilt_sd( dotprsum, _mm_load_sd( &zero ) ) )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vecta0 = _mm_mul_pd( vecta0, vecta0 );
vecta0 = _mm_add_sd( _mm_add_sd( vecta0, _mm_unpackhi_pd( vecta0, vecta0 ) ), _mm_mul_sd( vecta1, vecta1 ) );
newvectc0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), _mm_load_pd( rightpoint+0 ) );
newvectc1 = _mm_sub_sd( _mm_load_sd( newpoint+2 ), _mm_load_sd( rightpoint+2 ) );
newnormal0 = _mm_mul_pd( newnormal0, newnormal0 );
newnormal0 = _mm_add_sd( _mm_add_sd( newnormal0, _mm_unpackhi_pd( newnormal0, newnormal0 ) ), _mm_mul_sd( newnormal1, newnormal1 ) );
newvectb0 = _mm_mul_pd( newvectb0, newvectb0 );
newvectb0 = _mm_add_sd( _mm_add_sd( newvectb0, _mm_unpackhi_pd( newvectb0, newvectb0 ) ), _mm_mul_sd( newvectb1, newvectb1 ) );
newvectc0 = _mm_mul_pd( newvectc0, newvectc0 );
newvectc0 = _mm_add_sd( _mm_add_sd( newvectc0, _mm_unpackhi_pd( newvectc0, newvectc0 ) ), _mm_mul_sd( newvectc1, newvectc1 ) );
norm = _mm_cvtsd_f64( _mm_add_sd( vecta0, _mm_add_sd( newvectb0, newvectc0 ) ) );
newcompactness = _mm_cvtsd_f64( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( newnormal0, newnormal0 ) ) );
if( newcompactness < ( compactnesstarget * norm ) )
{
newcompactness /= norm;
oldvectc0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), _mm_load_pd( rightpoint+0 ) );
oldvectc1 = _mm_sub_sd( _mm_load_sd( oldpoint+2 ), _mm_load_sd( rightpoint+2 ) );
oldnormal0 = _mm_mul_pd( oldnormal0, oldnormal0 );
oldnormal0 = _mm_add_sd( _mm_add_sd( oldnormal0, _mm_unpackhi_pd( oldnormal0, oldnormal0 ) ), _mm_mul_sd( oldnormal1, oldnormal1 ) );
oldvectb0 = _mm_mul_pd( oldvectb0, oldvectb0 );
oldvectb0 = _mm_add_sd( _mm_add_sd( oldvectb0, _mm_unpackhi_pd( oldvectb0, oldvectb0 ) ), _mm_mul_sd( oldvectb1, oldvectb1 ) );
oldvectc0 = _mm_mul_pd( oldvectc0, oldvectc0 );
oldvectc0 = _mm_add_sd( _mm_add_sd( oldvectc0, _mm_unpackhi_pd( oldvectc0, oldvectc0 ) ), _mm_mul_sd( oldvectc1, oldvectc1 ) );
oldcompactness = _mm_cvtsd_f64( _mm_div_sd( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( oldnormal0, oldnormal0 ) ), _mm_add_sd( vecta0, _mm_add_sd( oldvectb0, oldvectc0 ) ) ) );
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
#else
int mdPathSSE2 = 0x0;
float mdEdgeCollapsePenaltyTriangleSSE2f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag )
{
return 0.0;
}
double mdEdgeCollapsePenaltyTriangleSSE2d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag )
{
return 0.0;
}
#endif
@@ -0,0 +1,286 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include "cpuconfig.h"
#include "cpuinfo.h"
#include "cc.h"
#include "mm.h"
#include "mmhash.h"
#include "math3d.h"
#include "mmbinsort.h"
#include "meshdecimation.h"
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#ifdef __SSE2__
#include <emmintrin.h>
#endif
#ifdef __SSE3__
#include <pmmintrin.h>
#endif
#ifdef __SSSE3__
#include <tmmintrin.h>
#endif
#ifdef __SSE4A__
#include <ammintrin.h>
#endif
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
/****/
#ifdef __SSE3__
#define MD_CONFIG_SSE3_SUPPORT
#else
#warning "SSE3 wasn't enabled to compile this file."
#endif
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define RF_ALIGN16 __attribute__((aligned(16)))
#elif defined(_MSC_VER)
#define RF_ALIGN16 __declspec(align(16))
#else
#define RF_ALIGN16
#warning "SSE Disabled: Unsupported Compiler."
#ifdef MD_CONFIG_SSE3_SUPPORT
#undef MD_CONFIG_SSE3_SUPPORT
#endif
#endif
#define MD_CONFIG_SSE_APPROX
#ifdef MD_CONFIG_SSE3_SUPPORT
int mdPathSSE3 = 0x1 | 0x2;
#define MD_COMPACTNESS_NORMALIZATION_FACTOR (0.5*4.0*1.732050808)
float mdEdgeCollapsePenaltyTriangleSSE3f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag, float compactnesstarget )
{
float penalty, compactness, oldcompactness, newcompactness;
static float zero = 0.0;
__m128 left, vecta, oldvectb, oldvectc, newvectb, newvectc, oldnormal, newnormal, dotproduct;
/* Normal of old triangle */
left = _mm_load_ps( leftpoint );
vecta = _mm_sub_ps( _mm_load_ps( rightpoint ), left );
oldvectb = _mm_sub_ps( _mm_load_ps( oldpoint ), left );
oldnormal = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( oldvectb, oldvectb, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( oldvectb, oldvectb, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Normal of new triangle */
newvectb = _mm_sub_ps( _mm_load_ps( newpoint ), left );
newnormal = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( newvectb, newvectb, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( newvectb, newvectb, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Detect normal inversion */
dotproduct = _mm_mul_ps( oldnormal, newnormal );
dotproduct = _mm_hadd_ps( dotproduct, dotproduct );
dotproduct = _mm_hadd_ps( dotproduct, dotproduct );
if( _mm_comilt_ss( dotproduct, _mm_load_ss( &zero ) ) )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vecta = _mm_mul_ps( vecta, vecta );
vecta = _mm_hadd_ps( vecta, vecta );
vecta = _mm_hadd_ps( vecta, vecta );
newvectc = _mm_sub_ps( _mm_load_ps( newpoint ), _mm_load_ps( rightpoint ) );
newnormal = _mm_mul_ps( newnormal, newnormal );
newnormal = _mm_hadd_ps( newnormal, newnormal );
newnormal = _mm_hadd_ps( newnormal, newnormal );
newvectb = _mm_mul_ps( newvectb, newvectb );
newvectb = _mm_hadd_ps( newvectb, newvectb );
newvectb = _mm_hadd_ps( newvectb, newvectb );
newvectc = _mm_mul_ps( newvectc, newvectc );
newvectc = _mm_hadd_ps( newvectc, newvectc );
newvectc = _mm_hadd_ps( newvectc, newvectc );
#ifdef MD_CONFIG_SSE_APPROX
newcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( newnormal ), _mm_add_ss( _mm_add_ss( vecta, newvectb ), newvectc ) ) ) ) );
#else
newcompactness = _mm_cvtss_f32( _mm_div_ss( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_ss( newnormal ) ), _mm_add_ss( _mm_add_ss( vecta, newvectb ), newvectc ) ) );
#endif
if( newcompactness < compactnesstarget )
{
oldvectc = _mm_sub_ps( _mm_load_ps( oldpoint ), _mm_load_ps( rightpoint ) );
oldnormal = _mm_mul_ps( oldnormal, oldnormal );
oldnormal = _mm_hadd_ps( oldnormal, oldnormal );
oldnormal = _mm_hadd_ps( oldnormal, oldnormal );
oldvectb = _mm_mul_ps( oldvectb, oldvectb );
oldvectb = _mm_hadd_ps( oldvectb, oldvectb );
oldvectb = _mm_hadd_ps( oldvectb, oldvectb );
oldvectc = _mm_mul_ps( oldvectc, oldvectc );
oldvectc = _mm_hadd_ps( oldvectc, oldvectc );
oldvectc = _mm_hadd_ps( oldvectc, oldvectc );
#ifdef MD_CONFIG_SSE_APPROX
oldcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( oldnormal ), _mm_add_ss( _mm_add_ss( vecta, oldvectb ), oldvectc ) ) ) ) );
#else
oldcompactness = _mm_cvtss_f32( _mm_div_ss( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_ss( oldnormal ) ), _mm_add_ss( _mm_add_ss( vecta, oldvectb ), oldvectc ) ) );
#endif
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
double mdEdgeCollapsePenaltyTriangleSSE3d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag, double compactnesstarget )
{
__m128d vecta0, vecta1, oldvectb0, oldvectb1, oldvectc0, oldvectc1, newvectb0, newvectb1, newvectc0, newvectc1;
__m128d oldnormal0, oldnormal1, newnormal0, newnormal1;
__m128d dotprsum;
__m128d left0, left1;
double newcompactness, oldcompactness, compactness, penalty, norm;
static double zero = 0.0;
/* Normal of old triangle */
left0 = _mm_load_pd( leftpoint+0 );
left1 = _mm_load_sd( leftpoint+2 );
vecta0 = _mm_sub_pd( _mm_load_pd( rightpoint+0 ), left0 );
vecta1 = _mm_sub_pd( _mm_load_pd( rightpoint+2 ), left1 );
oldvectb0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), left0 );
oldvectb1 = _mm_sub_pd( _mm_load_pd( oldpoint+2 ), left1 );
oldnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( oldvectb1, oldvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( oldvectb0, oldvectb1, _MM_SHUFFLE2(0,1) ) )
);
oldnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( oldvectb0, oldvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), oldvectb0 )
);
/* Normal of new triangle */
newvectb0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), left0 );
newvectb1 = _mm_sub_pd( _mm_load_pd( newpoint+2 ), left1 );
newnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( newvectb1, newvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( newvectb0, newvectb1, _MM_SHUFFLE2(0,1) ) )
);
newnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( newvectb0, newvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), newvectb0 )
);
/* Detect normal inversion */
dotprsum = _mm_mul_pd( oldnormal0, newnormal0 );
dotprsum = _mm_add_sd( _mm_hadd_pd( dotprsum, dotprsum ), _mm_mul_sd( oldnormal1, newnormal1 ) );
if( _mm_comilt_sd( dotprsum, _mm_load_sd( &zero ) ) )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vecta0 = _mm_mul_pd( vecta0, vecta0 );
vecta0 = _mm_add_sd( _mm_hadd_pd( vecta0, vecta0 ), _mm_mul_sd( vecta1, vecta1 ) );
newvectc0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), _mm_load_pd( rightpoint+0 ) );
newvectc1 = _mm_sub_sd( _mm_load_sd( newpoint+2 ), _mm_load_sd( rightpoint+2 ) );
newnormal0 = _mm_mul_pd( newnormal0, newnormal0 );
newnormal0 = _mm_add_sd( _mm_hadd_pd( newnormal0, newnormal0 ), _mm_mul_sd( newnormal1, newnormal1 ) );
newvectb0 = _mm_mul_pd( newvectb0, newvectb0 );
newvectb0 = _mm_add_sd( _mm_hadd_pd( newvectb0, newvectb0 ), _mm_mul_sd( newvectb1, newvectb1 ) );
newvectc0 = _mm_mul_pd( newvectc0, newvectc0 );
newvectc0 = _mm_add_sd( _mm_hadd_pd( newvectc0, newvectc0 ), _mm_mul_sd( newvectc1, newvectc1 ) );
norm = _mm_cvtsd_f64( _mm_add_sd( vecta0, _mm_add_sd( newvectb0, newvectc0 ) ) );
newcompactness = _mm_cvtsd_f64( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( newnormal0, newnormal0 ) ) );
if( newcompactness < ( compactnesstarget * norm ) )
{
newcompactness /= norm;
oldvectc0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), _mm_load_pd( rightpoint+0 ) );
oldvectc1 = _mm_sub_sd( _mm_load_sd( oldpoint+2 ), _mm_load_sd( rightpoint+2 ) );
oldnormal0 = _mm_mul_pd( oldnormal0, oldnormal0 );
oldnormal0 = _mm_add_sd( _mm_hadd_pd( oldnormal0, oldnormal0 ), _mm_mul_sd( oldnormal1, oldnormal1 ) );
oldvectb0 = _mm_mul_pd( oldvectb0, oldvectb0 );
oldvectb0 = _mm_add_sd( _mm_hadd_pd( oldvectb0, oldvectb0 ), _mm_mul_sd( oldvectb1, oldvectb1 ) );
oldvectc0 = _mm_mul_pd( oldvectc0, oldvectc0 );
oldvectc0 = _mm_add_sd( _mm_hadd_pd( oldvectc0, oldvectc0 ), _mm_mul_sd( oldvectc1, oldvectc1 ) );
oldcompactness = _mm_cvtsd_f64( _mm_div_sd( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( oldnormal0, oldnormal0 ) ), _mm_add_sd( vecta0, _mm_add_sd( oldvectb0, oldvectc0 ) ) ) );
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
#else
int mdPathSSE3 = 0x0;
float mdEdgeCollapsePenaltyTriangleSSE3f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag )
{
return 0.0;
}
double mdEdgeCollapsePenaltyTriangleSSE3d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag )
{
return 0.0;
}
#endif
@@ -0,0 +1,261 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include "cpuconfig.h"
#include "cpuinfo.h"
#include "cc.h"
#include "mm.h"
#include "mmhash.h"
#include "math3d.h"
#include "mmbinsort.h"
#include "meshdecimation.h"
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#ifdef __SSE2__
#include <emmintrin.h>
#endif
#ifdef __SSE3__
#include <pmmintrin.h>
#endif
#ifdef __SSSE3__
#include <tmmintrin.h>
#endif
#ifdef __SSE4A__
#include <ammintrin.h>
#endif
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
/****/
#ifdef __SSE4_1__
#define MD_CONFIG_SSE4_1_SUPPORT
#else
#warning "SSE4.1 wasn't enabled to compile this file."
#endif
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define RF_ALIGN16 __attribute__((aligned(16)))
#elif defined(_MSC_VER)
#define RF_ALIGN16 __declspec(align(16))
#else
#define RF_ALIGN16
#warning "SSE Disabled: Unsupported Compiler."
#ifdef MD_CONFIG_SSE4_1_SUPPORT
#undef MD_CONFIG_SSE4_1_SUPPORT
#endif
#endif
#define MD_CONFIG_SSE_APPROX
#ifdef MD_CONFIG_SSE4_1_SUPPORT
int mdPathSSE4p1 = 0x1 | 0x2;
#define MD_COMPACTNESS_NORMALIZATION_FACTOR (0.5*4.0*1.732050808)
float mdEdgeCollapsePenaltyTriangleSSE4p1f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag, float compactnesstarget )
{
float penalty, compactness, oldcompactness, newcompactness;
static float zero = 0.0;
__m128 left, vecta, oldvectb, oldvectc, newvectb, newvectc, oldnormal, newnormal;
/* Normal of old triangle */
left = _mm_load_ps( leftpoint );
vecta = _mm_sub_ps( _mm_load_ps( rightpoint ), left );
oldvectb = _mm_sub_ps( _mm_load_ps( oldpoint ), left );
oldnormal = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( oldvectb, oldvectb, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( oldvectb, oldvectb, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Normal of new triangle */
newvectb = _mm_sub_ps( _mm_load_ps( newpoint ), left );
newnormal = _mm_sub_ps(
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,0,2,1) ), _mm_shuffle_ps( newvectb, newvectb, _MM_SHUFFLE(3,1,0,2) ) ),
_mm_mul_ps( _mm_shuffle_ps( vecta, vecta, _MM_SHUFFLE(3,1,0,2) ), _mm_shuffle_ps( newvectb, newvectb, _MM_SHUFFLE(3,0,2,1) ) )
);
/* Detect normal inversion */
if( _mm_comilt_ss( _mm_dp_ps( oldnormal, newnormal, 0x1 | 0x70 ), _mm_load_ss( &zero ) ) )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vecta = _mm_dp_ps( vecta, vecta, 0x1 | 0x70 );
newvectc = _mm_sub_ps( _mm_load_ps( newpoint ), _mm_load_ps( rightpoint ) );
newnormal = _mm_dp_ps( newnormal, newnormal, 0x1 | 0x70 );
newvectb = _mm_dp_ps( newvectb, newvectb, 0x1 | 0x70 );
newvectc = _mm_dp_ps( newvectc, newvectc, 0x1 | 0x70 );
#ifdef MD_CONFIG_SSE_APPROX
newcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( newnormal ), _mm_add_ss( _mm_add_ss( vecta, newvectb ), newvectc ) ) ) ) );
#else
newcompactness = _mm_cvtss_f32( _mm_div_ss( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_ss( newnormal ) ), _mm_add_ss( _mm_add_ss( vecta, newvectb ), newvectc ) ) );
#endif
if( newcompactness < compactnesstarget )
{
oldvectc = _mm_sub_ps( _mm_load_ps( oldpoint ), _mm_load_ps( rightpoint ) );
oldnormal = _mm_dp_ps( oldnormal, oldnormal, 0x1 | 0x70 );
oldvectb = _mm_dp_ps( oldvectb, oldvectb, 0x1 | 0x70 );
oldvectc = _mm_dp_ps( oldvectc, oldvectc, 0x1 | 0x70 );
#ifdef MD_CONFIG_SSE_APPROX
oldcompactness = _mm_cvtss_f32( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_rcp_ss( _mm_mul_ss( _mm_rsqrt_ss( oldnormal ), _mm_add_ss( _mm_add_ss( vecta, oldvectb ), oldvectc ) ) ) ) );
#else
oldcompactness = _mm_cvtss_f32( _mm_div_ss( _mm_mul_ss( _mm_set_ss( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_ss( oldnormal ) ), _mm_add_ss( _mm_add_ss( vecta, oldvectb ), oldvectc ) ) );
#endif
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
double mdEdgeCollapsePenaltyTriangleSSE4p1d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag, double compactnesstarget )
{
__m128d vecta0, vecta1, oldvectb0, oldvectb1, oldvectc0, oldvectc1, newvectb0, newvectb1, newvectc0, newvectc1;
__m128d oldnormal0, oldnormal1, newnormal0, newnormal1;
__m128d dotprsum;
__m128d left0, left1;
double newcompactness, oldcompactness, compactness, penalty, norm;
static double zero = 0.0;
/* Normal of old triangle */
left0 = _mm_load_pd( leftpoint+0 );
left1 = _mm_load_sd( leftpoint+2 );
vecta0 = _mm_sub_pd( _mm_load_pd( rightpoint+0 ), left0 );
vecta1 = _mm_sub_pd( _mm_load_pd( rightpoint+2 ), left1 );
oldvectb0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), left0 );
oldvectb1 = _mm_sub_pd( _mm_load_pd( oldpoint+2 ), left1 );
oldnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( oldvectb1, oldvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( oldvectb0, oldvectb1, _MM_SHUFFLE2(0,1) ) )
);
oldnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( oldvectb0, oldvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), oldvectb0 )
);
/* Normal of new triangle */
newvectb0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), left0 );
newvectb1 = _mm_sub_pd( _mm_load_pd( newpoint+2 ), left1 );
newnormal0 = _mm_sub_pd(
_mm_mul_pd( _mm_shuffle_pd( vecta0, vecta1, _MM_SHUFFLE2(0,1) ), _mm_unpacklo_pd( newvectb1, newvectb0 ) ),
_mm_mul_pd( _mm_unpacklo_pd( vecta1, vecta0 ), _mm_shuffle_pd( newvectb0, newvectb1, _MM_SHUFFLE2(0,1) ) )
);
newnormal1 = _mm_sub_sd(
_mm_mul_sd( vecta0, _mm_unpackhi_pd( newvectb0, newvectb0 ) ),
_mm_mul_sd( _mm_unpackhi_pd( vecta0, vecta0 ), newvectb0 )
);
/* Detect normal inversion */
dotprsum = _mm_add_sd( _mm_dp_pd( oldnormal0, oldnormal0, 0x1 | 0x30 ), _mm_mul_sd( oldnormal1, newnormal1 ) );
if( _mm_comilt_sd( dotprsum, _mm_load_sd( &zero ) ) )
{
*denyflag = 1;
return 0.0;
}
/* Penalize long thin triangles */
penalty = 0.0;
vecta0 = _mm_add_sd( _mm_dp_pd( vecta0, vecta0, 0x1 | 0x30 ), _mm_mul_sd( vecta1, vecta1 ) );
newvectc0 = _mm_sub_pd( _mm_load_pd( newpoint+0 ), _mm_load_pd( rightpoint+0 ) );
newvectc1 = _mm_sub_sd( _mm_load_sd( newpoint+2 ), _mm_load_sd( rightpoint+2 ) );
newnormal0 = _mm_add_sd( _mm_dp_pd( newnormal0, newnormal0, 0x1 | 0x30 ), _mm_mul_sd( newnormal1, newnormal1 ) );
newvectb0 = _mm_add_sd( _mm_dp_pd( newvectb0, newvectb0, 0x1 | 0x30 ), _mm_mul_sd( newvectb1, newvectb1 ) );
newvectc0 = _mm_add_sd( _mm_dp_pd( newvectc0, newvectc0, 0x1 | 0x30 ), _mm_mul_sd( newvectc1, newvectc1 ) );
norm = _mm_cvtsd_f64( _mm_add_sd( vecta0, _mm_add_sd( newvectb0, newvectc0 ) ) );
newcompactness = _mm_cvtsd_f64( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( newnormal0, newnormal0 ) ) );
if( newcompactness < ( compactnesstarget * norm ) )
{
newcompactness /= norm;
oldvectc0 = _mm_sub_pd( _mm_load_pd( oldpoint+0 ), _mm_load_pd( rightpoint+0 ) );
oldvectc1 = _mm_sub_sd( _mm_load_sd( oldpoint+2 ), _mm_load_sd( rightpoint+2 ) );
oldnormal0 = _mm_add_sd( _mm_dp_pd( oldnormal0, oldnormal0, 0x1 | 0x30 ), _mm_mul_sd( oldnormal1, oldnormal1 ) );
oldvectb0 = _mm_add_sd( _mm_dp_pd( oldvectb0, oldvectb0, 0x1 | 0x30 ), _mm_mul_sd( oldvectb1, oldvectb1 ) );
oldvectc0 = _mm_add_sd( _mm_dp_pd( oldvectc0, oldvectc0, 0x1 | 0x30 ), _mm_mul_sd( oldvectc1, oldvectc1 ) );
oldcompactness = _mm_cvtsd_f64( _mm_div_sd( _mm_mul_sd( _mm_set_sd( MD_COMPACTNESS_NORMALIZATION_FACTOR ), _mm_sqrt_sd( oldnormal0, oldnormal0 ) ), _mm_add_sd( vecta0, _mm_add_sd( oldvectb0, oldvectc0 ) ) ) );
compactness = fmin( compactnesstarget, oldcompactness ) - newcompactness;
if( compactness > 0.0 )
penalty = compactness;
}
return penalty;
}
#else
int mdPathSSE4p1 = 0x0;
float mdEdgeCollapsePenaltyTriangleSSE4p1f( float *newpoint, float *oldpoint, float *leftpoint, float *rightpoint, int *denyflag )
{
return 0.0;
}
double mdEdgeCollapsePenaltyTriangleSSE4p1d( double *newpoint, double *oldpoint, double *leftpoint, double *rightpoint, int *denyflag )
{
return 0.0;
}
#endif
@@ -0,0 +1,93 @@
/* meshoptimization.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/26/13
*
* Authors(s):
* DRH
*
* Description:
* Mesh optimization routine.
*
*/
// System headers
#include <stdio.h>
// Local headers
#include "meshoptimization.h"
void
mesh_optimization (long vertexcount,
long tricount,
void *indices,
int indiceswidth,
int threadcount,
int optimizationlevel
#if DEBUG_MESH_OPTIMIZATION_VERBOSE
, std::string rname
#endif
)
{
int depth, flags, maxthreadcount;
switch( optimizationlevel )
{
case 3:
depth = 32;
flags = 0;
break;
case 2:
depth = 32;
flags = OPTIMIZATION_FLAGS;
break;
case 1:
depth = 16;
flags = OPTIMIZATION_FLAGS;
break;
case 0:
default:
return;
}
maxthreadcount = tricount / 16384;
if( threadcount > maxthreadcount )
threadcount = maxthreadcount;
#if DEBUG_MESH_OPTIMIZATION_VERBOSE
fprintf (stderr, "Optimizing %s...", rname.c_str());
#endif
moOptimizeMesh (vertexcount,
tricount,
indices, indiceswidth,
3*indiceswidth, 0, 0,
depth,
threadcount,
flags);
#if DEBUG_MESH_OPTIMIZATION_VERBOSE
fprintf (stderr, "Done.\n");
#endif
}
@@ -0,0 +1,74 @@
/* meshoptimization.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/26/13
*
* Authors(s):
* DRH
*
* Description:
* Mesh optimization routine.
*
*/
#ifndef MESHOPTIMIZATION_H
#define MESHOPTIMIZATION_H
// Standard headers
#include <string>
// Local headers
#include "meshoptimizer.h"
#define OPTIMIZATION_FLAGS MO_FLAGS_DISABLE_LOOK_AHEAD | \
MO_FLAGS_ENABLE_LAZY_SEARCH | \
MO_FLAGS_FAST_SEED_SELECT
#define DEBUG_MESH_OPTIMIZATION_VERBOSE 0
#ifdef __cplusplus
extern "C" {
#endif
void
mesh_optimization (long vertexcount,
long tricount,
void *indices,
int indiceswidth,
int threadcount,
int optimizationlevel
#if DEBUG_MESH_OPTIMIZATION_VERBOSE
, std::string rname
#endif
);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
/* *****************************************************************************
*
* Copyright (c) 2014 Alexis Naveros. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* *****************************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int moOptimizeMesh( size_t vertexcount, size_t tricount, void *indices, int indiceswidth, size_t indicesstride, void (*shufflecallback)( void *opaquepointer, long newvertexindex, long oldvertexindex ), void *shuffleopaquepointer, int vertexcachesize, int threadcount, int flags );
#define MO_FLAGS_FIXED_CACHE_SIZE (0x1)
#define MO_FLAGS_DISABLE_LOOK_AHEAD (0x2)
#define MO_FLAGS_ENABLE_LAZY_SEARCH (0x4)
#define MO_FLAGS_FAST_SEED_SELECT (0x8)
double moEvaluateMesh( size_t tricount, void *indices, int indiceswidth, size_t indicesstride, int vertexcachesize, int flags );
#ifdef __cplusplus
}
#endif
+32
View File
@@ -0,0 +1,32 @@
set(GCT_SAMPLER_SRCS
PointSampler.cpp
MarchingCubesSampler.cpp
)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
)
add_library(Sampler SHARED ${GCT_SAMPLER_SRCS})
set_target_properties(Sampler PROPERTIES VERSION 1.1.0 SOVERSION 1)
install(TARGETS Sampler
RUNTIME DESTINATION ${BIN_DIR}
LIBRARY DESTINATION ${LIB_DIR}
ARCHIVE DESTINATION ${LIB_DIR})
if(MSVC)
set_property(TARGET Sampler APPEND PROPERTY COMPILE_DEFINITIONS "SAMPLER_DLL_EXPORTS")
endif(MSVC)
# Local Variables:
# tab-width: 8
# mode: cmake
# indent-tabs-mode: t
# End:
# ex: shiftwidth=2 tabstop=8
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,204 @@
/* MarchingCubesSampler.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/22/13
*
* Authors(s):
* DRH
*
* Description:
* Implements a marching cubes technique to create a faceted representation
* of a piece of geometry.
*/
#ifndef MARCHINGCUBESSAMPLER_H
#define MARCHINGCUBESSAMPLER_H
// System headers
#include <vector>
// Local headers
#include "Interface/ISampler.h"
namespace GeomConversion {
namespace Sampler {
// Structures
struct edge_int
{
float pt[3];
float norm[3];
int set;
};
struct cube_def
{
int ll[2], lr[2], ul[2], ur[2];
double ymin, ymax;
/* output lists */
std::vector<float> points;
std::vector<float> normals;
};
struct mc_thread_data
{
double cellsize;
/* intermediate data */
Interface::trace_data **rayGrid;
int rowCount, colCount, rayCount;
int currRow, currCol, doneRays;
#if USE_QT
QMutex threadMutex;
#else
pthread_mutex_t threadMutex;
#endif
std::vector<struct cube_def> cubes;
int currCube;
};
//*******************************************************************
// NAME MarchingCubesWorker
//
// DESCRIPTION
// Holds data used/created on a per thread basis.
//
// NOTE
// Glorified structure declared as a class for Qt threading model.
//*******************************************************************
class MarchingCubesWorker
#if USE_QT
: public QObject
#endif
{
#if USE_QT
Q_OBJECT
#endif
public:
MarchingCubesWorker(struct mc_thread_data *td
#if USE_QT
, QObject *parent = NULL) : QObject(parent) ,
#else
) :
#endif
m_threadData(td)
{
#if USE_QT
m_keepGoing = true;
#endif
}
/* thread data */
unsigned long m_ID;
struct mc_thread_data *m_threadData;
/* input data */
Interface::IGeometryTracer *tracer;
void incrementStep()
{
#if USE_QT
emit doneStep();
#endif
}
#if USE_QT
bool m_keepGoing;
void pleaseStop() { m_keepGoing = false; }
signals:
void doneStep();
void finished();
public slots:
void run();
#endif
};
/**
* MarchingCubesSampler
*
* Implements a marching cubes technique to create a faceted representation
* of a piece of geometry.
*/
class MarchingCubesSampler : public Interface::ISampler
{
#if USE_QT
Q_OBJECT
#endif
public:
MarchingCubesSampler(SAMPLER_CONST_DEF);
~MarchingCubesSampler();
virtual void setSpacing(float s) { m_threadData.cellsize = s; }
virtual void prepSample();
virtual void endSample();
std::vector<float> getVertices() { return m_vertex; }
std::vector<float> getNormals() { return m_normal; }
std::vector<int> getIndices() { return m_index; }
#if USE_QT
virtual void stopSampling();
virtual float getProgress();
virtual QString getStatusString() { return m_statusStr; }
public slots:
void incrementStep() { m_doneSteps++; updateProgress(); }
virtual void workerFinished();
#endif
virtual void runSample();
private:
/* threading data */
std::vector<MarchingCubesWorker *> m_workers;
struct mc_thread_data m_threadData;
/* output storage */
std::vector<float> m_vertex;
std::vector<float> m_normal;
std::vector<int> m_index;
#if USE_QT
long m_doneSteps;
long m_totalSteps;
QString m_statusStr;
#endif
};
} // namespace Sampler
} // namespace GeomConversion
#endif
+692
View File
@@ -0,0 +1,692 @@
/* PointSampler.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/21/13
*
* Authors(s):
* DRH
* LB
*
* Description:
* Implements a point sample technique to get (x, y, z) locations on
* a piece of geometry.
*/
// System headers
#include <math.h>
// Local headers
#include "PointSampler.h"
#include "Auxiliary/gctcommon.h"
namespace GeomConversion {
namespace Sampler {
#if USE_QT
#define PS_CHECK_CANCEL() (! twd->m_keepGoing)
#else
#define PS_CHECK_CANCEL() (0)
#endif
//*******************************************************************
// NAME ray_results_differ
//
// INPUTS
// previousRayResults, currentRayResults - the ray results for the rays
//
// DESCRIPTION
// Check to see if the results of two rays are different.
// true = different.
//*******************************************************************
bool
ray_results_differ(const Interface::ray_results &previousRayResults,
const Interface::ray_results &currentRayResults)
{
// If the list sizes differ that is a dead give-away
if (previousRayResults.hitData.size() != currentRayResults.hitData.size())
return true;
for (unsigned i=0 ; i < previousRayResults.hitData.size() ; i++)
{
const Interface::one_hit &prevHit = previousRayResults.hitData[i];
const Interface::one_hit &currHit = currentRayResults.hitData[i];
// compare things in relative order of difficulty of the comparison
if (prevHit.solidSurface != currHit.solidSurface )
return true;
if (prevHit.solidName.compare(currHit.solidName))
return true;
}
return false;
}
//*******************************************************************
// NAME sub_sample
//
// INPUTS
// thisThreadResults - all the ray results for the current thread
// twd - pointer to the current thread's thread_worker_data
// prevResults - results from the previously shot ray
// currResults - results from the current ray
// depth, limit - variables to control depth of recursion
//
// DESCRIPTION
// Function performs sub sampling to determine if/where an edge occurs
// between 2 rays.
//*******************************************************************
void
sub_sample (std::vector<Interface::ray_results> &thisThreadResults,
const PointSamplerWorker *twd,
const Interface::ray_results &prevResults,
const Interface::ray_results &currResults,
const int depth, const int limit)
{
if (depth >= limit)
return;
Interface::trace_data middle_ray;
TRACE_DATA_INIT(middle_ray);
VADD2(middle_ray.point, currResults.origin, prevResults.origin);
VSCALE(middle_ray.point, middle_ray.point, 0.5);
VMOVE(middle_ray.direc, currResults.dir);
middle_ray.results.x = -1; // note that this is a sub-sampling ray
middle_ray.results.y = -1;
VMOVE(middle_ray.results.origin, middle_ray.point);
VMOVE(middle_ray.results.dir, middle_ray.direc);
twd->tracer->fireRay(&middle_ray);
bool diffLeft = ray_results_differ(prevResults, middle_ray.results);
bool diffRight = ray_results_differ(middle_ray.results, currResults);
unsigned remember = thisThreadResults.size();
if (diffLeft && diffRight)
{
sub_sample(thisThreadResults, twd,
prevResults, middle_ray.results,
depth+1, limit);
sub_sample(thisThreadResults, twd,
middle_ray.results, currResults,
depth+1, limit);
thisThreadResults.push_back(middle_ray.results);
}
else if (diffLeft)
{
sub_sample(thisThreadResults, twd,
prevResults, middle_ray.results,
depth+1, limit);
for (unsigned pos=remember; pos < thisThreadResults.size(); pos++)
{
Interface::ray_results &newerResults = thisThreadResults[pos];
if (!ray_results_differ(newerResults, currResults))
{
// somethig to my left also matches right so I am not needed
goto rightFound;
}
}
thisThreadResults.push_back(middle_ray.results);
rightFound:
;
}
else if (diffRight)
{
sub_sample(thisThreadResults, twd,
middle_ray.results, currResults,
depth+1, limit);
for (unsigned pos=remember ; pos < thisThreadResults.size() ; pos++)
{
Interface::ray_results &newerResults = thisThreadResults[pos];
if (!ray_results_differ(newerResults, prevResults))
{
// somethig to my right also matches left so I am not needed
goto leftFound;
}
}
thisThreadResults.push_back(middle_ray.results);
leftFound:
;
}
}
//*******************************************************************
// NAME check_subsample
//
// INPUTS
// twd - pointer to the current thread's thread_worker_data
// j - ???
// currResults - results from the current ray
// prevResults - results from the previously shot ray
// thisThreadResults - all the ray results for the current thread
//
// DESCRIPTION
// Check whether there is any sub-sampling needed and perform it if so.
//*******************************************************************
void
check_subsample(const PointSamplerWorker *twd,
const int j,
const Interface::ray_results &currResults,
const Interface::ray_results &prevResults,
std::vector<Interface::ray_results> &thisThreadResults)
{
Interface::ray_results lowerRowRayResults, diagonalRayResults;
RAY_RESULTS_INIT(lowerRowRayResults);
RAY_RESULTS_INIT(diagonalRayResults);
// look to see if we crossed a physical boundary
// along the i_axis and should sub-sample
if (ray_results_differ(prevResults, currResults))
{
sub_sample(thisThreadResults, twd,
prevResults, currResults,
0, twd->model->sub_division);
}
// look to see if we crossed a physical boundary
// along the j_axis and should sub-sample
if (j == 0)
return;
// look backwards for matching x,y-1 entry
for (int prevIdx=thisThreadResults.size()-1; prevIdx >= 0; prevIdx--)
{
if (thisThreadResults.at(prevIdx).x == currResults.x &&
thisThreadResults.at(prevIdx).y ==(currResults.y-1))
{
// found it
RAY_RESULTS_COPY(lowerRowRayResults, thisThreadResults[prevIdx]);
if (ray_results_differ(lowerRowRayResults, currResults))
{
sub_sample(thisThreadResults, twd,
lowerRowRayResults, currResults,
0, twd->model->sub_division);
}
// sample diagonally across the "cell"
if (ray_results_differ(prevResults, lowerRowRayResults))
{
sub_sample(thisThreadResults, twd,
prevResults, lowerRowRayResults,
0, twd->model->sub_division);
}
// now go looking back for the x-1,y-1 entry
// so we can sample along the other diagonal
for (int diagIdx=thisThreadResults.size()-1; diagIdx >= 0;
diagIdx--)
{
if (thisThreadResults.at(diagIdx).x ==(currResults.x-1) &&
thisThreadResults.at(diagIdx).y ==(currResults.y-1))
{
// found it
RAY_RESULTS_COPY(diagonalRayResults,
thisThreadResults[diagIdx]);
if (ray_results_differ(diagonalRayResults, currResults))
{
sub_sample(thisThreadResults, twd,
diagonalRayResults, currResults,
0, twd->model->sub_division);
}
break;
} // found x-1, y-1
}
break;
} // found x, y-1
}
}
//*******************************************************************
// NAME pointsample_worker
//
// INPUTS
// td - pointer to PointSamplerWorker
//
// DESCRIPTION
// Function called to perform work for each thread.
//*******************************************************************
void *
pointsample_worker (void *td)
{
PointSamplerWorker *twd = (PointSamplerWorker *) td;
Interface::trace_data prevRay, currentRay;
std::vector<Interface::ray_results> thisViewResults; // the results for the current view
std::vector<Interface::ray_results> thisThreadResults; // the total results for this thread
// make sure everythign is clear
thisThreadResults.clear();
TRACE_DATA_INIT(prevRay);
/* We shoot rays in the shootAxis direction,
* we step from bounding box min..max along the i_axis.
* we step from slabStartLineNumber..slabEndLineNumber along j_axis
*
* Conceptually, the bounding box of the object is divided into slabs
* along the j_axis. Each thread of computation handles one
* slab. Within a slab, the thread shoots rays along the individal
* lines (rows) stepping from mdl_min[i_axis]..mdl_max[i_axis].
*/
for (int shootAxis = 0; shootAxis < 3; shootAxis++)
{
if (PS_CHECK_CANCEL()) goto endWorker;
// make sure everything is clear
thisViewResults.clear();
TRACE_DATA_INIT(currentRay);
/* set direction vector */
int i_axis = (shootAxis + 1) % 3; // the axis we step between rays
int j_axis = (shootAxis + 2) % 3; // the slab axis
currentRay.point[shootAxis] = twd->model->model_min[shootAxis];
currentRay.direc[shootAxis] = 1.0;
currentRay.direc[i_axis] = 0.0;
currentRay.direc[j_axis] = 0.0;
// compute the dimensions of the slab along the j_axis dimension
float slabBottom = twd->cpuID * twd->model->perCpuSlabWidth[j_axis];
float slabTop = (twd->cpuID+1) * twd->model->perCpuSlabWidth[j_axis];
int slabStartLineNumber = ceil(slabBottom / twd->model->spacing);
int slabEndLineNumber = ceil(slabTop / twd->model->spacing);
for (long j=slabStartLineNumber ; j <= slabEndLineNumber ; j++)
{
if (PS_CHECK_CANCEL()) goto endWorker;
currentRay.point[j_axis] = twd->model->model_min[j_axis] + (j * twd->model->spacing);
prevRay.results.hitData.clear();
prevRay.results.x = -1;
prevRay.results.y = -1;
long iAxisSteps = ceil(twd->model->model_span[i_axis] / twd->model->spacing);
for (long i=0 ; i <= iAxisSteps ; i++)
{
if (PS_CHECK_CANCEL()) goto endWorker;
currentRay.point[i_axis] = twd->model->model_min[i_axis] + (i * twd->model->spacing);
currentRay.results.x = i;
currentRay.results.y = j;
VMOVE(currentRay.results.origin, currentRay.point);
VMOVE(currentRay.results.dir, currentRay.direc);
currentRay.results.hitData.clear();
// fire the ray
twd->tracer->fireRay(&currentRay);
if (j < slabEndLineNumber || (twd->cpuID+1) == twd->model->total_threads)
{
// record results
thisViewResults.push_back(currentRay.results);
}
if (twd->model->do_subsample && twd->model->sub_division > 0)
{
if (i > 0)
{
check_subsample(twd, j, currentRay.results,
prevRay.results, thisViewResults);
}
}
twd->completedRays++;
TRACE_DATA_COPY(prevRay, currentRay);
}
}
// copy the view results to the overall results
thisThreadResults.insert(thisThreadResults.end(),
thisViewResults.begin(),
thisViewResults.end());
}
thisViewResults.clear(); // not needed anymore
if (PS_CHECK_CANCEL()) goto endWorker;
// move all points to proper lists
for (unsigned i = 0; i < thisThreadResults.size(); i++)
{
std::vector<float> *points = &(twd->points);
std::vector<float> *normals = &(twd->normals);
std::vector<std::string> *solNumber = &(twd->solidNumber);
std::vector<long> *surfNumber = &(twd->surfNumber);
for (unsigned j = 0; j < thisThreadResults[i].hitData.size(); j++)
{
Interface::one_hit &hit = thisThreadResults[i].hitData[j];
/* save points and normals */
for (int a=0; a<3; a++)
{
points->push_back(hit.point[a]);
normals->push_back(hit.normal[a]);
}
/* save surface numbers and solid numbers */
solNumber->push_back(hit.solidName);
surfNumber->push_back(hit.solidSurface);
}
}
endWorker:
thisThreadResults.clear();
//fprintf (stderr, "Ending CPU %d\n", twd->cpuID);
SAMPLER_THREAD_EXIT();
return NULL;
}
#if USE_QT
//*******************************************************************
// NAME run
//
// INPUTS
// none
//
// DESCRIPTION
// Start the worker.
//*******************************************************************
void PointSamplerWorker::run()
{
pointsample_worker((void *) this);
emit finished();
}
#endif
//*******************************************************************
// NAME constructor
//
// INPUTS
// ti - pointer to a target
// tracers - list of tracer objects
// threads - list of already instantiated QThreads (Qt only)
// parent - parent QObject (Qt only, should be NULL)
//
// DESCRIPTION
// Construct the object.
//*******************************************************************
PointSampler::PointSampler(SAMPLER_CONST_IMP)
: Interface::ISampler(SAMPLER_CONST_PARAMS)
, m_spacing(1.0)
, m_subdivision(4)
{
m_points.clear();
m_normals.clear();
m_surfNumber.clear();
m_solidNumber.clear();
}
//*******************************************************************
// NAME destructor
//
// DESCRIPTION
// Cleanup the object.
//*******************************************************************
PointSampler::~PointSampler()
{
m_points.clear();
m_normals.clear();
m_surfNumber.clear();
m_solidNumber.clear();
}
//*******************************************************************
// NAME prepSample
//
// INPUTS
// none
//
// DESCRIPTION
// Preps data used across the entire model.
//*******************************************************************
void PointSampler::prepSample()
{
memset (&m_model, 0, sizeof (struct thread_model_data));
// load geometry and determine overall model data
VMOVE(m_model.model_min, m_geometry->getGeometryMin());
VMOVE(m_model.model_max, m_geometry->getGeometryMax());
VSUB2(m_model.model_span, m_model.model_max, m_model.model_min);
m_model.total_threads = m_threadCount;
m_model.sub_division = m_subdivision;
m_model.do_subsample = true; // always set to true
m_model.spacing = m_spacing;
for (int currentAxis = 0; currentAxis < 3; currentAxis++)
{
m_model.perCpuSlabWidth[currentAxis] = m_model.model_span[currentAxis] / m_threadCount;
m_model.ray_total += m_model.model_span[currentAxis] / m_spacing;
}
for (int i=0; i<m_threadCount; i++)
{
PointSamplerWorker *worker = new PointSamplerWorker();
// assign tracer object
worker->tracer = m_tracers[i];
// set pointer to model data
worker->model = &m_model;
// set completed rays
worker->completedRays = 0;
// set cpu ID
worker->cpuID = i;
// make sure output vectors are empty
worker->points.clear();
worker->normals.clear();
worker->surfNumber.clear();
worker->solidNumber.clear();
m_workers.push_back(worker);
#if USE_QT
// move the worker to it's thread
worker->moveToThread(m_threads.at(i));
// connect signals
connect(worker, SIGNAL(finished()),
this, SLOT(workerFinished()),
Qt::QueuedConnection);
connect(this, SIGNAL(startWorkers()),
worker, SLOT(run()),
Qt::QueuedConnection);
#endif
}
m_threadsDone = 0;
m_prepped = true;
}
//*******************************************************************
// NAME runSample
//
// INPUTS
// none
//
// DESCRIPTION
// Does the work to perform the point sampling, including subdividing
// the work amongst a desired number of threads.
//*******************************************************************
void PointSampler::runSample()
{
if (m_prepped)
{
#if USE_QT
emit startWorkers();
#else
// set up threading data
pthread_attr_t attr;
pthread_t *ptid = NULL;
pthread_attr_init (&attr);
ptid = (pthread_t *) malloc (sizeof (pthread_t) * m_threadCount);
memset (ptid, 0, sizeof (pthread_t) * m_threadCount);
/* start threading */
for (int i=0; i<m_threadCount; i++)
pthread_create (&ptid[i], &attr, pointsample_worker, (void*) (m_workers.at(i)));
/* thread join */
for (int i=0; i<m_threadCount; i++)
pthread_join(ptid[i], NULL);
/* get output data */
endSample();
if (ptid) free (ptid);
pthread_attr_destroy (&attr);
#endif
}
}
//*******************************************************************
// NAME endSample
//
// INPUTS
// none
//
// DESCRIPTION
// Move all the worker data to the main lists.
//*******************************************************************
void PointSampler::endSample()
{
/* get output data */
for (int i=0; i<m_threadCount; i++)
{
// if (i != 1) continue;
PointSamplerWorker *worker = m_workers.at(i);
std::vector<float> *points = &(worker->points);
std::vector<float> *normals = &(worker->normals);
m_points.insert(m_points.end(), points->begin(), points->end());
m_normals.insert(m_normals.end(), normals->begin(), normals->end());
std::vector<std::string> *solNum = &(worker->solidNumber);
std::vector<long> *surfNum = &(worker->surfNumber);
m_surfNumber.insert(m_surfNumber.end(), surfNum->begin(), surfNum->end());
m_solidNumber.insert(m_solidNumber.end(), solNum->begin(), solNum->end());
/* cleanup */
worker->tracer = NULL;
worker->points.clear();
worker->normals.clear();
worker->surfNumber.clear();
worker->solidNumber.clear();
delete worker;
}
m_workers.clear();
m_prepped = false;
}
#if USE_QT
//*******************************************************************
// NAME workerFinished
//
// INPUTS
// none
//
// DESCRIPTION
// Returns here when a worker is done it's part. Once all are done it
// does the finishing work.
//*******************************************************************
void PointSampler::workerFinished()
{
// wait for the threads to finish
m_threadsDone++;
updateProgress();
if (m_threadsDone < m_threadCount)
return;
if (!m_canceled)
endSample();
emit finished();
}
//*******************************************************************
// NAME getProgress
//
// INPUTS
// none
//
// DESCRIPTION
// Return the overall progress of the workers
//*******************************************************************
float PointSampler::getProgress()
{
int done_rays = 0;
float progress = 0.0;
for (unsigned i=0; i < m_workers.size(); i++)
done_rays += (m_workers[i])->completedRays;
if (m_model.ray_total)
progress = (float) done_rays / (float) m_model.ray_total;
if( progress > 100.0 )
progress = 100.0;
return progress;
}
//*******************************************************************
// NAME stopSampling
//
// INPUTS
// none
//
// DESCRIPTION
// Tell all the workers to stop
//*******************************************************************
void PointSampler::stopSampling()
{
m_canceled = true;
for (unsigned i=0; i<m_workers.size(); i++)
{
PointSamplerWorker *worker = m_workers.at(i);
worker->pleaseStop();
}
}
#endif
} // namespace Sampler
} // namespace GeomConversion
+179
View File
@@ -0,0 +1,179 @@
/* PointSampler.h
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/21/13
*
* Authors(s):
* DRH
*
* Description:
* Implements a point sample technique to get (x, y, z) locations on
* a piece of geometry.
*/
#ifndef POINTSAMPLER_H
#define POINTSAMPLER_H
// System headers
#include <vector>
// Local headers
#include "Interface/ISampler.h"
namespace GeomConversion {
namespace Sampler {
// Structures
//*******************************************************************
// NAME thread_model_data
//
// DESCRIPTION
// Holds data used across the entire geometric model.
//*******************************************************************
struct thread_model_data
{
int total_threads;
int sub_division;
bool do_subsample;
double spacing;
double model_min[3];
double model_max[3];
double model_span[3];
double perCpuSlabWidth[3];
int ray_total;
};
//*******************************************************************
// NAME PointSamplerWorker
//
// DESCRIPTION
// Holds data used/created on a per thread basis.
//
// NOTE
// Glorified structure declared as a class for Qt threading model.
//*******************************************************************
class PointSamplerWorker
#if USE_QT
: public QObject
#endif
{
#if USE_QT
Q_OBJECT
#endif
public:
#if USE_QT
PointSamplerWorker(QObject *parent = NULL) : QObject(parent) { m_keepGoing = true; }
#endif
/* input data */
Interface::IGeometryTracer *tracer;
struct thread_model_data *model;
int cpuID;
/* intermediate data */
int completedRays;
/* output data */
std::vector<float> points;
std::vector<float> normals;
std::vector<std::string> solidNumber;
std::vector<long> surfNumber;
#if USE_QT
bool m_keepGoing;
void pleaseStop() { m_keepGoing = false; }
signals:
void finished();
public slots:
void run();
#endif
};
/**
* PointSampler
*
* Implements a point sample technique to get (x, y, z) locations on
* a piece of geometry.
*/
class PointSampler : public Interface::ISampler
{
#if USE_QT
Q_OBJECT
#endif
public:
PointSampler(SAMPLER_CONST_DEF);
~PointSampler();
void setSubdivisionDepth(int d) { m_subdivision = d; }
virtual void setSpacing(float s) { m_spacing = s; }
virtual void prepSample();
virtual void endSample();
std::vector<float> getPoints() { return m_points; }
std::vector<float> getNormals() { return m_normals; }
std::vector<std::string> getSolidNumbers() { return m_solidNumber; }
std::vector<long> getSurfNumbers() { return m_surfNumber; }
#if USE_QT
virtual void stopSampling();
virtual float getProgress();
public slots:
virtual void workerFinished();
#endif
virtual void runSample();
private:
/* necessary inputs */
float m_spacing;
int m_subdivision;
struct thread_model_data m_model;
std::vector<PointSamplerWorker *> m_workers;
/* output storage */
std::vector<float> m_points;
std::vector<float> m_normals;
std::vector<std::string> m_solidNumber;
std::vector<long> m_surfNumber;
};
} // namespace Sampler
} // namespace GeomConversion
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../Auxiliary
)
add_executable(bpmain main.cpp)
target_link_libraries(bpmain librt libbu libbn AUX BallPivoting
${M_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
+349
View File
@@ -0,0 +1,349 @@
/* main.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/22/13
*
* Authors(s):
* DRH
*
* Description:
* This is the standalone ball pivoting application.
*
*/
/* Standard C/C++ libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
/* BRL-CAD libraries */
/* needed to set uint32_t in ballpivoting.h */
#include "bu.h"
/* Custom libraries */
#include "gctcommon.h"
#include "BallPivoting/ballpivoting.h"
/* defines */
#define DEBUG_BALL_PIVOTING_VERBOSE 0
/* structures */
typedef struct
{
float *vertex;
float *normal;
} BallPivotingPack;
/* globals */
std::vector<float> gVertex;
std::vector<float> gNormal;
std::vector<long> gVIndex;
std::vector<std::string> gGeom;
std::vector<long> gOffset;
/*============ STATIC FUNCTIONS ============*/
//******************************************************************************
// NAME ballpivoting_pack_callback
//
// INPUTS
// ???
//
// DESCRIPTION
// Callback from ball pivoting code to repack vertices.
//******************************************************************************
static void
ballpivoting_pack_callback( void *opaquepointer,
long newvertexindex,
long oldvertexindex )
{
BallPivotingPack *bppack;
float *src, *dst;
bppack = (BallPivotingPack *)opaquepointer;
src = &bppack->vertex[3*oldvertexindex];
dst = &bppack->vertex[3*newvertexindex];
memcpy( dst, src, 3*sizeof(float) );
src = &bppack->normal[3*oldvertexindex];
dst = &bppack->normal[3*newvertexindex];
memcpy( dst, src, 3*sizeof(float) );
return;
}
//******************************************************************************
// NAME ball_pivot
//
// INPUTS
// points - list of 3D points
// normals - list of normals for the points
// ballrange - ball range ratio
// spacing - cell spacing that was used to get points
//
// DESCRIPTION
// Function that actually performs the ball pivoting routines.
//******************************************************************************
static void
ball_pivot(std::vector<float> &points,
std::vector<float> &normals,
float ballrange,
float spacing)
{
int threadcount;
int pointcount = points.size() / 3;
float *vertex = &points[0];
float *normal = &normals[0];
bpOperation bp;
bpOutput output;
BallPivotingPack bppack;
int *bpindices;
int *triindices;
long bptricount, bpvertexcount;
bpOperationInit( &bp );
bpOperationSetInput( &bp,
pointcount,
vertex, 3*sizeof(float),
normal, 3*sizeof(float) );
if( ballrange <= 1.0 )
bpOperationSetBall( &bp, spacing );
else
bpOperationSetBallRange( &bp, spacing, ballrange * spacing );
bpOperationSetOutput( &bp,
BP_TRIANGLE_WINDING_CCW,
3*sizeof(int),
sizeof(int),
0, 0, 0 );
bpOperationNormalAgreement( &bp, 0.5, 0.5 );
/* Set up callback to pack vertices */
bppack.vertex = vertex;
bppack.normal = normal;
bpOperationVertexPackCallback( &bp, ballpivoting_pack_callback, &bppack );
threadcount = (int) ideal_thread_count ();
/*
* Note from Alexis:
* It could be a good idea to expose memory consumption limits...
* By default, it's set to 50% of system RAM.
* Indirectly, it acts to reduce the sampling rate when it's excessive for large parts.
*
* bp.maxmemorysize = 1*1024*1024*1024;
*
* Or, what about an adaptive sampling rate? 0.25mm is great for a truck's
* engine, not so much for the hood.
*/
#if DEBUG_BALL_PIVOTING_VERBOSE
fprintf( stderr, "Ball Pivoting Start, %d points, %f spacing, %d threads\n",
(int)pointcount, spacing, threadcount );
#endif
bpindices = (int *)bpConstructMesh( &bp,
&output,
threadcount,
BP_FLAGS_PACK_VERTICES | BP_FLAGS_ALLOW_REDUCTION );
#if DEBUG_BALL_PIVOTING_VERBOSE
fprintf( stderr, "Ball Pivoting End, %d vertices, %d triangles, %.3f seconds ( %d warnings, %d errors )\n",
(int)output.vertexcount, (int)output.trianglecount,
(double)output.msecs / 1000.0, output.warningcount,
output.errorcount );
#endif
bptricount = output.trianglecount;
bpvertexcount = output.vertexcount;
long offset = gVertex.size()/3; /* indices need to be offset by the vertices already present */
for( long i = bpvertexcount, j = 0 ; i ; i--, j += 3 )
{
gVertex.push_back(vertex[j+0]);
gVertex.push_back(vertex[j+1]);
gVertex.push_back(vertex[j+2]);
gNormal.push_back(normal[j+0]);
gNormal.push_back(normal[j+1]);
gNormal.push_back(normal[j+2]);
}
triindices = bpindices;
for( long i = bptricount ; i ; i--, triindices += 3 )
{
gVIndex.push_back( triindices[0] + offset );
gVIndex.push_back( triindices[1] + offset );
gVIndex.push_back( triindices[2] + offset );
}
free( bpindices );
}
/*============ MAIN FUNCTION ============*/
//******************************************************************************
// NAME main
//
// INPUTS
// argc - commandline argument count
// argv - array of commandline arguments
//
// DESCRIPTION
// Perform ball pivoting on a ".psamp" file generated from the
// pointsampler application.
//******************************************************************************
int
main (int argc, char **argv)
{
FILE *fp1 = NULL, *fp2 = NULL;
char buffer[255], ch, gname[100];
float csize = 0.0;
float ballrange = 1.0;
std::vector<float> points, normals;
if (argc < 3)
{
fprintf (stderr, "Usage: %s pointfile objfile [ballrange]\n", argv[0]);
exit (1);
}
if (argc == 4)
ballrange = (float) atof (argv[3]);
if (!(fp1 = fopen (argv[1], "r")))
{
fprintf (stderr, "Error opening Point file(%s).\n", argv[1]);
exit(2);
}
memset (gname, 0, sizeof (gname));
/* read cellsize */
memset (buffer, 0, sizeof (buffer));
fgets (buffer, 255, fp1);
csize = (float) atof (buffer);
points.clear();
normals.clear();
gVIndex.clear();
gOffset.clear();
gGeom.clear();
gVertex.clear();
gNormal.clear();
/* read points */
ch = fgetc (fp1);
while (!feof(fp1))
{
ungetc (ch, fp1);
memset (buffer, 0, sizeof (buffer));
fgets (buffer, 255, fp1);
if (buffer[0] == '#')
{
if (points.size() > 0)
{
/* set grouping info */
gOffset.push_back(gVIndex.size());
gGeom.push_back(gname);
#if DEBUG
fprintf (stdout, "Ball Pivoting %s...\n", gname);
#endif
/* perform ball pivoting */
ball_pivot (points, normals, ballrange, csize);
}
/* empty points & normals */
points.clear();
normals.clear();
/* read geometry name */
char *tok = strtok (buffer, " \n\r"); /* eat '#' */
tok = strtok (NULL, " \n\r");
sprintf (gname, "%s", tok);
}
else
{
float px, py, pz;
float dx, dy, dz;
sscanf (buffer, "%f %f %f %f %f %f",
&px, &py, &pz, &dx, &dy, &dz);
points.push_back (px);
points.push_back (py);
points.push_back (pz);
normals.push_back (dx);
normals.push_back (dy);
normals.push_back (dz);
}
ch = fgetc (fp1);
while (ch == '\n' || ch == '\r') ch = fgetc (fp1);
}
/* close point file */
fclose (fp1);
fp1 = NULL;
if (points.size() > 0)
{
/* set grouping info */
gOffset.push_back(gVIndex.size());
gGeom.push_back(gname);
#if DEBUG
fprintf (stdout, "Ball Pivoting %s...\n", gname);
#endif
/* perform ball pivoting */
ball_pivot (points, normals, ballrange, csize);
}
/* output obj file */
if (!(fp2 = fopen (argv[2], "w")))
{
fprintf (stderr, "Error opening OBJ file(%s).\n", argv[2]);
exit(3);
}
#if DEBUG
fprintf (stdout, "Outputting OBJ file.\n", gname);
#endif
/* output OBJ file */
output_obj (fp2, gVertex, gNormal, gVIndex, gGeom, gOffset);
/* close mesh file */
fclose (fp2);
fp2 = NULL;
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../Auxiliary
)
add_executable(dcmain main.cpp)
target_link_libraries(dcmain librt libbu libbn AUX MeshDecimation ${M_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
+341
View File
@@ -0,0 +1,341 @@
/* main.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/26/13
*
* Authors(s):
* DRH
*
* Description:
* This is the standalone mesh decimation application.
*
*/
/* Standard C/C++ libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
/* Custom libraries */
#include "gctcommon.h"
#include "MeshDecimation/meshdecimation.h"
#include "MeshDecimation/meshoptimizer.h"
#include "MeshDecimation/meshoptimization.h"
#if 0
#define DECIMATION_FLAGS MD_ATTRIB_FLAGS_NORMALIZE
#else
#define DECIMATION_FLAGS MD_ATTRIB_FLAGS_COMPUTE_NORMALS
#endif
#define OPTLEVEL 3 // 0=none, 1=low, 2=medium, 3=high
/* globals */
std::vector<float> gVertex;
std::vector<float> gNormal;
std::vector<float> gNewVertex;
std::vector<float> gNewNormal;
std::vector<long> gNewVIndex;
std::vector<std::string> gGeom;
std::vector<long> gOffset;
/*============ STATIC FUNCTIONS ============*/
//******************************************************************************
// NAME mesh_decimate
//
// INPUTS
// points - initial list of non-decimated vertices
// normals - initial list of non-decimated normals
// indexes - initial list of non-decimated indices
// featuresize - the smallest feature size to keep undecimated
// optlevel - optimization level
//
// DESCRIPTION
// Function that actually performs the mesh decimation routines.
//******************************************************************************
static void
mesh_decimate(std::vector<float> &points,
std::vector<float> &normals,
std::vector<int> &indexes,
float featuresize,
int optlevel)
{
int threadcount;
long pointcount = points.size() / 3;
long tricount = indexes.size() / 3;
float *vertex = &points[0];
float *normal = &normals[0];
int *indices = &indexes[0];
int *triindices, isize = (int) sizeof(int);
mdOperation mdop;
if (points.size() < 1) return;
threadcount = (int) ideal_thread_count ();
mdOperationInit(&mdop);
mdOperationData(&mdop, pointcount, vertex, sizeof(float), 3*sizeof(float),
tricount, indices, isize, 3*isize);
mdOperationStrength(&mdop, featuresize);
mdOperationAddAttrib(&mdop, normal, sizeof(float), 3, 3*sizeof(float), DECIMATION_FLAGS);
#if DEBUG_MESH_DECIMATION_VERBOSE
fprintf( stderr, "Mesh Decimation Start, %d vertices, %d triangles, %f featuresize\n",
(int)pointcount, (int)tricount, featuresize );
#endif
mdMeshDecimation(&mdop, threadcount,
MD_FLAGS_NORMAL_VERTEX_SPLITTING|MD_FLAGS_TRIANGLE_WINDING_CCW);
#if DEBUG_MESH_DECIMATION_VERBOSE
fprintf( stderr, "Mesh Decimation End, %d vertices, %d triangles, %.3f seconds\n",
(int)mdop.vertexcount, (int)mdop.tricount, (double)mdop.msecs / 1000.0 );
#endif
pointcount = mdop.vertexcount;
tricount = mdop.tricount;
mesh_optimization (pointcount, tricount, indices, isize, threadcount, optlevel);
/* indices need to be offset by the vertices already present */
long offset = gNewVertex.size()/3;
for( long i = pointcount, j = 0 ; i ; i--, j += 3 )
{
gNewVertex.push_back(vertex[j+0]);
gNewVertex.push_back(vertex[j+1]);
gNewVertex.push_back(vertex[j+2]);
gNewNormal.push_back(normal[j+0]);
gNewNormal.push_back(normal[j+1]);
gNewNormal.push_back(normal[j+2]);
}
triindices = indices;
for( long i = tricount ; i ; i--, triindices += 3 )
{
gNewVIndex.push_back( triindices[0] + offset );
gNewVIndex.push_back( triindices[1] + offset );
gNewVIndex.push_back( triindices[2] + offset );
}
}
/*============ MAIN FUNCTION ============*/
//******************************************************************************
// NAME main
//
// INPUTS
// argc - commandline argument count
// argv - array of commandline arguments
//
// DESCRIPTION
// Perform mesh decimation on an ".obj" file generated from the
// ballpivot (Ball Pivoting) or march (Marching Cubes) application.
//******************************************************************************
int
main (int argc, char **argv)
{
FILE *fp1 = NULL, *fp2 = NULL;
char buffer[255], ch, gname[100];
float fsize = 0.25;
std::vector<int> indexes;
if (argc < 3)
{
fprintf (stderr, "Usage: %s infile outfile [featuresize]\n", argv[0]);
exit (1);
}
if (argc == 4)
fsize = (float) atof (argv[3]);
if (!(fp1 = fopen (argv[1], "r")))
{
fprintf (stderr, "Error opening infile(%s).\n", argv[1]);
exit(2);
}
memset (gname, 0, sizeof (gname));
long low = 0;
long high = 0;
long offset = 0;
ch = fgetc (fp1);
while (!feof(fp1))
{
ungetc (ch, fp1);
memset (buffer, 0, sizeof (buffer));
fgets (buffer, 255, fp1);
int len = strlen(buffer);
if (buffer[len-1] == '\n') buffer[len-1] = '\0';
if (buffer[0] == 'g')
{
if (buffer[1] != '\0')
{
if (low > 0 && high > 0)
{
std::vector<float> points, normals;
/* set grouping info */
gOffset.push_back(gNewVIndex.size());
gGeom.push_back(gname);
#if DEBUG
fprintf (stdout, "Decimating %s...\n", gname);
#endif
/* stick current element's points into temp vectors */
for (long i = (low -1); i <= (high -1); i++)
{
long idx = i*3;
points.push_back (gVertex[idx+0]);
points.push_back (gVertex[idx+1]);
points.push_back (gVertex[idx+2]);
normals.push_back (gNormal[idx+0]);
normals.push_back (gNormal[idx+1]);
normals.push_back (gNormal[idx+2]);
}
/* do the mesh decimation */
mesh_decimate(points, normals, indexes, fsize, OPTLEVEL);
/* reset indices */
offset = high;
low = high = -1;
}
/* grab region name */
char *tok = strtok (buffer, " \n\r"); /* eat 'g' */
tok = strtok (NULL, " \n\r");
sprintf (gname, "%s", tok);
indexes.clear();
}
}
else if (buffer[0] == 'v')
{
if (buffer[1] == ' ') /* vertex */
{
float x, y, z;
sscanf (buffer+2, "%f %f %f", &x, &y, &z);
gVertex.push_back (x);
gVertex.push_back (y);
gVertex.push_back (z);
}
else if (buffer[1] == 'n') /* normal */
{
float x, y, z;
sscanf (buffer+3, "%f %f %f", &x, &y, &z);
gNormal.push_back (x);
gNormal.push_back (y);
gNormal.push_back (z);
}
}
else if (buffer[0] == 'f')
{
long idx[3];
char *tok = strtok(buffer, " \n");
tok = strtok(NULL, " \n"); sscanf(tok, "%ld", &idx[0]);
tok = strtok(NULL, " \n"); sscanf(tok, "%ld", &idx[1]);
tok = strtok(NULL, " \n"); sscanf(tok, "%ld", &idx[2]);
for (int i=0; i<3; i++)
{
int j = idx[i];
if (low < 1) low = j;
else if (j < low) low = j;
if (high < 1) high = j;
else if (j > high) high = j;
indexes.push_back (idx[i] - offset - 1);
}
}
ch = fgetc (fp1);
while (ch == '\n' || ch == '\r') ch = fgetc (fp1);
}
fclose (fp1);
fp1 = NULL;
if (low > 0 && high > 0)
{
std::vector<float> points, normals;
/* set grouping info */
gOffset.push_back(gNewVIndex.size());
gGeom.push_back(gname);
#if DEBUG
fprintf (stdout, "Decimating %s...\n", gname);
#endif
/* stick current element's points into temp vectors */
for (long i = (low -1); i <= (high -1); i++)
{
long idx = i*3;
points.push_back (gVertex[idx+0]);
points.push_back (gVertex[idx+1]);
points.push_back (gVertex[idx+2]);
normals.push_back (gNormal[idx+0]);
normals.push_back (gNormal[idx+1]);
normals.push_back (gNormal[idx+2]);
}
/* do the mesh decimation */
mesh_decimate(points, normals, indexes, fsize, OPTLEVEL);
}
/* output obj file */
if (!(fp2 = fopen (argv[2], "w")))
{
fprintf (stderr, "Error opening OBJ file(%s).\n", argv[2]);
exit(3);
}
#if DEBUG
fprintf (stdout, "Outputting OBJ file.\n", gname);
#endif
/* output OBJ file */
output_obj (fp2, gNewVertex, gNewNormal, gNewVIndex, gGeom, gOffset);
/* close mesh file */
fclose (fp2);
fp2 = NULL;
return 0;
}
+11
View File
@@ -0,0 +1,11 @@
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../../../../include
${CMAKE_CURRENT_SOURCE_DIR}/../../openNURBS
${CMAKE_CURRENT_SOURCE_DIR}/../../tcl/generic
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/../Auxiliary
)
add_executable(psmain main.cpp)
target_link_libraries(psmain librt libbu libbn AUX Sampler BrlcadGCT ${CMAKE_THREAD_LIBS_INIT})
+178
View File
@@ -0,0 +1,178 @@
/* main.cpp
*
* ----------------------------------------------------------------------
*
* Copyright (c) 2014 SURVICE Engineering. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. 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.
*
* 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 OWNER 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.
*
* ----------------------------------------------------------------------
*
* Revision Date:
* 08/22/13
*
* Authors(s):
* DRH
*
* Description:
* This is the standalone point sampling application.
*
*/
/* Standard C/C++ libraries */
#include <stdio.h>
#include <vector>
/* BRL-CAD libraries */
#include "bu.h"
/* Custom libraries */
#include "BRLCAD/BrlcadLoader.h"
#include "BRLCAD/DbGeometry.h"
#include "BRLCAD/DbTracer.h"
#include "Sampler/PointSampler.h"
#include <gctcommon.h> // this has to be behind the brlcad headers!!!
/*============ MAIN FUNCTION ============*/
//******************************************************************************
// NAME main
//
// INPUTS
// argc - commandline argument count
// argv - array of commandline arguments
//
// DESCRIPTION
// Perform point sampling on BRL-CAD geometry.
//******************************************************************************
int
main (int argc, char **argv)
{
int i, thread_count = (int) ideal_thread_count();
float csize = 0.0;
GLoaderInterface *loader = NULL;
std::vector<std::string> gnames;
if (argc < 3)
bu_exit(1, "Usage: %s model.g cellsize [item0 ...]\n", argv[0]);
/* get the cube size */
csize = (float) atof (argv[2]);
if (csize <= 0.0)
bu_exit(2, "Cube size (%s) needs to be a float greater than 0.0.", argv[2]);
if (argc > 3)
{
/* user specified piece(s) of geometry */
for (i=3; i<argc; i++)
gnames.push_back(argv[i]);
}
else
{
/* no geometry specified... convert them all */
/* create loader and start loading -- right now assume BRLCAD */
loader = new BrlcadLoader(argv[1]);
loader->startLoader();
if (loader->getStatus())
{
/* get region names */
gnames = loader->getGeomNames();
}
/* cleanup loader */
delete loader;
loader = NULL;
}
FILE *fp = NULL;
char fname[100];
memset (fname, 0, sizeof (char) * 100);
sprintf (fname, "%s.psamp", argv[1]);
if (!(fp = fopen (fname, "w")))
bu_exit(5, "Opening output PSAMP file failed.\n");
/* print cellsize */
fprintf (fp, "%.4f\n", csize);
/* create target & tracers -- right now assume BRLCAD */
GeomConversion::Interface::INativeGeometry *target = new GeomConversion::BRLCAD::DbGeometry(argv[1]);
std::vector<GeomConversion::Interface::IGeometryTracer *> tracers;
for (i=0; i<thread_count; i++)
tracers.push_back(new GeomConversion::BRLCAD::DbTracer(target, i));
for (i=0; i<gnames.size(); i++)
{
#ifdef DEBUG
fprintf (stdout, "Processing %s...\n", gnames.at(i).c_str());
#endif
/* create the point sampler, set details, and start running */
GeomConversion::Sampler::PointSampler *psamp = new GeomConversion::Sampler::PointSampler(target, tracers);
target->loadGeometry(gnames.at(i), thread_count);
psamp->setSpacing(csize);
psamp->prepSample();
psamp->runSample();
target->cleanupGeometry();
/* Get points and normals for this geometry */
std::vector<float> points = psamp->getPoints();
std::vector<float> normals = psamp->getNormals();
#if SURF_SOL_CAPTURE
std::vector<std::string> sols = psamp->getSolidNumbers();
std::vector<int> surfs = psamp->getSurfNumbers();
#endif
/* cleanup sampler */
delete psamp;
psamp = NULL;
/* output points & normals */
fprintf (fp, "# %s\n", gnames.at(i).c_str());
for (int j=0; j<points.size(); j+=3)
{
fprintf (fp, "%.4f %.4f %.4f %.4f %.4f %.4f",
points[j], points[j+1], points[j+2],
normals[j], normals[j+1], normals[j+2]);
#if SURF_SOL_CAPTURE
fprintf (fp, " %s %d", sols[j/3].c_str(), surfs[j/3]);
#endif
fprintf (fp, "\n");
}
}
fclose (fp);
/* cleanup target & tracers */
while (tracers.size() > 0)
{
GeomConversion::Interface::IGeometryTracer *ti = tracers.back();
tracers.pop_back();
delete ti;
}
delete target;
target = NULL;
return 0;
}
View File