mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-14 05:40:05 +00:00
353 lines
9.7 KiB
C++
353 lines
9.7 KiB
C++
#include "TimeSeriesCanvas.h"
|
|
#include "../CommonInterfaces/Common2dCanvasInterface.h"
|
|
#include "LinearMath/btAlignedObjectArray.h"
|
|
#include "TimeSeriesFontData.h"
|
|
#include "LinearMath/btVector3.h"
|
|
#include <stdio.h>
|
|
|
|
struct DataSource
|
|
{
|
|
unsigned char m_red;
|
|
unsigned char m_green;
|
|
unsigned char m_blue;
|
|
float m_lastValue;
|
|
bool m_hasLastValue;
|
|
DataSource()
|
|
:m_hasLastValue(false)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TimeSeriesInternalData
|
|
{
|
|
btAlignedObjectArray<DataSource> m_dataSources;
|
|
|
|
struct Common2dCanvasInterface* m_canvasInterface;
|
|
int m_canvasIndex;
|
|
int m_width;
|
|
int m_height;
|
|
|
|
float m_pixelsPerUnit;
|
|
float m_zero;
|
|
int m_timeTicks;
|
|
int m_ticksPerSecond;
|
|
float m_yScale;
|
|
int m_bar;
|
|
|
|
unsigned char m_backgroundRed;
|
|
unsigned char m_backgroundGreen;
|
|
unsigned char m_backgroundBlue;
|
|
unsigned char m_backgroundAlpha;
|
|
|
|
unsigned char m_textColorRed;
|
|
unsigned char m_textColorGreen;
|
|
unsigned char m_textColorBlue;
|
|
unsigned char m_textColorAlpha;
|
|
|
|
float getTime()
|
|
{
|
|
return m_timeTicks/(float)m_ticksPerSecond;
|
|
}
|
|
|
|
TimeSeriesInternalData(int width, int height)
|
|
:m_width(width),
|
|
m_height(height),
|
|
m_pixelsPerUnit(-100),
|
|
m_zero(height/2.0),
|
|
m_timeTicks(0),
|
|
m_ticksPerSecond(100),
|
|
m_yScale(1),
|
|
m_bar(0),
|
|
m_backgroundRed(255),
|
|
m_backgroundGreen(255),
|
|
m_backgroundBlue(255),
|
|
m_backgroundAlpha(255),
|
|
m_textColorRed(0),
|
|
m_textColorGreen(0),
|
|
m_textColorBlue(255),
|
|
m_textColorAlpha(255)
|
|
{
|
|
}
|
|
};
|
|
|
|
TimeSeriesCanvas::TimeSeriesCanvas(struct Common2dCanvasInterface* canvasInterface, int width, int height, const char* windowTitle)
|
|
{
|
|
m_internalData = new TimeSeriesInternalData(width,height);
|
|
|
|
m_internalData->m_canvasInterface = canvasInterface;
|
|
|
|
if (canvasInterface)
|
|
{
|
|
m_internalData->m_canvasIndex = m_internalData->m_canvasInterface->createCanvas(windowTitle,m_internalData->m_width,m_internalData->m_height);
|
|
}
|
|
}
|
|
|
|
void TimeSeriesCanvas::addDataSource(const char* dataSourceLabel, unsigned char red,unsigned char green,unsigned char blue)
|
|
{
|
|
DataSource dataSource;
|
|
dataSource.m_red = red;
|
|
dataSource.m_green = green;
|
|
dataSource.m_blue = blue;
|
|
dataSource.m_lastValue = 0;
|
|
dataSource.m_hasLastValue = false;
|
|
|
|
|
|
if (dataSourceLabel)
|
|
{
|
|
int numSources = m_internalData->m_dataSources.size();
|
|
int row = numSources%3;
|
|
int column = numSources/3;
|
|
grapicalPrintf(dataSourceLabel, sTimeSeriesFontData, 50+200*column,m_internalData->m_height-48+row*16,
|
|
red, green,blue,255);
|
|
}
|
|
|
|
m_internalData->m_dataSources.push_back(dataSource);
|
|
|
|
}
|
|
void TimeSeriesCanvas::setupTimeSeries(float yScale, int ticksPerSecond, int startTime)
|
|
{
|
|
if (0==m_internalData->m_canvasInterface)
|
|
return;
|
|
|
|
m_internalData->m_pixelsPerUnit = -(m_internalData->m_height/3.f)/yScale;
|
|
m_internalData->m_ticksPerSecond = ticksPerSecond;
|
|
m_internalData->m_yScale = yScale;
|
|
m_internalData->m_dataSources.clear();
|
|
for (int i=0;i<m_internalData->m_width;i++)
|
|
{
|
|
for (int j=0;j<m_internalData->m_height;j++)
|
|
{
|
|
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,i,j,
|
|
m_internalData->m_backgroundRed,
|
|
m_internalData->m_backgroundGreen,
|
|
m_internalData->m_backgroundBlue,
|
|
m_internalData->m_backgroundAlpha);
|
|
}
|
|
}
|
|
|
|
|
|
float zeroPixelCoord = m_internalData->m_zero;
|
|
float pixelsPerUnit = m_internalData->m_pixelsPerUnit;
|
|
|
|
float yPos = zeroPixelCoord+pixelsPerUnit*yScale;
|
|
float yNeg = zeroPixelCoord+pixelsPerUnit*-yScale;
|
|
|
|
|
|
grapicalPrintf("0", sTimeSeriesFontData, 2,zeroPixelCoord,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha);
|
|
char label[1024];
|
|
sprintf(label,"%2.1f", yScale);
|
|
grapicalPrintf(label, sTimeSeriesFontData, 2,yPos,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha);
|
|
sprintf(label,"%2.1f", -yScale);
|
|
grapicalPrintf(label, sTimeSeriesFontData, 2,yNeg,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha);
|
|
|
|
m_internalData->m_canvasInterface->refreshImageData(m_internalData->m_canvasIndex);
|
|
|
|
}
|
|
|
|
TimeSeriesCanvas::~TimeSeriesCanvas()
|
|
{
|
|
if (m_internalData->m_canvasInterface && m_internalData->m_canvasIndex>=0)
|
|
{
|
|
m_internalData->m_canvasInterface->destroyCanvas(m_internalData->m_canvasIndex);
|
|
}
|
|
delete m_internalData;
|
|
}
|
|
|
|
float TimeSeriesCanvas::getCurrentTime() const
|
|
{
|
|
return m_internalData->getTime();
|
|
}
|
|
void TimeSeriesCanvas::grapicalPrintf(const char* str, void* fontData, int rasterposx,int rasterposy, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha)
|
|
{
|
|
unsigned char c;
|
|
int x=0;
|
|
int xx=0;
|
|
|
|
while ((c = (unsigned char) *str++)) {
|
|
|
|
x=xx;
|
|
unsigned char* fontPtr = (unsigned char*) fontData;
|
|
char ch = c-32;
|
|
|
|
int sx=ch%16;
|
|
int sy=ch/16;
|
|
|
|
|
|
for (int i=sx*16;i<(sx*16+16);i++)
|
|
{
|
|
int y=0;
|
|
for (int j=sy*16;j<(sy*16+16);j++)
|
|
{
|
|
unsigned char packedColor = (fontPtr[i*3+255*256*3-(256*j)*3]);
|
|
//float colorf = packedColor ? 0.f : 1.f;
|
|
float colorf = packedColor/255.f;// ? 0.f : 1.f;
|
|
btVector4 rgba(colorf,colorf,colorf,1.f);
|
|
if (colorf)
|
|
{
|
|
if ((rasterposx+x>=0) && (rasterposx+x < m_internalData->m_width) &&
|
|
(rasterposy+y>=0) && (rasterposy+y<m_internalData->m_height))
|
|
{
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,rasterposx+x,rasterposy+y,
|
|
red,green,blue,alpha);
|
|
}
|
|
}
|
|
y++;
|
|
}
|
|
x++;
|
|
}
|
|
xx+=10;
|
|
}
|
|
}
|
|
|
|
void TimeSeriesCanvas::shift1PixelToLeft()
|
|
{
|
|
|
|
int resetVal = 10;
|
|
int countdown = resetVal;
|
|
|
|
//shift pixture one pixel to the left
|
|
for (int j=0;j<m_internalData->m_height-48;j++)
|
|
{
|
|
for (int i=40;i<this->m_internalData->m_width;i++)
|
|
{
|
|
unsigned char red, green, blue, alpha;
|
|
m_internalData->m_canvasInterface->getPixel(m_internalData->m_canvasIndex,i,j,red,green,blue,alpha);
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,i-1,j,red,green,blue,alpha);
|
|
}
|
|
if (!m_internalData->m_bar)
|
|
{
|
|
|
|
|
|
if (!countdown--)
|
|
{
|
|
countdown=resetVal;
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,0,0,0,255);
|
|
} else
|
|
{
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,255,255,255,255);
|
|
|
|
}
|
|
} else
|
|
{
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,255,255,255,255);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
{
|
|
int resetVal = 2;
|
|
static int countdown = resetVal;
|
|
if (!countdown--)
|
|
{
|
|
countdown=resetVal;
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,m_internalData->m_zero,0,0,0,255);
|
|
}
|
|
}
|
|
|
|
{
|
|
int resetVal = 10;
|
|
static int countdown = resetVal;
|
|
if (!countdown--)
|
|
{
|
|
countdown=resetVal;
|
|
float zeroPixelCoord = m_internalData->m_zero;
|
|
float pixelsPerUnit = m_internalData->m_pixelsPerUnit;
|
|
|
|
float yPos = zeroPixelCoord+pixelsPerUnit*m_internalData->m_yScale;
|
|
float yNeg = zeroPixelCoord+pixelsPerUnit*-m_internalData->m_yScale;
|
|
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,
|
|
yPos,0,0,0,255);
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,
|
|
yNeg,0,0,0,255);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_internalData->m_bar)
|
|
{
|
|
char buf[1024];
|
|
float time = m_internalData->getTime();
|
|
sprintf(buf,"%2.0f",time);
|
|
grapicalPrintf(buf, sTimeSeriesFontData, m_internalData->m_width-25,m_internalData->m_zero+3,0,0,0,255);
|
|
|
|
m_internalData->m_bar=m_internalData->m_ticksPerSecond;
|
|
|
|
}
|
|
m_internalData->m_timeTicks++;
|
|
|
|
m_internalData->m_bar--;
|
|
|
|
}
|
|
|
|
void TimeSeriesCanvas::insertDataAtCurrentTime(float orgV, int dataSourceIndex, bool connectToPrevious)
|
|
{
|
|
if (0==m_internalData->m_canvasInterface)
|
|
return;
|
|
|
|
btAssert(dataSourceIndex < m_internalData->m_dataSources.size());
|
|
|
|
float zero = m_internalData->m_zero;
|
|
float amp = m_internalData->m_pixelsPerUnit;
|
|
//insert some new value(s) in the right-most column
|
|
{
|
|
float time = m_internalData->getTime();
|
|
|
|
float v = zero+amp*orgV;
|
|
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,v,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_red,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_green,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_blue,
|
|
255
|
|
);
|
|
|
|
if (connectToPrevious && m_internalData->m_dataSources[dataSourceIndex].m_hasLastValue)
|
|
{
|
|
for (int value=m_internalData->m_dataSources[dataSourceIndex].m_lastValue;value<=v;value++)
|
|
{
|
|
if (value>=0 && value < float(m_internalData->m_height-1))
|
|
{
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,value,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_red,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_green,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_blue,
|
|
255
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int value=v;value<=m_internalData->m_dataSources[dataSourceIndex].m_lastValue;value++)
|
|
{
|
|
if (value>=0 && value < float(m_internalData->m_height-1))
|
|
{
|
|
m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,value,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_red,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_green,
|
|
m_internalData->m_dataSources[dataSourceIndex].m_blue,
|
|
255);
|
|
}
|
|
}
|
|
|
|
}
|
|
m_internalData->m_dataSources[dataSourceIndex].m_lastValue = v;
|
|
m_internalData->m_dataSources[dataSourceIndex].m_hasLastValue = true;
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
void TimeSeriesCanvas::nextTick()
|
|
{
|
|
shift1PixelToLeft();
|
|
m_internalData->m_canvasInterface->refreshImageData(m_internalData->m_canvasIndex);
|
|
}
|