#include #include template struct stack { int data[size] = {}; uint32_t top = 0; inline void push(int symbol) { if(!full()) { data[top++] = symbol; } } inline int pop() { if(!empty()) { return data[--top]; } return 0; } inline int peek() { if(!empty()) { return data[top - 1]; } return 0; } inline bool empty() { return top == 0; } inline bool full() { return top >= size; } inline void clear() { top = 0; } void print() { for(uint32_t cursor = 0; cursor < top; cursor++) { Serial.printf("%d ", data[cursor]); } Serial.println(); } }; template struct generator { stack stack; char program[program_size] = {}; uint32_t length = program_size; generator() { randomize(); } generator(const char* program) { uint32_t cursor = 0; while(program[cursor] != '\0' && cursor < program_size - 1) { this->program[cursor] = program[cursor]; cursor++; } length = cursor; this->program[length + 1] = '\0'; } char random_command() { const char commands[] = "0123456789abcdefxywhtrsopzq_=+*&|^~<>-/%"; return commands[random(0, sizeof(commands) - 1)]; } void randomize() { length = random(2, program_size-1); for(uint32_t cursor = 0; cursor < length; cursor++) { program[cursor] = random_command(); } program[length] = '\0'; } int run(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t t, int previous, uint16_t tx, uint16_t ty) { for(uint32_t cursor = 0; cursor < length; cursor++) { char instruction = program[cursor]; if(instruction >= '0' && instruction <= '9') { stack.push(instruction - '0'); } else if(instruction >= 'a' && instruction <= 'f') { stack.push((instruction - 'a') + 10); } else { switch(instruction) { case 'x': stack.push(x); break; case 'y': stack.push(y); break; case 'w': stack.push(w); break; case 'h': stack.push(h); break; case 't': stack.push(t); break; case 'r': stack.push(random()); break; case 's': stack.push(sin(stack.pop()) * INT_MAX); break; case 'o': stack.push(cos(stack.pop()) * INT_MAX); break; case 'p': stack.push(previous); break; case 'z': stack.push(tx); break; case 'q': stack.push(ty); break; case '_': stack.push(abs(stack.pop())); break; case '=': stack.push(stack.pop() == stack.pop()); break; case '+': stack.push(stack.pop() + stack.pop()); break; case '*': stack.push(stack.pop() * stack.pop()); break; case '&': stack.push(stack.pop() & stack.pop()); break; case '|': stack.push(stack.pop() | stack.pop()); break; case '^': stack.push(stack.pop() ^ stack.pop()); break; case '~': stack.push(~stack.pop()); break; case '<': { int first = stack.pop(); int second = stack.pop(); stack.push(second < first); break; } case '>': { int first = stack.pop(); int second = stack.pop(); stack.push(second < first); break; } case '-': { int first = stack.pop(); int second = stack.pop(); if(first == 0) { first = -1; } if(second == 0) { second = -1; } stack.push(second - first); break; } case '/': { int first = stack.pop(); int second = stack.pop(); stack.push(second / first); break; } case '%': { int first = stack.pop(); int second = stack.pop(); stack.push(second % first); break; } default: break; } } } return stack.pop(); } void print(uint32_t size) { M5.Display.pushState(); M5.Display.writeFillRect(0, M5.Display.height() - (size * 8), M5.Display.width(), M5.Display.height(), TFT_BLACK); M5.Display.setCursor(0, M5.Display.height() - (size * 8) + 4); M5.Display.setTextSize(3); M5.Display.setTextWrap(true); M5.Display.setTextColor(TFT_DARKGREY, TFT_BLACK); for(uint32_t instruction = 0; instruction < length; instruction++) { M5.Display.print(program[instruction]); } M5.Display.popState(); } }; uint32_t width = 0; uint32_t height = 0; uint32_t size = 10; uint32_t tile_size = 1; uint32_t t = 0; uint32_t cooldown = 0; uint8_t wait = 25; int8_t offset = 1; generator<256, 53*3> pixel("xy+xy-&9f+%9>8-"); inline bool shaken(float ax, float ay, float az) { return (abs(ax) >= 1.75) || (abs(ay) >= 1.5) || (abs(az) >= 1.75); } void intro() { M5.Display.setTextSize(4); M5.Display.drawCenterString("For Greg", M5.Display.width() / 2, (M5.Display.height() / 2) - 16); M5.Display.drawCenterString("From Nouveau", M5.Display.width() / 2, (M5.Display.height() / 2) + 16); M5.Display.setTextColor(random(0, UINT16_MAX), random(0, UINT16_MAX)); delay(5000); M5.Display.clear(); M5.Display.setTextSize(size); int previous = pixel.run(0, 0, width, height, 0, 0, 0, 0); for(uint32_t x = 0; x < width; x++) { for(uint32_t y = 0; y < height; y++) { const int value = pixel.run(x, y, width, height, t, previous, 0, 0); const int character = (abs(value % 17)) + 127; M5.Display.drawChar(character, x * tile_size, y * tile_size); previous = value; delay(1); } } delay(1000); M5.Display.setTextSize(4); M5.Display.setTextColor(TFT_CYAN, TFT_DARKCYAN); M5.Display.drawCenterString(" ", M5.Display.width() / 2, (M5.Display.height() / 2) - 48); M5.Display.drawCenterString(" ALL THESE WORLDS ", M5.Display.width() / 2, (M5.Display.height() / 2) - 16); M5.Display.drawCenterString(" ARE YOURS ", M5.Display.width() / 2, (M5.Display.height() / 2) + 16); M5.Display.drawCenterString(" ", M5.Display.width() / 2, (M5.Display.height() / 2) + 48); delay(5000); pixel.randomize(); M5.Display.fillRect(0, 0, M5.Display.width(), M5.Display.height(), TFT_BLACK); delay(1000); } void setup(void) { Serial.begin(9600); M5.begin(); M5.Display.setRotation(1); M5.Display.setFont(&fonts::Font8x8C64); M5.Display.waitDisplay(); size = 2; tile_size = size * 8; width = M5.Display.width() / tile_size; height = (M5.Display.height() / tile_size) - 1; intro(); size = 10; tile_size = size * 8; width = M5.Display.width() / tile_size; height = (M5.Display.height() / tile_size) - 1; M5.Display.setTextSize(size); M5.Display.setTextColor(random(), random()); pixel.print(size); } void loop(void) { lgfx::touch_point_t point = {}; float ax = 0, ay = 0, az = 0; bool touch = false; M5.Imu.update(); M5.Imu.getAccel(&ax, &ay, &az); if(M5.Display.getTouchRaw(&point, 1)) { M5.Display.convertRawXY(&point, 1); touch = true; } M5.Display.startWrite(); int previous = pixel.run(0, 0, width, height, 0, 0, 0, 0); bool alive = false; for(uint32_t x = 0; x < width; x++) { for(uint32_t y = 0; y < height; y++) { const int value = pixel.run(x, y, width, height, t, previous, map(point.x, 0, M5.Display.width(), 0, width), map(point.y, 0, M5.Display.height(), 0, height)); const int character = (abs(value % 17)) + 127; M5.Display.drawChar(character, x * tile_size, y * tile_size); if(((abs(previous % 17)) + 127) != character) { alive = true; } previous = value; } } M5.Display.endWrite(); t += offset; if(wait > 0) { wait--; } if(cooldown > 0) { cooldown--; } if(touch) { cooldown = 100; } if(!alive) { wait = 0; } if((shaken(ax, ay, az) && !touch) || (wait == 0 && (!alive || cooldown == 0))) { pixel.randomize(); if(alive) { M5.Display.setTextColor(random(), random()); } wait = 50; pixel.print(size); t = 0; } if(t >= 1000000) { offset = -1; } else if(t == 0) { offset = 1; } }