mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-28 15:55:39 +00:00
* Adjustment: Update Bullet version to 3.24.
This commit is contained in:
parent
35de012ee7
commit
4a3f31df2a
6148 changed files with 2112532 additions and 56873 deletions
271
Engine/lib/bullet/examples/Utils/ChromeTraceUtil.cpp
Normal file
271
Engine/lib/bullet/examples/Utils/ChromeTraceUtil.cpp
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
|
||||
#include "ChromeTraceUtil.h"
|
||||
#include "b3Clock.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#include <stdio.h>
|
||||
#include <climits>
|
||||
|
||||
struct btTiming
|
||||
{
|
||||
const char* m_name;
|
||||
int m_threadId;
|
||||
unsigned long long int m_usStartTime;
|
||||
unsigned long long int m_usEndTime;
|
||||
};
|
||||
|
||||
FILE* gTimingFile = 0;
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif //__STDC_FORMAT_MACROS
|
||||
|
||||
//see http://stackoverflow.com/questions/18107426/printf-format-for-unsigned-int64-on-windows
|
||||
#ifndef _WIN32
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#define BT_TIMING_CAPACITY 16 * 65536
|
||||
static bool m_firstTiming = true;
|
||||
|
||||
struct btTimings
|
||||
{
|
||||
btTimings()
|
||||
: m_numTimings(0),
|
||||
m_activeBuffer(0)
|
||||
{
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
for (int i = 0; i < m_numTimings; i++)
|
||||
{
|
||||
const char* name = m_timings[m_activeBuffer][i].m_name;
|
||||
int threadId = m_timings[m_activeBuffer][i].m_threadId;
|
||||
unsigned long long int startTime = m_timings[m_activeBuffer][i].m_usStartTime;
|
||||
unsigned long long int endTime = m_timings[m_activeBuffer][i].m_usEndTime;
|
||||
|
||||
if (!m_firstTiming)
|
||||
{
|
||||
fprintf(gTimingFile, ",\n");
|
||||
}
|
||||
|
||||
m_firstTiming = false;
|
||||
|
||||
if (startTime > endTime)
|
||||
{
|
||||
endTime = startTime;
|
||||
}
|
||||
|
||||
unsigned long long int startTimeDiv1000 = startTime / 1000;
|
||||
unsigned long long int endTimeDiv1000 = endTime / 1000;
|
||||
|
||||
#if 0
|
||||
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".123 ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
|
||||
threadId, startTimeDiv1000, name);
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%" PRIu64 ".234 ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
|
||||
threadId, endTimeDiv1000, name);
|
||||
|
||||
#else
|
||||
|
||||
|
||||
unsigned int startTimeRem1000 = startTime % 1000;
|
||||
unsigned int endTimeRem1000 = endTime % 1000;
|
||||
|
||||
char startTimeRem1000Str[16];
|
||||
char endTimeRem1000Str[16];
|
||||
|
||||
if (startTimeRem1000 < 10)
|
||||
{
|
||||
sprintf(startTimeRem1000Str, "00%d", startTimeRem1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startTimeRem1000 < 100)
|
||||
{
|
||||
sprintf(startTimeRem1000Str, "0%d", startTimeRem1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(startTimeRem1000Str, "%d", startTimeRem1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (endTimeRem1000 < 10)
|
||||
{
|
||||
sprintf(endTimeRem1000Str, "00%d", endTimeRem1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (endTimeRem1000 < 100)
|
||||
{
|
||||
sprintf(endTimeRem1000Str, "0%d", endTimeRem1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(endTimeRem1000Str, "%d", endTimeRem1000);
|
||||
}
|
||||
}
|
||||
|
||||
char newname[1024];
|
||||
static int counter2 = 0;
|
||||
sprintf(newname, "%s%d", name, counter2++);
|
||||
|
||||
#ifdef _WIN32
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%I64d.%s ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
|
||||
threadId, startTimeDiv1000, startTimeRem1000Str, newname);
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%I64d.%s ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
|
||||
threadId, endTimeDiv1000, endTimeRem1000Str, newname);
|
||||
#else
|
||||
// Note: on 64b build, PRIu64 resolves in 'lu' whereas timings ('ts') have to be printed as 'llu'.
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%llu.%s ,\"ph\":\"B\",\"name\":\"%s\",\"args\":{}},\n",
|
||||
threadId, startTimeDiv1000, startTimeRem1000Str, newname);
|
||||
fprintf(gTimingFile, "{\"cat\":\"timing\",\"pid\":1,\"tid\":%d,\"ts\":%llu.%s ,\"ph\":\"E\",\"name\":\"%s\",\"args\":{}}",
|
||||
threadId, endTimeDiv1000, endTimeRem1000Str, newname);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
m_numTimings = 0;
|
||||
}
|
||||
|
||||
void addTiming(const char* name, int threadId, unsigned long long int startTime, unsigned long long int endTime)
|
||||
{
|
||||
if (m_numTimings >= BT_TIMING_CAPACITY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_timings[0].size() == 0)
|
||||
{
|
||||
m_timings[0].resize(BT_TIMING_CAPACITY);
|
||||
}
|
||||
|
||||
int slot = m_numTimings++;
|
||||
|
||||
m_timings[m_activeBuffer][slot].m_name = name;
|
||||
m_timings[m_activeBuffer][slot].m_threadId = threadId;
|
||||
m_timings[m_activeBuffer][slot].m_usStartTime = startTime;
|
||||
m_timings[m_activeBuffer][slot].m_usEndTime = endTime;
|
||||
}
|
||||
|
||||
int m_numTimings;
|
||||
int m_activeBuffer;
|
||||
btAlignedObjectArray<btTiming> m_timings[1];
|
||||
};
|
||||
//#ifndef BT_NO_PROFILE
|
||||
btTimings gTimings[BT_QUICKPROF_MAX_THREAD_COUNT];
|
||||
#define MAX_NESTING 1024
|
||||
int gStackDepths[BT_QUICKPROF_MAX_THREAD_COUNT] = {0};
|
||||
const char* gFuncNames[BT_QUICKPROF_MAX_THREAD_COUNT][MAX_NESTING];
|
||||
unsigned long long int gStartTimes[BT_QUICKPROF_MAX_THREAD_COUNT][MAX_NESTING];
|
||||
//#endif
|
||||
|
||||
btClock clk;
|
||||
|
||||
bool gProfileDisabled = true;
|
||||
|
||||
void MyDummyEnterProfileZoneFunc(const char* msg)
|
||||
{
|
||||
}
|
||||
|
||||
void MyDummyLeaveProfileZoneFunc()
|
||||
{
|
||||
}
|
||||
|
||||
void MyEnterProfileZoneFunc(const char* msg)
|
||||
{
|
||||
if (gProfileDisabled)
|
||||
return;
|
||||
|
||||
int threadId = btQuickprofGetCurrentThreadIndex2();
|
||||
if (threadId < 0 || threadId >= BT_QUICKPROF_MAX_THREAD_COUNT)
|
||||
return;
|
||||
|
||||
if (gStackDepths[threadId] >= MAX_NESTING)
|
||||
{
|
||||
btAssert(0);
|
||||
return;
|
||||
}
|
||||
gFuncNames[threadId][gStackDepths[threadId]] = msg;
|
||||
gStartTimes[threadId][gStackDepths[threadId]] = clk.getTimeNanoseconds();
|
||||
if (gStartTimes[threadId][gStackDepths[threadId]] <= gStartTimes[threadId][gStackDepths[threadId] - 1])
|
||||
{
|
||||
gStartTimes[threadId][gStackDepths[threadId]] = 1 + gStartTimes[threadId][gStackDepths[threadId] - 1];
|
||||
}
|
||||
gStackDepths[threadId]++;
|
||||
|
||||
}
|
||||
void MyLeaveProfileZoneFunc()
|
||||
{
|
||||
if (gProfileDisabled)
|
||||
return;
|
||||
|
||||
int threadId = btQuickprofGetCurrentThreadIndex2();
|
||||
if (threadId < 0 || threadId >= BT_QUICKPROF_MAX_THREAD_COUNT)
|
||||
return;
|
||||
|
||||
if (gStackDepths[threadId] <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gStackDepths[threadId]--;
|
||||
|
||||
const char* name = gFuncNames[threadId][gStackDepths[threadId]];
|
||||
unsigned long long int startTime = gStartTimes[threadId][gStackDepths[threadId]];
|
||||
|
||||
unsigned long long int endTime = clk.getTimeNanoseconds();
|
||||
gTimings[threadId].addTiming(name, threadId, startTime, endTime);
|
||||
|
||||
}
|
||||
|
||||
void b3ChromeUtilsStartTimings()
|
||||
{
|
||||
m_firstTiming = true;
|
||||
gProfileDisabled = false; //true;
|
||||
b3SetCustomEnterProfileZoneFunc(MyEnterProfileZoneFunc);
|
||||
b3SetCustomLeaveProfileZoneFunc(MyLeaveProfileZoneFunc);
|
||||
|
||||
//also for Bullet 2.x API
|
||||
btSetCustomEnterProfileZoneFunc(MyEnterProfileZoneFunc);
|
||||
btSetCustomLeaveProfileZoneFunc(MyLeaveProfileZoneFunc);
|
||||
}
|
||||
|
||||
void b3ChromeUtilsStopTimingsAndWriteJsonFile(const char* fileNamePrefix)
|
||||
{
|
||||
b3SetCustomEnterProfileZoneFunc(MyDummyEnterProfileZoneFunc);
|
||||
b3SetCustomLeaveProfileZoneFunc(MyDummyLeaveProfileZoneFunc);
|
||||
//also for Bullet 2.x API
|
||||
btSetCustomEnterProfileZoneFunc(MyDummyEnterProfileZoneFunc);
|
||||
btSetCustomLeaveProfileZoneFunc(MyDummyLeaveProfileZoneFunc);
|
||||
char fileName[1024];
|
||||
static int fileCounter = 0;
|
||||
sprintf(fileName, "%s_%d.json", fileNamePrefix, fileCounter++);
|
||||
gTimingFile = fopen(fileName, "w");
|
||||
if (gTimingFile)
|
||||
{
|
||||
fprintf(gTimingFile, "{\"traceEvents\":[\n");
|
||||
//dump the content to file
|
||||
for (int i = 0; i < BT_QUICKPROF_MAX_THREAD_COUNT; i++)
|
||||
{
|
||||
if (gTimings[i].m_numTimings)
|
||||
{
|
||||
printf("Writing %d timings for thread %d\n", gTimings[i].m_numTimings, i);
|
||||
gTimings[i].flush();
|
||||
}
|
||||
}
|
||||
fprintf(gTimingFile, "\n],\n\"displayTimeUnit\": \"ns\"}");
|
||||
fclose(gTimingFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
b3Printf("Error opening file");
|
||||
b3Printf(fileName);
|
||||
}
|
||||
gTimingFile = 0;
|
||||
}
|
||||
|
||||
void b3ChromeUtilsEnableProfiling()
|
||||
{
|
||||
gProfileDisabled = false;
|
||||
}
|
||||
9
Engine/lib/bullet/examples/Utils/ChromeTraceUtil.h
Normal file
9
Engine/lib/bullet/examples/Utils/ChromeTraceUtil.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#ifndef B3_CHROME_TRACE_UTIL_H
|
||||
#define B3_CHROME_TRACE_UTIL_H
|
||||
|
||||
void b3ChromeUtilsStartTimings();
|
||||
void b3ChromeUtilsStopTimingsAndWriteJsonFile(const char* fileNamePrefix);
|
||||
void b3ChromeUtilsEnableProfiling();
|
||||
|
||||
#endif //B3_CHROME_TRACE_UTIL_H
|
||||
263
Engine/lib/bullet/examples/Utils/RobotLoggingUtil.cpp
Normal file
263
Engine/lib/bullet/examples/Utils/RobotLoggingUtil.cpp
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
#include "RobotLoggingUtil.h"
|
||||
#include <stdio.h>
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
|
||||
#include "../Importers/ImportURDFDemo/urdfStringSplit.h"
|
||||
|
||||
static bool readLine(FILE* file, btAlignedObjectArray<char>& line)
|
||||
{
|
||||
int c = 0;
|
||||
for (c = fgetc(file); (c != EOF && c != '\n'); c = fgetc(file))
|
||||
{
|
||||
line.push_back(c);
|
||||
}
|
||||
line.push_back(0);
|
||||
return (c == EOF);
|
||||
}
|
||||
|
||||
int readMinitaurLogFile(const char* fileName, btAlignedObjectArray<std::string>& structNames, std::string& structTypes, btAlignedObjectArray<MinitaurLogRecord>& logRecords, bool verbose)
|
||||
{
|
||||
int retVal = 0;
|
||||
|
||||
FILE* f = fopen(fileName, "rb");
|
||||
if (f)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("Opened file %s\n", fileName);
|
||||
}
|
||||
btAlignedObjectArray<char> line0Buf;
|
||||
bool eof = readLine(f, line0Buf);
|
||||
btAlignedObjectArray<char> line1Buf;
|
||||
eof |= readLine(f, line1Buf);
|
||||
std::string line0 = &line0Buf[0];
|
||||
structTypes = &line1Buf[0];
|
||||
|
||||
btAlignedObjectArray<std::string> separators;
|
||||
separators.push_back(",");
|
||||
|
||||
urdfStringSplit(structNames, line0, separators);
|
||||
if (verbose)
|
||||
{
|
||||
printf("Num Fields = %d\n", structNames.size());
|
||||
}
|
||||
btAssert(structTypes.size() == structNames.size());
|
||||
if (structTypes.size() != structNames.size())
|
||||
{
|
||||
retVal = eCorruptHeader;
|
||||
}
|
||||
int numStructsRead = 0;
|
||||
|
||||
if (structTypes.size() == structNames.size())
|
||||
{
|
||||
while (!eof)
|
||||
{
|
||||
unsigned char blaat[1024];
|
||||
size_t s = fread(blaat, 2, 1, f);
|
||||
if (s != 1)
|
||||
{
|
||||
eof = true;
|
||||
retVal = eInvalidAABBAlignCheck;
|
||||
break;
|
||||
}
|
||||
if ((blaat[0] != 0xaa) || (blaat[1] != 0xbb))
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("Expected 0xaa0xbb, terminating\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
printf("Reading structure %d\n", numStructsRead);
|
||||
}
|
||||
MinitaurLogRecord record;
|
||||
|
||||
for (int i = 0; i < structNames.size(); i++)
|
||||
{
|
||||
switch (structTypes[i])
|
||||
{
|
||||
case 'I':
|
||||
{
|
||||
size_t s = fread(blaat, sizeof(int), 1, f);
|
||||
if (s != 1)
|
||||
{
|
||||
eof = true;
|
||||
retVal = eCorruptValue;
|
||||
break;
|
||||
}
|
||||
int v = (int)*(unsigned int*)blaat;
|
||||
if (s == 1)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("%s = %d\n", structNames[i].c_str(), v);
|
||||
}
|
||||
record.m_values.push_back(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'i':
|
||||
{
|
||||
size_t s = fread(blaat, sizeof(int), 1, f);
|
||||
if (s != 1)
|
||||
{
|
||||
eof = true;
|
||||
retVal = eCorruptValue;
|
||||
break;
|
||||
}
|
||||
int v = *(int*)blaat;
|
||||
if (s == 1)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("%s = %d\n", structNames[i].c_str(), v);
|
||||
}
|
||||
record.m_values.push_back(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
float v;
|
||||
size_t s = fread(&v, sizeof(float), 1, f);
|
||||
if (s != 1)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (s == 1)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("%s = %f\n", structNames[i].c_str(), v);
|
||||
}
|
||||
record.m_values.push_back(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'B':
|
||||
{
|
||||
char v;
|
||||
size_t s = fread(&v, sizeof(char), 1, f);
|
||||
if (s != 1)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
if (s == 1)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("%s = %d\n", structNames[i].c_str(), v);
|
||||
}
|
||||
record.m_values.push_back(v);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("Unknown type\n");
|
||||
}
|
||||
retVal = eUnknownType;
|
||||
btAssert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
logRecords.push_back(record);
|
||||
numStructsRead++;
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
printf("numStructsRead = %d\n", numStructsRead);
|
||||
}
|
||||
if (retVal == 0)
|
||||
{
|
||||
retVal = numStructsRead;
|
||||
}
|
||||
}
|
||||
|
||||
//read header and
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
printf("Could not open file %s", fileName);
|
||||
}
|
||||
retVal = eMinitaurFileNotFound;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
FILE* createMinitaurLogFile(const char* fileName, btAlignedObjectArray<std::string>& structNames, std::string& structTypes)
|
||||
{
|
||||
FILE* f = fopen(fileName, "wb");
|
||||
if (f)
|
||||
{
|
||||
for (int i = 0; i < structNames.size(); i++)
|
||||
{
|
||||
int len = strlen(structNames[i].c_str());
|
||||
fwrite(structNames[i].c_str(), len, 1, f);
|
||||
if (i < structNames.size() - 1)
|
||||
{
|
||||
fwrite(",", 1, 1, f);
|
||||
}
|
||||
}
|
||||
int sz = sizeof("\n");
|
||||
fwrite("\n", sz - 1, 1, f);
|
||||
fwrite(structTypes.c_str(), strlen(structTypes.c_str()), 1, f);
|
||||
fwrite("\n", sz - 1, 1, f);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void appendMinitaurLogData(FILE* f, std::string& structTypes, const MinitaurLogRecord& logData)
|
||||
{
|
||||
if (f)
|
||||
{
|
||||
unsigned char buf[2] = {0xaa, 0xbb};
|
||||
fwrite(buf, 2, 1, f);
|
||||
if (structTypes.length() == logData.m_values.size())
|
||||
{
|
||||
for (int i = 0; i < logData.m_values.size(); i++)
|
||||
{
|
||||
switch (structTypes[i])
|
||||
{
|
||||
case 'i':
|
||||
case 'I':
|
||||
{
|
||||
fwrite(&logData.m_values[i].m_intVal, sizeof(int), 1, f);
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
fwrite(&logData.m_values[i].m_floatVal, sizeof(float), 1, f);
|
||||
break;
|
||||
}
|
||||
case 'B':
|
||||
{
|
||||
fwrite(&logData.m_values[i].m_charVal, sizeof(char), 1, f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void closeMinitaurLogFile(FILE* f)
|
||||
{
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
53
Engine/lib/bullet/examples/Utils/RobotLoggingUtil.h
Normal file
53
Engine/lib/bullet/examples/Utils/RobotLoggingUtil.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef ROBOT_LOGGING_UTIL_H
|
||||
#define ROBOT_LOGGING_UTIL_H
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include <string>
|
||||
|
||||
struct MinitaurLogValue
|
||||
{
|
||||
MinitaurLogValue()
|
||||
: m_intVal(0xcdcdcdcd)
|
||||
{
|
||||
}
|
||||
MinitaurLogValue(int iv)
|
||||
: m_intVal(iv)
|
||||
{
|
||||
}
|
||||
MinitaurLogValue(float fv)
|
||||
: m_floatVal(fv)
|
||||
{
|
||||
}
|
||||
MinitaurLogValue(char fv)
|
||||
: m_charVal(fv)
|
||||
{
|
||||
}
|
||||
|
||||
union {
|
||||
char m_charVal;
|
||||
int m_intVal;
|
||||
float m_floatVal;
|
||||
};
|
||||
};
|
||||
|
||||
struct MinitaurLogRecord
|
||||
{
|
||||
btAlignedObjectArray<MinitaurLogValue> m_values;
|
||||
};
|
||||
|
||||
enum MINITAUR_LOG_ERROR
|
||||
{
|
||||
eMinitaurFileNotFound = -1,
|
||||
eCorruptHeader = -2,
|
||||
eUnknownType = -3,
|
||||
eCorruptValue = -4,
|
||||
eInvalidAABBAlignCheck = -5,
|
||||
};
|
||||
|
||||
int readMinitaurLogFile(const char* fileName, btAlignedObjectArray<std::string>& structNames, std::string& structTypes, btAlignedObjectArray<MinitaurLogRecord>& logRecords, bool verbose);
|
||||
|
||||
FILE* createMinitaurLogFile(const char* fileName, btAlignedObjectArray<std::string>& structNames, std::string& structTypes);
|
||||
void appendMinitaurLogData(FILE* f, std::string& structTypes, const MinitaurLogRecord& logData);
|
||||
void closeMinitaurLogFile(FILE* f);
|
||||
|
||||
#endif //ROBOT_LOGGING_UTIL_H
|
||||
199
Engine/lib/bullet/examples/Utils/b3BulletDefaultFileIO.h
Normal file
199
Engine/lib/bullet/examples/Utils/b3BulletDefaultFileIO.h
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
|
||||
#ifndef B3_BULLET_DEFAULT_FILE_IO_H
|
||||
#define B3_BULLET_DEFAULT_FILE_IO_H
|
||||
|
||||
#include "../CommonInterfaces/CommonFileIOInterface.h"
|
||||
#include "b3ResourcePath.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define B3_FILEIO_MAX_FILES 1024
|
||||
|
||||
struct b3BulletDefaultFileIO : public CommonFileIOInterface
|
||||
{
|
||||
static bool FileIOPluginFindFile(void* userPtr, const char* orgFileName, char* relativeFileName, int maxRelativeFileNameMaxLen)
|
||||
{
|
||||
b3BulletDefaultFileIO* fileIo = (b3BulletDefaultFileIO*) userPtr;
|
||||
return fileIo->findFile(orgFileName, relativeFileName, maxRelativeFileNameMaxLen);
|
||||
}
|
||||
|
||||
char m_prefix[1024];
|
||||
FILE* m_fileHandles[B3_FILEIO_MAX_FILES];
|
||||
int m_numFileHandles;
|
||||
|
||||
b3BulletDefaultFileIO(int fileIOType=0, const char* pathPrefix=0)
|
||||
:CommonFileIOInterface(fileIOType, m_prefix),
|
||||
m_numFileHandles(0)
|
||||
{
|
||||
m_prefix[0] = 0;
|
||||
if (pathPrefix)
|
||||
{
|
||||
sprintf(m_prefix,"%s", pathPrefix);
|
||||
}
|
||||
for (int i=0;i<B3_FILEIO_MAX_FILES;i++)
|
||||
{
|
||||
m_fileHandles[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~b3BulletDefaultFileIO()
|
||||
{
|
||||
}
|
||||
virtual int fileOpen(const char* fileName, const char* mode)
|
||||
{
|
||||
//search a free slot
|
||||
int slot = -1;
|
||||
for (int i=0;i<B3_FILEIO_MAX_FILES;i++)
|
||||
{
|
||||
if (m_fileHandles[i]==0)
|
||||
{
|
||||
slot=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (slot>=0)
|
||||
{
|
||||
FILE*f = ::fopen(fileName, mode);
|
||||
if (f)
|
||||
{
|
||||
m_fileHandles[slot]=f;
|
||||
} else
|
||||
{
|
||||
slot=-1;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
virtual int fileRead(int fileHandle, char* destBuffer, int numBytes)
|
||||
{
|
||||
if (fileHandle>=0 && fileHandle < B3_FILEIO_MAX_FILES)
|
||||
{
|
||||
FILE* f = m_fileHandles[fileHandle];
|
||||
if (f)
|
||||
{
|
||||
int readBytes = ::fread(destBuffer, 1, numBytes, f);
|
||||
return readBytes;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
virtual int fileWrite(int fileHandle,const char* sourceBuffer, int numBytes)
|
||||
{
|
||||
if (fileHandle>=0 && fileHandle < B3_FILEIO_MAX_FILES)
|
||||
{
|
||||
FILE* f = m_fileHandles[fileHandle];
|
||||
if (f)
|
||||
{
|
||||
return ::fwrite(sourceBuffer, 1, numBytes,m_fileHandles[fileHandle]);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
virtual void fileClose(int fileHandle)
|
||||
{
|
||||
if (fileHandle>=0 && fileHandle < B3_FILEIO_MAX_FILES)
|
||||
{
|
||||
FILE* f = m_fileHandles[fileHandle];
|
||||
if (f)
|
||||
{
|
||||
::fclose(f);
|
||||
m_fileHandles[fileHandle]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool findResourcePath(const char* fileName, char* relativeFileName, int relativeFileNameSizeInBytes)
|
||||
{
|
||||
return b3ResourcePath::findResourcePath(fileName, relativeFileName, relativeFileNameSizeInBytes, b3BulletDefaultFileIO::FileIOPluginFindFile, this)>0;
|
||||
}
|
||||
|
||||
|
||||
virtual bool findFile(const char* orgFileName, char* relativeFileName, int maxRelativeFileNameMaxLen)
|
||||
{
|
||||
FILE* f = 0;
|
||||
f = fopen(orgFileName, "rb");
|
||||
if (f)
|
||||
{
|
||||
//printf("original file found: [%s]\n", orgFileName);
|
||||
sprintf(relativeFileName, "%s", orgFileName);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
//printf("Trying various directories, relative to current working directory\n");
|
||||
const char* prefix[] = {m_prefix, "./", "./data/", "../data/", "../../data/", "../../../data/", "../../../../data/"};
|
||||
int numPrefixes = sizeof(prefix) / sizeof(const char*);
|
||||
|
||||
f = 0;
|
||||
bool fileFound = false;
|
||||
|
||||
for (int i = 0; !f && i < numPrefixes; i++)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(relativeFileName, maxRelativeFileNameMaxLen, "%s%s", prefix[i], orgFileName);
|
||||
#else
|
||||
sprintf(relativeFileName, "%s%s", prefix[i], orgFileName);
|
||||
#endif
|
||||
f = fopen(relativeFileName, "rb");
|
||||
if (f)
|
||||
{
|
||||
fileFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return fileFound;
|
||||
}
|
||||
virtual char* readLine(int fileHandle, char* destBuffer, int numBytes)
|
||||
{
|
||||
if (fileHandle>=0 && fileHandle < B3_FILEIO_MAX_FILES)
|
||||
{
|
||||
FILE* f = m_fileHandles[fileHandle];
|
||||
if (f)
|
||||
{
|
||||
memset(destBuffer, 0, numBytes);
|
||||
char* txt = ::fgets(destBuffer, numBytes, m_fileHandles[fileHandle]);
|
||||
for (int i=0;i<numBytes;i++)
|
||||
{
|
||||
if (destBuffer[i]=='\r'||destBuffer[i]=='\n' || destBuffer[i]==0)
|
||||
{
|
||||
destBuffer[i] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return txt;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual int getFileSize(int fileHandle)
|
||||
{
|
||||
int size = 0;
|
||||
if (fileHandle>=0 && fileHandle < B3_FILEIO_MAX_FILES)
|
||||
{
|
||||
FILE* f = m_fileHandles[fileHandle];
|
||||
if (f)
|
||||
{
|
||||
|
||||
if (fseek(f, 0, SEEK_END) || (size = ftell(f)) == EOF || fseek(f, 0, SEEK_SET))
|
||||
{
|
||||
printf("Error: Cannot access file to determine size\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
virtual void enableFileCaching(bool enable)
|
||||
{
|
||||
(void) enable;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //B3_BULLET_DEFAULT_FILE_IO_H
|
||||
215
Engine/lib/bullet/examples/Utils/b3Clock.cpp
Normal file
215
Engine/lib/bullet/examples/Utils/b3Clock.cpp
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
#include "b3Clock.h"
|
||||
|
||||
template <class T>
|
||||
const T& b3ClockMin(const T& a, const T& b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
#include <sys/sys_time.h>
|
||||
#include <sys/time_util.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined(SUNOS) || defined(__SUNOS__)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
|
||||
#define B3_USE_WINDOWS_TIMERS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOWINRES
|
||||
#define NOMCX
|
||||
#define NOIME
|
||||
|
||||
#ifdef _XBOX
|
||||
#include <Xtl.h>
|
||||
#else //_XBOX
|
||||
#include <windows.h>
|
||||
#endif //_XBOX
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#else //_WIN32
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif //_WIN32
|
||||
|
||||
struct b3ClockData
|
||||
{
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
LARGE_INTEGER mClockFrequency;
|
||||
LARGE_INTEGER mStartTime;
|
||||
#else
|
||||
#ifdef __CELLOS_LV2__
|
||||
uint64_t mStartTime;
|
||||
#else
|
||||
struct timeval mStartTime;
|
||||
#endif
|
||||
#endif //__CELLOS_LV2__
|
||||
};
|
||||
|
||||
///The b3Clock is a portable basic clock that measures accurate time in seconds, use for profiling.
|
||||
b3Clock::b3Clock()
|
||||
{
|
||||
m_data = new b3ClockData;
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
QueryPerformanceFrequency(&m_data->mClockFrequency);
|
||||
#endif
|
||||
reset();
|
||||
}
|
||||
|
||||
b3Clock::~b3Clock()
|
||||
{
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
b3Clock::b3Clock(const b3Clock& other)
|
||||
{
|
||||
m_data = new b3ClockData;
|
||||
*m_data = *other.m_data;
|
||||
}
|
||||
|
||||
b3Clock& b3Clock::operator=(const b3Clock& other)
|
||||
{
|
||||
*m_data = *other.m_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Resets the initial reference time.
|
||||
void b3Clock::reset(bool zeroReference)
|
||||
{
|
||||
if (zeroReference)
|
||||
{
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
m_data->mStartTime.QuadPart = 0;
|
||||
#else
|
||||
#ifdef __CELLOS_LV2__
|
||||
m_data->mStartTime = 0;
|
||||
#else
|
||||
m_data->mStartTime = (struct timeval){0};
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
QueryPerformanceCounter(&m_data->mStartTime);
|
||||
#else
|
||||
#ifdef __CELLOS_LV2__
|
||||
|
||||
typedef uint64_t ClockSize;
|
||||
ClockSize newTime;
|
||||
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
|
||||
SYS_TIMEBASE_GET(newTime);
|
||||
m_data->mStartTime = newTime;
|
||||
#else
|
||||
gettimeofday(&m_data->mStartTime, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the time in ms since the last call to reset or since
|
||||
/// the b3Clock was created.
|
||||
unsigned long int b3Clock::getTimeMilliseconds()
|
||||
{
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
LARGE_INTEGER currentTime;
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
LONGLONG elapsedTime = currentTime.QuadPart -
|
||||
m_data->mStartTime.QuadPart;
|
||||
// Compute the number of millisecond ticks elapsed.
|
||||
unsigned long msecTicks = (unsigned long)(1000 * elapsedTime /
|
||||
m_data->mClockFrequency.QuadPart);
|
||||
|
||||
return msecTicks;
|
||||
#else
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
uint64_t freq = sys_time_get_timebase_frequency();
|
||||
double dFreq = ((double)freq) / 1000.0;
|
||||
typedef uint64_t ClockSize;
|
||||
ClockSize newTime;
|
||||
SYS_TIMEBASE_GET(newTime);
|
||||
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
|
||||
|
||||
return (unsigned long int)((double(newTime - m_data->mStartTime)) / dFreq);
|
||||
#else
|
||||
|
||||
struct timeval currentTime;
|
||||
gettimeofday(¤tTime, 0);
|
||||
return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000 +
|
||||
(currentTime.tv_usec - m_data->mStartTime.tv_usec) / 1000;
|
||||
#endif //__CELLOS_LV2__
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns the time in us since the last call to reset or since
|
||||
/// the Clock was created.
|
||||
unsigned long long int b3Clock::getTimeMicroseconds()
|
||||
{
|
||||
#ifdef B3_USE_WINDOWS_TIMERS
|
||||
//see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
|
||||
LARGE_INTEGER currentTime, elapsedTime;
|
||||
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
elapsedTime.QuadPart = currentTime.QuadPart -
|
||||
m_data->mStartTime.QuadPart;
|
||||
elapsedTime.QuadPart *= 1000000;
|
||||
elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart;
|
||||
|
||||
return (unsigned long long)elapsedTime.QuadPart;
|
||||
#else
|
||||
|
||||
#ifdef __CELLOS_LV2__
|
||||
uint64_t freq = sys_time_get_timebase_frequency();
|
||||
double dFreq = ((double)freq) / 1000000.0;
|
||||
typedef uint64_t ClockSize;
|
||||
ClockSize newTime;
|
||||
//__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory");
|
||||
SYS_TIMEBASE_GET(newTime);
|
||||
|
||||
return (unsigned long int)((double(newTime - m_data->mStartTime)) / dFreq);
|
||||
#else
|
||||
|
||||
struct timeval currentTime;
|
||||
gettimeofday(¤tTime, 0);
|
||||
return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1000000 +
|
||||
(currentTime.tv_usec - m_data->mStartTime.tv_usec);
|
||||
#endif //__CELLOS_LV2__
|
||||
#endif
|
||||
}
|
||||
|
||||
double b3Clock::getTimeInSeconds()
|
||||
{
|
||||
return double(getTimeMicroseconds() / 1.e6);
|
||||
}
|
||||
|
||||
void b3Clock::usleep(int microSeconds)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (microSeconds == 0)
|
||||
{
|
||||
Sleep(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int millis = microSeconds / 1000;
|
||||
if (millis < 1)
|
||||
millis = 1;
|
||||
Sleep(millis);
|
||||
}
|
||||
#else
|
||||
if (microSeconds > 0)
|
||||
{
|
||||
::usleep(microSeconds);
|
||||
//struct timeval tv;
|
||||
//tv.tv_sec = microSeconds/1000000L;
|
||||
//tv.tv_usec = microSeconds%1000000L;
|
||||
//return select(0, 0, 0, 0, &tv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
38
Engine/lib/bullet/examples/Utils/b3Clock.h
Normal file
38
Engine/lib/bullet/examples/Utils/b3Clock.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef B3_CLOCK_H
|
||||
#define B3_CLOCK_H
|
||||
|
||||
///The b3Clock is a portable basic clock that measures accurate time in seconds, use for profiling.
|
||||
class b3Clock
|
||||
{
|
||||
public:
|
||||
b3Clock();
|
||||
|
||||
b3Clock(const b3Clock& other);
|
||||
b3Clock& operator=(const b3Clock& other);
|
||||
|
||||
~b3Clock();
|
||||
|
||||
/// Resets the initial reference time. If zeroReference is true, will set reference to absolute 0.
|
||||
void reset(bool zeroReference = false);
|
||||
|
||||
/// Returns the time in ms since the last call to reset or since
|
||||
/// the b3Clock was created.
|
||||
unsigned long int getTimeMilliseconds();
|
||||
|
||||
/// Returns the time in us since the last call to reset or since
|
||||
/// the Clock was created.
|
||||
unsigned long long int getTimeMicroseconds();
|
||||
|
||||
/// Returns the time in seconds since the last call to reset or since
|
||||
/// the Clock was created.
|
||||
double getTimeInSeconds();
|
||||
|
||||
///Sleep for 'microSeconds', to yield to other threads and not waste 100% CPU cycles.
|
||||
///Note that some operating systems may sleep a longer time.
|
||||
static void usleep(int microSeconds);
|
||||
|
||||
private:
|
||||
struct b3ClockData* m_data;
|
||||
};
|
||||
|
||||
#endif //B3_CLOCK_H
|
||||
81
Engine/lib/bullet/examples/Utils/b3ERPCFMHelper.hpp
Executable file
81
Engine/lib/bullet/examples/Utils/b3ERPCFMHelper.hpp
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef B3_ERPCFM_HELPER
|
||||
#define B3_ERPCFM_HELPER
|
||||
|
||||
#include <LinearMath/btScalar.h>
|
||||
|
||||
/**
|
||||
* @brief ERP/CFM Utils are to provide bullet specific helper functions.
|
||||
* @details Details
|
||||
* @date 2015-09-20
|
||||
* @author Benjamin Ellenberger
|
||||
*/
|
||||
class b3ERPCFMHelper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* == How To Use ERP and CFM ==
|
||||
* ERP and CFM can be independently set in many joints. They can be set in contact joints, in joint limits and various other places, to control the spongyness and springyness of the joint (or joint limit).
|
||||
* If CFM is set to zero, the constraint will be hard. If CFM is set to a positive value, it will be possible to violate the constraint by "pushing on it" (for example, for contact constraints by forcing the two contacting objects together). In other words the constraint will be soft, and the softness will increase as CFM increases. What is actually happening here is that the constraint is allowed to be violated by an amount proportional to CFM times the restoring force that is needed to enforce the constraint. Note that setting CFM to a negative value can have undesirable bad effects, such as instability. Don't do it.
|
||||
* By adjusting the values of ERP and CFM, you can achieve various effects. For example you can simulate springy constraints, where the two bodies oscillate as though connected by springs. Or you can simulate more spongy constraints, without the oscillation. In fact, ERP and CFM can be selected to have the same effect as any desired spring and damper constants. If you have a spring constant k_p and damping constant k_d, then the corresponding ODE constants are:
|
||||
*
|
||||
* ERP = \frac{h k_p} {h k_p + k_d}
|
||||
*
|
||||
* CFM = \frac{1} {h k_p + k_d}
|
||||
*
|
||||
* where h is the step size. These values will give the same effect as a spring-and-damper system simulated with implicit first order integration.
|
||||
* Increasing CFM, especially the global CFM, can reduce the numerical errors in the simulation. If the system is near-singular, then this can markedly increase stability. In fact, if the system is misbehaving, one of the first things to try is to increase the global CFM.
|
||||
* @link http://ode-wiki.org/wiki/index.php?title=Manual:_All&printable=yes#How_To_Use_ERP_and_CFM
|
||||
* @return
|
||||
*/
|
||||
/**
|
||||
* Joint error and the Error Reduction Parameter (ERP)
|
||||
*
|
||||
* When a joint attaches two bodies, those bodies are required to have certain positions and orientations relative to each other. However, it is possible for the bodies to be in positions where the joint constraints are not met. This "joint error" can happen in two ways:
|
||||
*
|
||||
* If the user sets the position/orientation of one body without correctly setting the position/orientation of the other body.
|
||||
* During the simulation, errors can creep in that result in the bodies drifting away from their required positions.
|
||||
* Figure 3 shows an example of error in a ball and socket joint (where the ball and socket do not line up).
|
||||
*
|
||||
* There is a mechanism to reduce joint error: during each simulation step each joint applies a special force to bring its bodies back into correct alignment. This force is controlled by the error reduction parameter (ERP), which has a value between 0 and 1.
|
||||
*
|
||||
* The ERP specifies what proportion of the joint error will be fixed during the next simulation step. If ERP = 0 then no correcting force is applied and the bodies will eventually drift apart as the simulation proceeds. If ERP=1 then the simulation will attempt to fix all joint error during the next time step. However, setting ERP=1 is not recommended, as the joint error will not be completely fixed due to various internal approximations. A value of ERP=0.1 to 0.8 is recommended (0.2 is the default).
|
||||
*
|
||||
* A global ERP value can be set that affects most joints in the simulation. However some joints have local ERP values that control various aspects of the joint.
|
||||
* @link http://ode-wiki.org/wiki/index.php?title=Manual:_All&printable=yes#How_To_Use_ERP_and_CFM
|
||||
* @return
|
||||
*/
|
||||
static btScalar getERP(btScalar timeStep, btScalar kSpring,
|
||||
btScalar kDamper)
|
||||
{
|
||||
return timeStep * kSpring / (timeStep * kSpring + kDamper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Most constraints are by nature "hard". This means that the constraints represent conditions that are never violated. For example, the ball must always be in the socket, and the two parts of the hinge must always be lined up. In practice constraints can be violated by unintentional introduction of errors into the system, but the error reduction parameter can be set to correct these errors.
|
||||
* Not all constraints are hard. Some "soft" constraints are designed to be violated. For example, the contact constraint that prevents colliding objects from penetrating is hard by default, so it acts as though the colliding surfaces are made of steel. But it can be made into a soft constraint to simulate softer materials, thereby allowing some natural penetration of the two objects when they are forced together.
|
||||
* There are two parameters that control the distinction between hard and soft constraints. The first is the error reduction parameter (ERP) that has already been introduced. The second is the constraint force mixing (CFM) value, that is described below.
|
||||
*
|
||||
* == Constraint Force Mixing (CFM) ==
|
||||
* What follows is a somewhat technical description of the meaning of CFM. If you just want to know how it is used in practice then skip to the next section.
|
||||
* Traditionally the constraint equation for every joint has the form
|
||||
* \mathbf{J} v = \mathbf{c}
|
||||
* where v is a velocity vector for the bodies involved, \mathbf{J} is a "Jacobian" matrix with one row for every degree of freedom the joint removes from the system, and \mathbf{c} is a right hand side vector. At the next time step, a vector \lambda is calculated (of the same size as \mathbf{c}) such that the forces applied to the bodies to preserve the joint constraint are:
|
||||
* F_c = \mathbf{J}^T \lambda
|
||||
* ODE adds a new twist. ODE's constraint equation has the form
|
||||
*
|
||||
* \mathbf{J} v = \mathbf{c} + \textbf{CFM} \, \lambda
|
||||
* where CFM is a square diagonal matrix. CFM mixes the resulting constraint force in with the constraint that produces it. A nonzero (positive) value of CFM allows the original constraint equation to be violated by an amount proportional to CFM times the restoring force \lambda that is needed to enforce the constraint. Solving for \lambda gives
|
||||
*
|
||||
* (\mathbf{J} \mathbf{M}^{-1} \mathbf{J}^T + \frac{1}{h} \textbf{CFM}) \lambda = \frac{1}{h} \mathbf{c}
|
||||
* Thus CFM simply adds to the diagonal of the original system matrix. Using a positive value of CFM has the additional benefit of taking the system away from any singularity and thus improving the factorizer accuracy.
|
||||
* @link http://ode-wiki.org/wiki/index.php?title=Manual:_All&printable=yes#How_To_Use_ERP_and_CFM
|
||||
* @return
|
||||
*/
|
||||
static btScalar getCFM(btScalar avoidSingularity, btScalar timeStep, btScalar kSpring,
|
||||
btScalar kDamper)
|
||||
{
|
||||
return btScalar(avoidSingularity) / (timeStep * kSpring + kDamper);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* B3_ERPCFM_HELPER */
|
||||
403
Engine/lib/bullet/examples/Utils/b3Quickprof.cpp
Normal file
403
Engine/lib/bullet/examples/Utils/b3Quickprof.cpp
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
***************************************************************************************************
|
||||
**
|
||||
** profile.cpp
|
||||
**
|
||||
** Real-Time Hierarchical Profiling for Game Programming Gems 3
|
||||
**
|
||||
** by Greg Hjelstrom & Byon Garrabrant
|
||||
**
|
||||
***************************************************************************************************/
|
||||
|
||||
// Credits: The Clock class was inspired by the Timer classes in
|
||||
// Ogre (www.ogre3d.org).
|
||||
|
||||
#include "Bullet3Common/b3MinMax.h"
|
||||
#include "b3Quickprof.h"
|
||||
|
||||
#ifndef B3_NO_PROFILE
|
||||
|
||||
static b3Clock b3s_profileClock;
|
||||
|
||||
inline void b3Profile_Get_Ticks(unsigned long int* ticks)
|
||||
{
|
||||
*ticks = b3s_profileClock.getTimeMicroseconds();
|
||||
}
|
||||
|
||||
inline float b3Profile_Get_Tick_Rate(void)
|
||||
{
|
||||
// return 1000000.f;
|
||||
return 1000.f;
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
**
|
||||
** b3ProfileNode
|
||||
**
|
||||
***************************************************************************************************/
|
||||
|
||||
/***********************************************************************************************
|
||||
* INPUT: *
|
||||
* name - pointer to a static string which is the name of this profile node *
|
||||
* parent - parent pointer *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* The name is assumed to be a static pointer, only the pointer is stored and compared for *
|
||||
* efficiency reasons. *
|
||||
*=============================================================================================*/
|
||||
b3ProfileNode::b3ProfileNode(const char* name, b3ProfileNode* parent) : Name(name),
|
||||
TotalCalls(0),
|
||||
TotalTime(0),
|
||||
StartTime(0),
|
||||
RecursionCounter(0),
|
||||
Parent(parent),
|
||||
Child(NULL),
|
||||
Sibling(NULL),
|
||||
m_userPtr(0)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void b3ProfileNode::CleanupMemory()
|
||||
{
|
||||
delete (Child);
|
||||
Child = NULL;
|
||||
delete (Sibling);
|
||||
Sibling = NULL;
|
||||
}
|
||||
|
||||
b3ProfileNode::~b3ProfileNode(void)
|
||||
{
|
||||
delete (Child);
|
||||
delete (Sibling);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* INPUT: *
|
||||
* name - static string pointer to the name of the node we are searching for *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* All profile names are assumed to be static strings so this function uses pointer compares *
|
||||
* to find the named node. *
|
||||
*=============================================================================================*/
|
||||
b3ProfileNode* b3ProfileNode::Get_Sub_Node(const char* name)
|
||||
{
|
||||
// Try to find this sub node
|
||||
b3ProfileNode* child = Child;
|
||||
while (child)
|
||||
{
|
||||
if (child->Name == name)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
child = child->Sibling;
|
||||
}
|
||||
|
||||
// We didn't find it, so add it
|
||||
|
||||
b3ProfileNode* node = new b3ProfileNode(name, this);
|
||||
node->Sibling = Child;
|
||||
Child = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void b3ProfileNode::Reset(void)
|
||||
{
|
||||
TotalCalls = 0;
|
||||
TotalTime = 0.0f;
|
||||
|
||||
if (Child)
|
||||
{
|
||||
Child->Reset();
|
||||
}
|
||||
if (Sibling)
|
||||
{
|
||||
Sibling->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void b3ProfileNode::Call(void)
|
||||
{
|
||||
TotalCalls++;
|
||||
if (RecursionCounter++ == 0)
|
||||
{
|
||||
b3Profile_Get_Ticks(&StartTime);
|
||||
}
|
||||
}
|
||||
|
||||
bool b3ProfileNode::Return(void)
|
||||
{
|
||||
if (--RecursionCounter == 0 && TotalCalls != 0)
|
||||
{
|
||||
unsigned long int time;
|
||||
b3Profile_Get_Ticks(&time);
|
||||
time -= StartTime;
|
||||
TotalTime += (float)time / b3Profile_Get_Tick_Rate();
|
||||
}
|
||||
return (RecursionCounter == 0);
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
**
|
||||
** b3ProfileIterator
|
||||
**
|
||||
***************************************************************************************************/
|
||||
b3ProfileIterator::b3ProfileIterator(b3ProfileNode* start)
|
||||
{
|
||||
CurrentParent = start;
|
||||
CurrentChild = CurrentParent->Get_Child();
|
||||
}
|
||||
|
||||
void b3ProfileIterator::First(void)
|
||||
{
|
||||
CurrentChild = CurrentParent->Get_Child();
|
||||
}
|
||||
|
||||
void b3ProfileIterator::Next(void)
|
||||
{
|
||||
CurrentChild = CurrentChild->Get_Sibling();
|
||||
}
|
||||
|
||||
bool b3ProfileIterator::Is_Done(void)
|
||||
{
|
||||
return CurrentChild == NULL;
|
||||
}
|
||||
|
||||
void b3ProfileIterator::Enter_Child(int index)
|
||||
{
|
||||
CurrentChild = CurrentParent->Get_Child();
|
||||
while ((CurrentChild != NULL) && (index != 0))
|
||||
{
|
||||
index--;
|
||||
CurrentChild = CurrentChild->Get_Sibling();
|
||||
}
|
||||
|
||||
if (CurrentChild != NULL)
|
||||
{
|
||||
CurrentParent = CurrentChild;
|
||||
CurrentChild = CurrentParent->Get_Child();
|
||||
}
|
||||
}
|
||||
|
||||
void b3ProfileIterator::Enter_Parent(void)
|
||||
{
|
||||
if (CurrentParent->Get_Parent() != NULL)
|
||||
{
|
||||
CurrentParent = CurrentParent->Get_Parent();
|
||||
}
|
||||
CurrentChild = CurrentParent->Get_Child();
|
||||
}
|
||||
|
||||
/***************************************************************************************************
|
||||
**
|
||||
** b3ProfileManager
|
||||
**
|
||||
***************************************************************************************************/
|
||||
|
||||
b3ProfileNode b3ProfileManager::Root("Root", NULL);
|
||||
b3ProfileNode* b3ProfileManager::CurrentNode = &b3ProfileManager::Root;
|
||||
int b3ProfileManager::FrameCounter = 0;
|
||||
unsigned long int b3ProfileManager::ResetTime = 0;
|
||||
|
||||
/***********************************************************************************************
|
||||
* b3ProfileManager::Start_Profile -- Begin a named profile *
|
||||
* *
|
||||
* Steps one level deeper into the tree, if a child already exists with the specified name *
|
||||
* then it accumulates the profiling; otherwise a new child node is added to the profile tree. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* name - name of this profiling record *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* The string used is assumed to be a static string; pointer compares are used throughout *
|
||||
* the profiling code for efficiency. *
|
||||
*=============================================================================================*/
|
||||
void b3ProfileManager::Start_Profile(const char* name)
|
||||
{
|
||||
if (name != CurrentNode->Get_Name())
|
||||
{
|
||||
CurrentNode = CurrentNode->Get_Sub_Node(name);
|
||||
}
|
||||
|
||||
CurrentNode->Call();
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* b3ProfileManager::Stop_Profile -- Stop timing and record the results. *
|
||||
*=============================================================================================*/
|
||||
void b3ProfileManager::Stop_Profile(void)
|
||||
{
|
||||
// Return will indicate whether we should back up to our parent (we may
|
||||
// be profiling a recursive function)
|
||||
if (CurrentNode->Return())
|
||||
{
|
||||
CurrentNode = CurrentNode->Get_Parent();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* b3ProfileManager::Reset -- Reset the contents of the profiling system *
|
||||
* *
|
||||
* This resets everything except for the tree structure. All of the timing data is reset. *
|
||||
*=============================================================================================*/
|
||||
void b3ProfileManager::Reset(void)
|
||||
{
|
||||
b3s_profileClock.reset();
|
||||
Root.Reset();
|
||||
Root.Call();
|
||||
FrameCounter = 0;
|
||||
b3Profile_Get_Ticks(&ResetTime);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* b3ProfileManager::Increment_Frame_Counter -- Increment the frame counter *
|
||||
*=============================================================================================*/
|
||||
void b3ProfileManager::Increment_Frame_Counter(void)
|
||||
{
|
||||
FrameCounter++;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* b3ProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset *
|
||||
*=============================================================================================*/
|
||||
float b3ProfileManager::Get_Time_Since_Reset(void)
|
||||
{
|
||||
unsigned long int time;
|
||||
b3Profile_Get_Ticks(&time);
|
||||
time -= ResetTime;
|
||||
return (float)time / b3Profile_Get_Tick_Rate();
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void b3ProfileManager::dumpRecursive(b3ProfileIterator* profileIterator, int spacing)
|
||||
{
|
||||
profileIterator->First();
|
||||
if (profileIterator->Is_Done())
|
||||
return;
|
||||
|
||||
float accumulated_time = 0, parent_time = profileIterator->Is_Root() ? b3ProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
|
||||
int i;
|
||||
int frames_since_reset = b3ProfileManager::Get_Frame_Count_Since_Reset();
|
||||
for (i = 0; i < spacing; i++) b3Printf(".");
|
||||
b3Printf("----------------------------------\n");
|
||||
for (i = 0; i < spacing; i++) b3Printf(".");
|
||||
b3Printf("Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time);
|
||||
float totalTime = 0.f;
|
||||
|
||||
int numChildren = 0;
|
||||
|
||||
for (i = 0; !profileIterator->Is_Done(); i++, profileIterator->Next())
|
||||
{
|
||||
numChildren++;
|
||||
float current_total_time = profileIterator->Get_Current_Total_Time();
|
||||
accumulated_time += current_total_time;
|
||||
float fraction = parent_time > B3_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < spacing; i++) b3Printf(".");
|
||||
}
|
||||
b3Printf("%d -- %s (%.2f %%) :: %.3f ms / frame (%d calls)\n", i, profileIterator->Get_Current_Name(), fraction, (current_total_time / (double)frames_since_reset), profileIterator->Get_Current_Total_Calls());
|
||||
totalTime += current_total_time;
|
||||
//recurse into children
|
||||
}
|
||||
|
||||
if (parent_time < accumulated_time)
|
||||
{
|
||||
b3Printf("what's wrong\n");
|
||||
}
|
||||
for (i = 0; i < spacing; i++) b3Printf(".");
|
||||
b3Printf("%s (%.3f %%) :: %.3f ms\n", "Unaccounted:", parent_time > B3_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
|
||||
|
||||
for (i = 0; i < numChildren; i++)
|
||||
{
|
||||
profileIterator->Enter_Child(i);
|
||||
dumpRecursive(profileIterator, spacing + 3);
|
||||
profileIterator->Enter_Parent();
|
||||
}
|
||||
}
|
||||
|
||||
void b3ProfileManager::dumpAll()
|
||||
{
|
||||
b3ProfileIterator* profileIterator = 0;
|
||||
profileIterator = b3ProfileManager::Get_Iterator();
|
||||
|
||||
dumpRecursive(profileIterator, 0);
|
||||
|
||||
b3ProfileManager::Release_Iterator(profileIterator);
|
||||
}
|
||||
|
||||
void b3ProfileManager::dumpRecursive(FILE* f, b3ProfileIterator* profileIterator, int spacing)
|
||||
{
|
||||
profileIterator->First();
|
||||
if (profileIterator->Is_Done())
|
||||
return;
|
||||
|
||||
float accumulated_time = 0, parent_time = profileIterator->Is_Root() ? b3ProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time();
|
||||
int i;
|
||||
int frames_since_reset = b3ProfileManager::Get_Frame_Count_Since_Reset();
|
||||
for (i = 0; i < spacing; i++) fprintf(f, ".");
|
||||
fprintf(f, "----------------------------------\n");
|
||||
for (i = 0; i < spacing; i++) fprintf(f, ".");
|
||||
fprintf(f, "Profiling: %s (total running time: %.3f ms) ---\n", profileIterator->Get_Current_Parent_Name(), parent_time);
|
||||
float totalTime = 0.f;
|
||||
|
||||
int numChildren = 0;
|
||||
|
||||
for (i = 0; !profileIterator->Is_Done(); i++, profileIterator->Next())
|
||||
{
|
||||
numChildren++;
|
||||
float current_total_time = profileIterator->Get_Current_Total_Time();
|
||||
accumulated_time += current_total_time;
|
||||
float fraction = parent_time > B3_EPSILON ? (current_total_time / parent_time) * 100 : 0.f;
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < spacing; i++) fprintf(f, ".");
|
||||
}
|
||||
fprintf(f, "%d -- %s (%.2f %%) :: %.3f ms / frame (%d calls)\n", i, profileIterator->Get_Current_Name(), fraction, (current_total_time / (double)frames_since_reset), profileIterator->Get_Current_Total_Calls());
|
||||
totalTime += current_total_time;
|
||||
//recurse into children
|
||||
}
|
||||
|
||||
if (parent_time < accumulated_time)
|
||||
{
|
||||
fprintf(f, "what's wrong\n");
|
||||
}
|
||||
for (i = 0; i < spacing; i++)
|
||||
fprintf(f, ".");
|
||||
fprintf(f, "%s (%.3f %%) :: %.3f ms\n", "Unaccounted:", parent_time > B3_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time);
|
||||
|
||||
for (i = 0; i < numChildren; i++)
|
||||
{
|
||||
profileIterator->Enter_Child(i);
|
||||
dumpRecursive(f, profileIterator, spacing + 3);
|
||||
profileIterator->Enter_Parent();
|
||||
}
|
||||
}
|
||||
|
||||
void b3ProfileManager::dumpAll(FILE* f)
|
||||
{
|
||||
b3ProfileIterator* profileIterator = 0;
|
||||
profileIterator = b3ProfileManager::Get_Iterator();
|
||||
|
||||
dumpRecursive(f, profileIterator, 0);
|
||||
|
||||
b3ProfileManager::Release_Iterator(profileIterator);
|
||||
}
|
||||
|
||||
#endif //B3_NO_PROFILE
|
||||
150
Engine/lib/bullet/examples/Utils/b3Quickprof.h
Normal file
150
Engine/lib/bullet/examples/Utils/b3Quickprof.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
**
|
||||
** Real-Time Hierarchical Profiling for Game Programming Gems 3
|
||||
**
|
||||
** by Greg Hjelstrom & Byon Garrabrant
|
||||
**
|
||||
***************************************************************************************************/
|
||||
|
||||
// Credits: The Clock class was inspired by the Timer classes in
|
||||
// Ogre (www.ogre3d.org).
|
||||
|
||||
#ifndef B3_QUICK_PROF_H
|
||||
#define B3_QUICK_PROF_H
|
||||
|
||||
//To disable built-in profiling, please comment out next line
|
||||
//#define B3_NO_PROFILE 1
|
||||
#ifndef B3_NO_PROFILE
|
||||
#include <stdio.h> //@todo remove this, backwards compatibility
|
||||
#include "Bullet3Common/b3Scalar.h"
|
||||
#include "Bullet3Common/b3AlignedAllocator.h"
|
||||
#include <new>
|
||||
|
||||
#include "b3Clock.h"
|
||||
|
||||
///A node in the Profile Hierarchy Tree
|
||||
class b3ProfileNode
|
||||
{
|
||||
public:
|
||||
b3ProfileNode(const char* name, b3ProfileNode* parent);
|
||||
~b3ProfileNode(void);
|
||||
|
||||
b3ProfileNode* Get_Sub_Node(const char* name);
|
||||
|
||||
b3ProfileNode* Get_Parent(void) { return Parent; }
|
||||
b3ProfileNode* Get_Sibling(void) { return Sibling; }
|
||||
b3ProfileNode* Get_Child(void) { return Child; }
|
||||
|
||||
void CleanupMemory();
|
||||
void Reset(void);
|
||||
void Call(void);
|
||||
bool Return(void);
|
||||
|
||||
const char* Get_Name(void) { return Name; }
|
||||
int Get_Total_Calls(void) { return TotalCalls; }
|
||||
float Get_Total_Time(void) { return TotalTime; }
|
||||
void* GetUserPointer() const { return m_userPtr; }
|
||||
void SetUserPointer(void* ptr) { m_userPtr = ptr; }
|
||||
|
||||
protected:
|
||||
const char* Name;
|
||||
int TotalCalls;
|
||||
float TotalTime;
|
||||
unsigned long int StartTime;
|
||||
int RecursionCounter;
|
||||
|
||||
b3ProfileNode* Parent;
|
||||
b3ProfileNode* Child;
|
||||
b3ProfileNode* Sibling;
|
||||
void* m_userPtr;
|
||||
};
|
||||
|
||||
///An iterator to navigate through the tree
|
||||
class b3ProfileIterator
|
||||
{
|
||||
public:
|
||||
// Access all the children of the current parent
|
||||
void First(void);
|
||||
void Next(void);
|
||||
bool Is_Done(void);
|
||||
bool Is_Root(void) { return (CurrentParent->Get_Parent() == 0); }
|
||||
|
||||
void Enter_Child(int index); // Make the given child the new parent
|
||||
void Enter_Largest_Child(void); // Make the largest child the new parent
|
||||
void Enter_Parent(void); // Make the current parent's parent the new parent
|
||||
|
||||
// Access the current child
|
||||
const char* Get_Current_Name(void) { return CurrentChild->Get_Name(); }
|
||||
int Get_Current_Total_Calls(void) { return CurrentChild->Get_Total_Calls(); }
|
||||
float Get_Current_Total_Time(void) { return CurrentChild->Get_Total_Time(); }
|
||||
|
||||
void* Get_Current_UserPointer(void) { return CurrentChild->GetUserPointer(); }
|
||||
void Set_Current_UserPointer(void* ptr) { CurrentChild->SetUserPointer(ptr); }
|
||||
// Access the current parent
|
||||
const char* Get_Current_Parent_Name(void) { return CurrentParent->Get_Name(); }
|
||||
int Get_Current_Parent_Total_Calls(void) { return CurrentParent->Get_Total_Calls(); }
|
||||
float Get_Current_Parent_Total_Time(void) { return CurrentParent->Get_Total_Time(); }
|
||||
|
||||
protected:
|
||||
b3ProfileNode* CurrentParent;
|
||||
b3ProfileNode* CurrentChild;
|
||||
|
||||
b3ProfileIterator(b3ProfileNode* start);
|
||||
friend class b3ProfileManager;
|
||||
};
|
||||
|
||||
///The Manager for the Profile system
|
||||
class b3ProfileManager
|
||||
{
|
||||
public:
|
||||
static void Start_Profile(const char* name);
|
||||
static void Stop_Profile(void);
|
||||
|
||||
static void CleanupMemory(void)
|
||||
{
|
||||
Root.CleanupMemory();
|
||||
}
|
||||
|
||||
static void Reset(void);
|
||||
static void Increment_Frame_Counter(void);
|
||||
static int Get_Frame_Count_Since_Reset(void) { return FrameCounter; }
|
||||
static float Get_Time_Since_Reset(void);
|
||||
|
||||
static b3ProfileIterator* Get_Iterator(void)
|
||||
{
|
||||
return new b3ProfileIterator(&Root);
|
||||
}
|
||||
static void Release_Iterator(b3ProfileIterator* iterator) { delete (iterator); }
|
||||
|
||||
static void dumpRecursive(b3ProfileIterator* profileIterator, int spacing);
|
||||
static void dumpAll();
|
||||
|
||||
static void dumpRecursive(FILE* f, b3ProfileIterator* profileIterator, int spacing);
|
||||
static void dumpAll(FILE* f);
|
||||
|
||||
private:
|
||||
static b3ProfileNode Root;
|
||||
static b3ProfileNode* CurrentNode;
|
||||
static int FrameCounter;
|
||||
static unsigned long int ResetTime;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#endif //#ifndef B3_NO_PROFILE
|
||||
|
||||
#endif //B3_QUICK_PROF_H
|
||||
62
Engine/lib/bullet/examples/Utils/b3ReferenceFrameHelper.hpp
Executable file
62
Engine/lib/bullet/examples/Utils/b3ReferenceFrameHelper.hpp
Executable file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2015 Google Inc. http://bulletphysics.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef B3_REFERENCEFRAMEHELPER_H
|
||||
#define B3_REFERENCEFRAMEHELPER_H
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
class b3ReferenceFrameHelper
|
||||
{
|
||||
public:
|
||||
static btVector3 getPointWorldToLocal(const btTransform& localObjectCenterOfMassTransform, const btVector3& point)
|
||||
{
|
||||
return localObjectCenterOfMassTransform.inverse() * point; // transforms the point from the world frame into the local frame
|
||||
}
|
||||
|
||||
static btVector3 getPointLocalToWorld(const btTransform& localObjectCenterOfMassTransform, const btVector3& point)
|
||||
{
|
||||
return localObjectCenterOfMassTransform * point; // transforms the point from the world frame into the local frame
|
||||
}
|
||||
|
||||
static btVector3 getAxisWorldToLocal(const btTransform& localObjectCenterOfMassTransform, const btVector3& axis)
|
||||
{
|
||||
btTransform local1 = localObjectCenterOfMassTransform.inverse(); // transforms the axis from the local frame into the world frame
|
||||
btVector3 zero(0, 0, 0);
|
||||
local1.setOrigin(zero);
|
||||
return local1 * axis;
|
||||
}
|
||||
|
||||
static btVector3 getAxisLocalToWorld(const btTransform& localObjectCenterOfMassTransform, const btVector3& axis)
|
||||
{
|
||||
btTransform local1 = localObjectCenterOfMassTransform; // transforms the axis from the local frame into the world frame
|
||||
btVector3 zero(0, 0, 0);
|
||||
local1.setOrigin(zero);
|
||||
return local1 * axis;
|
||||
}
|
||||
|
||||
static btTransform getTransformWorldToLocal(const btTransform& localObjectCenterOfMassTransform, const btTransform& transform)
|
||||
{
|
||||
return localObjectCenterOfMassTransform.inverse() * transform; // transforms the axis from the local frame into the world frame
|
||||
}
|
||||
|
||||
static btTransform getTransformLocalToWorld(const btTransform& localObjectCenterOfMassTransform, const btTransform& transform)
|
||||
{
|
||||
return localObjectCenterOfMassTransform * transform; // transforms the axis from the local frame into the world frame
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* B3_REFERENCEFRAMEHELPER_H */
|
||||
155
Engine/lib/bullet/examples/Utils/b3ResourcePath.cpp
Normal file
155
Engine/lib/bullet/examples/Utils/b3ResourcePath.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
#include "b3ResourcePath.h"
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
//not Mac, not Windows, let's cross the fingers it is Linux :-)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "Bullet3Common/b3FileUtils.h"
|
||||
#define B3_MAX_EXE_PATH_LEN 4096
|
||||
|
||||
int b3ResourcePath::getExePath(char* path, int maxPathLenInBytes)
|
||||
{
|
||||
int numBytes = 0;
|
||||
|
||||
#if __APPLE__
|
||||
uint32_t bufsize = uint32_t(maxPathLenInBytes);
|
||||
|
||||
if (_NSGetExecutablePath(path, &bufsize) != 0)
|
||||
{
|
||||
b3Warning("Cannot find executable path\n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
numBytes = strlen(path);
|
||||
}
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms683197(v=vs.85).aspx
|
||||
|
||||
HMODULE hModule = GetModuleHandle(NULL);
|
||||
numBytes = GetModuleFileNameA(hModule, path, maxPathLenInBytes);
|
||||
|
||||
#else
|
||||
///http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c
|
||||
numBytes = (int)readlink("/proc/self/exe", path, maxPathLenInBytes - 1);
|
||||
if (numBytes > 0)
|
||||
{
|
||||
path[numBytes] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b3Warning("Cannot find executable path\n");
|
||||
}
|
||||
#endif //_WIN32
|
||||
#endif //__APPLE__
|
||||
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
struct TempResourcePath
|
||||
{
|
||||
char* m_path;
|
||||
TempResourcePath(int len)
|
||||
{
|
||||
m_path = (char*)malloc(len);
|
||||
memset(m_path, 0, len);
|
||||
}
|
||||
virtual ~TempResourcePath()
|
||||
{
|
||||
free(m_path);
|
||||
}
|
||||
};
|
||||
|
||||
static char sAdditionalSearchPath[B3_MAX_EXE_PATH_LEN] = {0};
|
||||
|
||||
void b3ResourcePath::setAdditionalSearchPath(const char* path)
|
||||
{
|
||||
if (path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
if (len < (B3_MAX_EXE_PATH_LEN - 1))
|
||||
{
|
||||
strcpy(sAdditionalSearchPath, path);
|
||||
sAdditionalSearchPath[len] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sAdditionalSearchPath[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool b3MyFindFile(void* userPointer, const char* orgFileName, char* relativeFileName, int maxRelativeFileNameMaxLen)
|
||||
{
|
||||
return b3FileUtils::findFile(orgFileName, relativeFileName, maxRelativeFileNameMaxLen);
|
||||
}
|
||||
|
||||
int b3ResourcePath::findResourcePath(const char* resourceName, char* resourcePathOut, int resourcePathMaxNumBytes, PFN_FIND_FILE findFile, void* userPointer)
|
||||
{
|
||||
if (findFile==0)
|
||||
{
|
||||
findFile=b3MyFindFile;
|
||||
}
|
||||
//first find in a resource/<exeName> location, then in various folders within 'data' using b3FileUtils
|
||||
char exePath[B3_MAX_EXE_PATH_LEN];
|
||||
|
||||
bool res = findFile(userPointer, resourceName, resourcePathOut, resourcePathMaxNumBytes);
|
||||
if (res)
|
||||
{
|
||||
return strlen(resourcePathOut);
|
||||
}
|
||||
|
||||
if (sAdditionalSearchPath[0])
|
||||
{
|
||||
TempResourcePath tmpPath(resourcePathMaxNumBytes + 1024);
|
||||
char* resourcePathIn = tmpPath.m_path;
|
||||
sprintf(resourcePathIn, "%s/%s", sAdditionalSearchPath, resourceName);
|
||||
//printf("try resource at %s\n", resourcePath);
|
||||
if (findFile(userPointer, resourcePathIn, resourcePathOut, resourcePathMaxNumBytes))
|
||||
{
|
||||
return strlen(resourcePathOut);
|
||||
}
|
||||
}
|
||||
|
||||
int l = b3ResourcePath::getExePath(exePath, B3_MAX_EXE_PATH_LEN);
|
||||
if (l)
|
||||
{
|
||||
char pathToExe[B3_MAX_EXE_PATH_LEN];
|
||||
|
||||
int exeNamePos = b3FileUtils::extractPath(exePath, pathToExe, B3_MAX_EXE_PATH_LEN);
|
||||
if (exeNamePos)
|
||||
{
|
||||
TempResourcePath tmpPath(resourcePathMaxNumBytes + 1024);
|
||||
char* resourcePathIn = tmpPath.m_path;
|
||||
sprintf(resourcePathIn, "%s../data/%s", pathToExe, resourceName);
|
||||
//printf("try resource at %s\n", resourcePath);
|
||||
if (findFile(userPointer, resourcePathIn, resourcePathOut, resourcePathMaxNumBytes))
|
||||
{
|
||||
return strlen(resourcePathOut);
|
||||
}
|
||||
|
||||
sprintf(resourcePathIn, "%s../resources/%s/%s", pathToExe, &exePath[exeNamePos], resourceName);
|
||||
//printf("try resource at %s\n", resourcePath);
|
||||
if (findFile(userPointer, resourcePathIn, resourcePathOut, resourcePathMaxNumBytes))
|
||||
{
|
||||
return strlen(resourcePathOut);
|
||||
}
|
||||
sprintf(resourcePathIn, "%s.runfiles/google3/third_party/bullet/data/%s", exePath, resourceName);
|
||||
//printf("try resource at %s\n", resourcePath);
|
||||
if (findFile(userPointer, resourcePathIn, resourcePathOut, resourcePathMaxNumBytes))
|
||||
{
|
||||
return strlen(resourcePathOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
Engine/lib/bullet/examples/Utils/b3ResourcePath.h
Normal file
15
Engine/lib/bullet/examples/Utils/b3ResourcePath.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _B3_RESOURCE_PATH_H
|
||||
#define _B3_RESOURCE_PATH_H
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef bool (* PFN_FIND_FILE)(void* userPointer, const char* orgFileName, char* relativeFileName, int maxRelativeFileNameMaxLen);
|
||||
|
||||
class b3ResourcePath
|
||||
{
|
||||
public:
|
||||
static int getExePath(char* path, int maxPathLenInBytes);
|
||||
static int findResourcePath(const char* resourceName, char* resourcePathOut, int resourcePathMaxNumBytes, PFN_FIND_FILE findFile, void* userPointer=0);
|
||||
static void setAdditionalSearchPath(const char* path);
|
||||
};
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue