Skip to content

Instantly share code, notes, and snippets.

@focalintent
Last active March 1, 2023 07:08
Show Gist options
  • Save focalintent/5f97216341278976e749 to your computer and use it in GitHub Desktop.
Save focalintent/5f97216341278976e749 to your computer and use it in GitHub Desktop.
Showing off some pixel mapping and rotating
// base GridMap class. Allows from mapping from an X x Y grid of
// T values to an MX x MY grid of T values (where
// MX and MY are greater than X and Y respectively), using linear
// interpolation to fill in the gaps. Optionally allows for rotating
// around the center point. Subclasses should provide an implementation
// for the interpolate method, appropriate to the type of data being mapped
template<int X, int Y, int MX, int MY, class T> class AbstractGridMap {
int revcosval,revsinval;
uint8_t angle;
inline void rtpt_rev(int & x, int & y) {
if(angle) {
int _x = x - MX/2;
int _y = y - MX/2;
x = (_x * revcosval) - (_y * revsinval);
y = (_x * revsinval) + (_y * revcosval);
x /= 256;
y /= 256;
x += (MX/2);
y += (MX/2);
}
}
public:
T m_Data[X][Y];
public:
AbstractGridMap() { rotate(0); }
void rotate(uint8_t rotate) {
angle=rotate;
revcosval = 2 * ((int)cos8(256-angle)-128);
revsinval = 2 * ((int)sin8(256-angle)-128);
}
T* operator[](int x) { return m_Data[x]; }
virtual T interpolate(int bx, int by, int fx, int fy) = 0;
T operator()(int x, int y) {
// reverse rotate x/y
rtpt_rev(x,y);
// compute inner grid point
int bx = (x * (X-1))/MX;
int by = (y * (Y-1))/MY;
// get the delta between the inner grid point and the requested location
int dx = x - ((bx) * MX) / (X-1);
int dy = y - ((by) * MY) / (Y-1);
// convert the delta into a 0-255 frac8 value
uint8_t fx = (dx*256) / MX;
uint8_t fy = (dy*256) / MX;
return interpolate(bx,by,fx,fy);
}
};
template<int X, int Y, int MX, int MY> class CRGBGridMap : public AbstractGridMap<X,Y,MX,MY,CRGB> {
public:
CRGBGridMap() { this->rotate(0); }
virtual CRGB interpolate(int bx, int by, int fx, int fy) {
CRGB x1(this->m_Data[bx][by].lerp8(this->m_Data[bx+1][by],fx));
CRGB x2(this->m_Data[bx][by+1].lerp8(this->m_Data[bx+1][by+1],fx));
return x1.lerp8(x2,fy);
}
};
template<int X, int Y, int MX, int MY> class GridMap : public AbstractGridMap<X,Y,MX,MY,uint16_t> {
public:
GridMap() { memset(this->m_Data,0,sizeof(uint16_t)*X*Y); }
virtual uint16_t interpolate(int bx, int by, int fx, int fy) {
uint16_t x1 = lerp16by8(this->m_Data[bx][by],this->m_Data[bx+1][by],fx);
uint16_t x2 = lerp16by8(this->m_Data[bx][by+1], this->m_Data[bx+1][by+1],fx);
return lerp16by8(x1,x2,fy);
}
};
// An example of the fire demo. This assumes that there's a pair of arrays setup:
// int X[NUM_LEDS] = { 1,2,... };
// int Y[NUM_LEDS] = {10, 11, ... };
// so that you can get the X/Y mapped coordinates of a given led with X[i] and Y[i]. Also,
// note that i've normalized the X/Y mappings to be 0-255.
#define FIRE_GRID 17
void Fire2014()
{
// Array of temperature readings at each simulation cell
static byte heat[FIRE_GRID][FIRE_GRID];
// Map from a 17x17 CRGB grid of computed color cells to the 255x255 grid of
// leds.
static CRGBGridMap<FIRE_GRID, FIRE_GRID, 255, 255> heatColors;
// uncomment the following two lines to spin the fire around
// static uint8_t rotate = 0;
// heatColors.rotate(rotate++);
// Step 1. Cool down every cell a little
for(int col = 0; col < (FIRE_GRID); col++) {
for( int i = 0; i < FIRE_GRID; i++) {
heat[col][i] = qsub8( heat[col][i], random8(0, ((COOLING * 10) / FIRE_GRID) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( int k= FIRE_GRID - 3; k > 2; k--) {
heat[col][k] = (heat[col][k - 1] + heat[col][k - 2] + heat[col][k - 2] ) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
int y = random8(3);
heat[col][y] = qadd8( heat[col][y], random8(160,255) );
}
}
// Make heat colors
for(int i = 0; i < FIRE_GRID; i++) {
for(int j = 0; j < FIRE_GRID; j++) {
heatColors[i][j] = HeatColor(heat[i][j]);
}
}
// Map the heat colors into the array of leds
for(int i = 0; i < NUM_LEDS; i++) {
leds[i] = heatColors(X[i],Y[i]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment