├── Documentation ├── schematic.png └── schematic3bit.png ├── README.md ├── Utilities ├── SpriteEditor.html └── StlConverter.html ├── examples ├── 1BitMode │ └── 1BitMode.ino ├── 6BitMode │ └── 6BitMode.ino ├── 8BitDACMode │ └── 8BitDACMode.ino ├── CompositeDACColorMode │ └── CompositeDACColorMode.ino ├── CompositeDACMode │ └── CompositeDACMode.ino ├── GFXWrapper │ └── GFXWrapper.ino ├── LEDs │ ├── LEDWall3Camera │ │ ├── LEDWall3Camera.ino │ │ ├── camera.h │ │ ├── effects.h │ │ └── tools.h │ └── NyanCat │ │ ├── NyanCat.ino │ │ └── nyan.h ├── Raytracer │ ├── Raytracer.h │ └── Raytracer.ino ├── TextMode │ └── TextMode.ino ├── VGA2DFeatures │ ├── VGA2DFeatures.ino │ └── rock.h ├── VGA3DEngine │ ├── VGA3DEngine.ino │ └── thinker.h ├── VGACustomResolution │ └── VGACustomResolution.ino ├── VGADemo14Bit │ └── VGADemo14Bit.ino ├── VGAFonts │ └── VGAFonts.ino ├── VGAHelloWorld │ └── VGAHelloWorld.ino ├── VGAHighRes │ └── VGAHighRes.ino ├── VGAMadness │ ├── 3DStarfield │ │ └── 3DStarfield.ino │ ├── VGABitlunisMadnessColor │ │ └── VGABitlunisMadnessColor.ino │ ├── VGABitlunisMadnessMonoColorCombinations │ │ └── VGABitlunisMadnessMonoColorCombinations.ino │ └── VGABitlunisMadnessMonochrome │ │ └── VGABitlunisMadnessMonochrome.ino ├── VGANoFrameBuffer │ └── VGANoFrameBuffer.ino ├── VGASprites │ ├── VGASprites.ino │ └── explosion.h ├── VGAWiFiTextTerminal │ ├── VGAWiFiTextTerminal.ino │ └── page.h └── XPlayerGameAlpha │ └── XPlayerGameAlpha.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── Audio ├── AudioOutput.h └── AudioSystem.h ├── Composite ├── CompMode.cpp ├── CompMode.h ├── Composite.h ├── CompositeColorDAC.h ├── CompositeColorDACMemory.h ├── CompositeColorLadder.h ├── CompositeColorLadderMemory.h ├── CompositeGrayDAC.h ├── CompositeGrayDACI.cpp ├── CompositeGrayDACI.h ├── CompositeGrayLadder.h ├── CompositeGrayLadderI.cpp ├── CompositeGrayLadderI.h ├── CompositeGrayPDM2.h ├── CompositeGrayPDM4.h ├── CompositeGrayPDM8.h ├── CompositeI2SEngine.h ├── CompositeL8.h ├── CompositePAL8.h ├── CompositePinConfig.cpp ├── CompositePinConfig.h ├── ModeComposite.h └── PinConfigComposite.h ├── Controller └── GameControllers.h ├── ESP32Lib.h ├── ESP32Video.h ├── GfxWrapper.h ├── Graphics ├── Animation.h ├── BufferLayouts.h ├── BufferLayouts │ ├── BLpx1sz16sw0sh0.h │ ├── BLpx1sz16sw1sh0.h │ ├── BLpx1sz16sw1sh8.h │ ├── BLpx1sz32sw0sh0.h │ ├── BLpx1sz8sw0sh0.h │ ├── BLpx1sz8sw2sh0.h │ ├── BLpx1sz8sw3sh0.h │ ├── BLpx2sz8sw3xshx.h │ ├── BLpx2sz8swxshx.h │ ├── BLpx4sz16swmx1yshmxy.h │ ├── BLpx4sz8sw3xshx.h │ ├── BLpx6sz8swmx2yshmxy.h │ └── BLpx8sz8swyshy.h ├── ColorToBuffer.h ├── ColorToBuffer │ ├── CTBComposite.h │ ├── CTBCompositeMemory.h │ ├── CTBIdentity.h │ ├── CTBRange.h │ ├── CTBRangePDM2.h │ ├── CTBRangePDM4.h │ └── CTBRangePDM8.h ├── Colors │ ├── InterfaceColors_ColorR1G1B1A1X4.h │ ├── InterfaceColors_ColorR2G2B2A2.h │ ├── InterfaceColors_ColorR5G5B4A2.h │ ├── InterfaceColors_ColorR8G8B8A8.h │ ├── InterfaceColors_ColorW1X7.h │ └── InterfaceColors_ColorW8.h ├── Engine3D.h ├── Entity.h ├── Font.h ├── Graphics.h ├── GraphicsCA8Swapped.h ├── GraphicsL8CompositeSwapped.h ├── GraphicsM8CA8Swapped.h ├── GraphicsPAL8Swapped.h ├── GraphicsPALColor.h ├── GraphicsR1G1B1A1.h ├── GraphicsR1G1B1X3S2Swapped.h ├── GraphicsR2G2B2A2.h ├── GraphicsR2G2B2A2CA8Swapped.h ├── GraphicsR2G2B2S2Swapped.h ├── GraphicsR5G5B4A2.h ├── GraphicsR5G5B4S2Swapped.h ├── GraphicsTextBuffer.h ├── GraphicsW1.h ├── GraphicsW8.h ├── GraphicsW8RangedSwapped.h ├── GraphicsW8RangedSwappedPDM.h ├── GraphicsX6S2W8RangedSwapped.h ├── GraphicsX8CA8Swapped.h ├── Image.h ├── ImageDrawer.h ├── InterfaceColors.h ├── Mesh.h ├── RGB2YUV.h ├── Sprites.h ├── TriangleTree.h └── integertrigonometry.h ├── I2S ├── DMABufferDescriptor.h ├── I2S.h ├── I2S_ESP32.cpp ├── I2S_ESP8266.cpp └── lldesc.h ├── LED ├── LUT.h ├── ParallelLED.cpp ├── ParallelLED.h ├── ParallelLEDGraphics.cpp ├── ParallelLEDGraphics.h ├── SerialLED.cpp └── SerialLED.h ├── Math └── Matrix.h ├── Ressources ├── CodePage437_8x14.h ├── CodePage437_8x16.h ├── CodePage437_8x19.h ├── CodePage437_8x8.h ├── CodePage437_9x16.h ├── Font6x8.h └── Font8x8.h ├── Tools └── Log.h └── VGA ├── Mode.h ├── PinConfig.h ├── VGA.h ├── VGA14Bit.h ├── VGA14BitI.cpp ├── VGA14BitI.h ├── VGA1BitI.cpp ├── VGA1BitI.h ├── VGA3Bit.h ├── VGA3BitI.cpp ├── VGA3BitI.h ├── VGA4ColorMultimonitor.h ├── VGA6Bit.h ├── VGA6BitI.cpp ├── VGA6BitI.h ├── VGA6MonochromeVGAMadnessMultimonitor.h ├── VGA6Multimonitor.h ├── VGA8BitDAC.h ├── VGA8BitDACI.cpp ├── VGA8BitDACI.h ├── VGAI2SDynamic.h ├── VGAI2SEngine.h ├── VGAI2SOverlapping.h ├── VGAMode.cpp ├── VGAMode.h ├── VGAPinConfig.cpp ├── VGAPinConfig.h ├── VGATextI.cpp └── VGATextI.h /Documentation/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitluni/ESP32Lib/de3d73f3c68f879976a3351315b90f366dae8967/Documentation/schematic.png -------------------------------------------------------------------------------- /Documentation/schematic3bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitluni/ESP32Lib/de3d73f3c68f879976a3351315b90f366dae8967/Documentation/schematic3bit.png -------------------------------------------------------------------------------- /examples/1BitMode/1BitMode.ino: -------------------------------------------------------------------------------- 1 | //This example shows a simple "Hello world!" on a VGA screen. 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | 9 | //pin configuration 10 | const int redPin = 14; 11 | const int greenPin = 19; 12 | const int bluePin = 27; 13 | const int hsyncPin = 32; 14 | const int vsyncPin = 33; 15 | 16 | //VGA Device 17 | VGA1BitI videodisplay; 18 | 19 | const uint8_t frontColors[] = {0x2,0x0,0x1,0x4,0x1,0x7,0x3}; 20 | const uint8_t backColors[] = {0x0,0x7,0x0,0x6,0x7,0x0,0x4}; 21 | 22 | void setup() 23 | { 24 | //initializing vga at the specified pins 25 | videodisplay.init(VGAMode::MODE320x240, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 26 | //selecting the font 27 | videodisplay.setFont(Font6x8); 28 | videodisplay.setCursor(120,115); 29 | //displaying the text 30 | //default coloring 31 | videodisplay.println("Hello World!"); 32 | delay(10000); 33 | //custom coloring 34 | for(int i = 0; i < 10; i++) 35 | { 36 | videodisplay.setFrontGlobalColor(0,0,255); 37 | videodisplay.setBackGlobalColor(0,0,0); 38 | delay(500); 39 | videodisplay.setFrontGlobalColor(255,255,0); 40 | videodisplay.setBackGlobalColor(0,0,255); 41 | delay(500); 42 | } 43 | delay(2000); 44 | videodisplay.clear(); 45 | } 46 | 47 | void loop() 48 | { 49 | for(int i = 0; i < 10; i++) 50 | { 51 | videodisplay.setCursor(random(1,300),random(1,220)); 52 | videodisplay.println("Hello World!"); 53 | delay(250); 54 | } 55 | delay(1500); 56 | videodisplay.clear(); 57 | static int currentpalette = 0; 58 | videodisplay.frontGlobalColor = frontColors[currentpalette]; 59 | videodisplay.backGlobalColor = backColors[currentpalette]; 60 | currentpalette = (currentpalette + 1)%sizeof(frontColors); 61 | } 62 | -------------------------------------------------------------------------------- /examples/6BitMode/6BitMode.ino: -------------------------------------------------------------------------------- 1 | //This example shows a rendering of Julia set. Please change the pinConfig if you are using a different board to PicoVGA 2 | //cc by-sa 4.0 license 3 | //bitluni 4 | 5 | //include libraries 6 | #include 7 | #include 8 | 9 | //VGA Device 10 | VGA6Bit videodisplay; 11 | //Pin presets are avaialable for: VGAv01, VGABlackEdition, VGAWhiteEdition, PicoVGA 12 | const PinConfig &pinConfig = VGA6Bit::PicoVGA; 13 | 14 | int taskData[2][3] = 15 | { 16 | {0, 0, 160}, 17 | {0, 160, 320} 18 | }; 19 | 20 | static float v = -1.5; 21 | static float vs = 0.001; 22 | 23 | //https://en.wikipedia.org/wiki/Julia_set#Pseudocode_for_normal_Julia_sets 24 | int julia(int x, int y, float cx, float cy) 25 | { 26 | int zx = ((x - 159.5f) * (1.f / 320.f * 5.0f)) * (1 << 12); 27 | int zy = ((y - 99.5f) * (1.f / 200.f * 3.0f)) * (1 << 12); 28 | int i = 0; 29 | const int maxi = 17; 30 | int cxi = cx ; 31 | int cyi = cy * (1 << 12); 32 | while(zx * zx + zy * zy < (4 << 24) && i < maxi) 33 | { 34 | int xtemp = (zx * zx - zy * zy) >> 12; 35 | zy = ((zx * zy) >> 11) + cyi; 36 | zx = xtemp + cxi; 37 | i++; 38 | } 39 | return i; 40 | } 41 | 42 | int colors[] = { 43 | 0b110001, 0b110010, 0b110011, 0b100011, 0b010011, 44 | 0b000011, 0b000111, 0b001011, 0b001111, 0b001110, 0b001101, 45 | 0b001100, 0b011100, 0b101100, 0b111100, 0b111000, 0b110100, 46 | 0b110000}; 47 | 48 | void renderTask(void *param) 49 | { 50 | int *data = (int*)param; 51 | while(true) 52 | { 53 | while(!data[0]) delay(1); 54 | for(int y = 0; y < 100; y++) 55 | for(int x = data[1]; x < data[2]; x++) 56 | { 57 | int c = colors[julia(x, y, -0.74543f, v)]; 58 | videodisplay.dotFast(x, y, c); 59 | videodisplay.dotFast(319 - x, 199 - y, c); 60 | } 61 | data[0] = 0; 62 | } 63 | } 64 | 65 | //initial setup 66 | void setup() 67 | { 68 | //initializing i2s vga (with only one framebuffer) 69 | videodisplay.init(VGAMode::MODE320x200, pinConfig); 70 | TaskHandle_t xHandle = NULL; 71 | xTaskCreatePinnedToCore(renderTask, "Render1", 2000, taskData[0], ( 2 | portPRIVILEGE_BIT ), &xHandle, 0); 72 | xTaskCreatePinnedToCore(renderTask, "Render2", 2000, taskData[1], ( 2 | portPRIVILEGE_BIT ), &xHandle, 1); 73 | } 74 | 75 | //just draw each frame 76 | void loop() 77 | { 78 | static unsigned long ot = 0; 79 | unsigned long t = millis(); 80 | unsigned long dt = t - ot; 81 | ot = t; 82 | taskData[0][0] = 1; 83 | taskData[1][0] = 1; 84 | //waiting for task to finish 85 | while(taskData[0][0] || taskData[1][0]) delay(1); 86 | v += vs * dt; 87 | if(v > 1.5f) 88 | { 89 | v = 1.5f; 90 | vs = -vs; 91 | } 92 | if(v < -1.5f) 93 | { 94 | v = -1.5f; 95 | vs = -vs; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/8BitDACMode/8BitDACMode.ino: -------------------------------------------------------------------------------- 1 | //You need to connect a VGA screen cable to the pins specified below. 2 | //cc by-sa 4.0 license 3 | //Martin-Laclaustra 4 | /* 5 | CONNECTION 6 | 7 | A) voltageDivider = false; B) voltageDivider = true (last init parameter) 8 | 9 | 55 shades 255 shades 10 | 11 | ESP32 VGA ESP32 VGA 12 | -----+ -----+ ____ 100 ohm 13 | G|- +---- R G|---|____|+ +---- R 14 | pin25|----+---- G pin25|---|____|+---------+---- G 15 | pin26|- +---- B pin26|- 220 ohm +---- B 16 | pin X|--------- HSYNC pin X|------------------------ HSYNC 17 | pin Y|--------- VSYNC pin Y|------------------------ VSYNC 18 | -----+ -----+ 19 | 20 | Connect pin 25 or 26 21 | Connect the 3 channels in parallel or whatever combination of them 22 | depending on the monochrome color of choice 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | //pin configuration 29 | const int outputPin = 25; 30 | const int hsyncPin = 16; 31 | const int vsyncPin = 4; 32 | 33 | VGA8BitDAC videodisplay; 34 | 35 | void setup() 36 | { 37 | //initializing vga at the specified pins 38 | //output pin and boolean for voltage divider can be omitted 39 | videodisplay.init(VGAMode::MODE320x240, hsyncPin, vsyncPin, outputPin, false); 40 | //selecting the font 41 | videodisplay.setFont(Font6x8); 42 | //displaying the test pattern 43 | videodisplay.rect(30, 88, 255+5, 40+4, 127); 44 | for(int x = 0; x < 256; x++) 45 | { 46 | videodisplay.fillRect(x + 32, 90, 1, 40, x); 47 | if(x % 16 == 0) 48 | { 49 | videodisplay.fillRect(x + 32, 85, 1, 4, 255); 50 | videodisplay.setCursor(x + 32 - 3, 78); 51 | videodisplay.print(x,HEX); 52 | } 53 | } 54 | } 55 | 56 | void loop() 57 | { 58 | } 59 | -------------------------------------------------------------------------------- /examples/CompositeDACMode/CompositeDACMode.ino: -------------------------------------------------------------------------------- 1 | //You need to connect a composite TV input cable to the pins specified below. 2 | //cc by-sa 4.0 license 3 | //Martin-Laclaustra 4 | /* 5 | CONNECTION 6 | 7 | A) voltageDivider = false; B) voltageDivider = true 8 | 9 | 55 shades 179 shades 10 | 11 | ESP32 TV ESP32 TV 12 | -----+ -----+ ____ 100 ohm 13 | G|- G|---|____|+ 14 | pin25|--------- Comp pin25|---|____|+--------- Comp 15 | pin26|- pin26|- 220 ohm 16 | | | 17 | | | 18 | -----+ -----+ 19 | 20 | Connect pin 25 or 26 21 | 22 | C) R–2R resistor ladder; D) unequal rungs ladder 23 | 24 | 55 shades up to 254 shades? 25 | 26 | ESP32 TV ESP32 TV 27 | -----+ -----+ ____ 28 | G|-+_____ G|---|____| 29 | pinA0|-| R2R |- Comp pinA0|---|____|+--------- Comp 30 | pinA1|-| | pinA1|---|____| 31 | pinA2|-| | ...| 32 | ...|-|_____| | 33 | -----+ -----+ 34 | 35 | Connect pins of your choice (A0...A8=any pins). 36 | Custom ladders can be used by tweaking colorMinValue and colorMaxValue 37 | */ 38 | 39 | #include 40 | #include 41 | 42 | //pin configuration for DAC 43 | const int outputPin = 25; 44 | 45 | CompositeGrayDAC videodisplay; 46 | //CompositeGrayLadder videodisplay; 47 | 48 | void setup() 49 | { 50 | //initializing composite at the specified pins 51 | //output pin and boolean for voltage divider can be omitted 52 | //see Composite/CompMode.h for other modes 53 | videodisplay.init(CompMode::MODEPAL288P, 25, false); 54 | //videodisplay.init(CompMode::MODEPAL288P, videodisplay.XPlayer); 55 | 56 | //selecting the font 57 | videodisplay.setFont(Font6x8); 58 | //displaying the test pattern 59 | videodisplay.rect(30, 88, 255+5, 40+4, 127); 60 | for(int x = 0; x < 256; x++) 61 | { 62 | videodisplay.fillRect(x + 32, 90, 1, 40, x); 63 | if(x % 16 == 0) 64 | { 65 | videodisplay.fillRect(x + 32, 85, 1, 4, 255); 66 | videodisplay.setCursor(x + 32 - 3, 78); 67 | videodisplay.print(x,HEX); 68 | } 69 | } 70 | } 71 | 72 | void loop() 73 | { 74 | } 75 | -------------------------------------------------------------------------------- /examples/GFXWrapper/GFXWrapper.ino: -------------------------------------------------------------------------------- 1 | //This example shows how to use the GfxWrapper to be able to use the Adafruit GFX library with VGA 2 | //cc by-sa 4.0 license 3 | //bitluni 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //VGA Device 12 | VGA6Bit videodisplay; 13 | GfxWrapper gfx(videodisplay, 640, 400); 14 | 15 | //initial setup 16 | void setup() 17 | { 18 | //initializing i2s vga (with only one framebuffer) 19 | //Pin presets are avaialable for: VGAv01, VGABlackEdition, VGAWhiteEdition, PicoVGA 20 | //But you can also use custom pins. Check the other examples 21 | videodisplay.init(VGAMode::MODE640x400, videodisplay.VGABlackEdition); 22 | //using adafruit gfx 23 | gfx.setFont(&FreeMonoBoldOblique24pt7b); 24 | gfx.setCursor(100, 100); 25 | gfx.print("Hello"); 26 | } 27 | 28 | //the loop is done every frame 29 | void loop() 30 | { 31 | 32 | } 33 | -------------------------------------------------------------------------------- /examples/LEDs/LEDWall3Camera/LEDWall3Camera.ino: -------------------------------------------------------------------------------- 1 | //example for parallel LEDs not using the graphics interface 2 | //using the library 3 | #include 4 | #include "camera.h" 5 | #include "tools.h" 6 | 7 | ParallelLED gfx(4); //four color components for RGBW 8 | 9 | volatile bool frameAvailable = false; 10 | #include "effects.h" 11 | 12 | void setup() 13 | { 14 | Serial.begin(115200); 15 | cameraInit(); 16 | setCameraParams(); 17 | gfx.setGamma(3.2f, 2.0f, 4.0f, 3.2f); //gamma adjustment 18 | const int pins[] = {16, 12, 13, 15, 14, 2, -1, -1}; 19 | gfx.init(pins, 8 * 40); //8 x 40 LEDs per channel (8 channels total, here only 6 used) 20 | } 21 | 22 | void loop() 23 | { 24 | camera_fb_t * fb = esp_camera_fb_get(); 25 | if (fb) 26 | { 27 | downSample(fb->buf); //fb->width, fb->height, fb->format, fb->buf, fb->len 28 | frameAvailable = true; 29 | esp_camera_fb_return(fb); 30 | }; 31 | if(frameAvailable) 32 | { 33 | processImage(); 34 | frameAvailable = false; 35 | } 36 | } -------------------------------------------------------------------------------- /examples/LEDs/LEDWall3Camera/effects.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | unsigned char newImage[40][48][3]; 4 | 5 | void downSample(unsigned char *frame) 6 | { 7 | //160x120 8 | for(int y = 0; y < 40; y++) 9 | { 10 | for(int x = 0; x < 48; x++) 11 | { 12 | int r = 0; 13 | int g = 0; 14 | int b = 0; 15 | for(int j = 0; j < 3; j++) 16 | for(int i = 0; i < 3; i++) 17 | { 18 | unsigned char p[3]; 19 | getPixel(8 + x * 3 + i, y * 3 + j, frame, p); 20 | r += p[0]; 21 | g += p[1]; 22 | b += p[2]; 23 | } 24 | newImage[y][x][0] = (r * (256 / 9)) >> 8; 25 | newImage[y][x][1] = (g * (256 / 9)) >> 8; 26 | newImage[y][x][2] = (b * (256 / 9)) >> 8; 27 | } 28 | } 29 | } 30 | 31 | void showImage() 32 | { 33 | for(int y = 0; y < 40; y++) 34 | for(int x = 0; x < 48; x++) 35 | { 36 | int channel = 0, led = 0; 37 | pixelMap(x, y, channel, led); 38 | gfx.setLED(channel, led, newImage[y][x][1], newImage[y][x][0], newImage[y][x][2], 0); 39 | } 40 | gfx.show(); 41 | } 42 | 43 | 44 | void processImage() 45 | { 46 | showImage(); 47 | } -------------------------------------------------------------------------------- /examples/LEDs/LEDWall3Camera/tools.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | long sinTab[256]; 4 | 5 | void calculateSinTab() 6 | { 7 | for(int i = 0; i < 256; i++) 8 | { 9 | sinTab[i] = int(sin(M_PI / 128.f * i) * 256); 10 | } 11 | } 12 | 13 | float smoothstep(float x) 14 | { 15 | x = max(0.f, min(x, 1.f)); 16 | return (3 * x * x) - (2 * x * x * x); 17 | } 18 | 19 | float rsqrt(float number) 20 | { 21 | long i; 22 | float x2, y; 23 | const float threehalfs = 1.5F; 24 | 25 | x2 = number * 0.5F; 26 | y = number; 27 | i = * ( long * ) &y; // evil floating point bit level hacking 28 | i = 0x5f3759df - ( i >> 1 ); // what the fuck? 29 | y = * ( float * ) &i; 30 | y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration 31 | y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed 32 | return y; 33 | } 34 | 35 | int rainbow[256][3]; 36 | void calcRainbow() 37 | { 38 | const float cb[][3] = {{1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 1}, {0, 0, 1}, {1, 0, 1}}; 39 | for (int i = 0; i < 256; i++) 40 | { 41 | //interpolate the colors from the cb array and calculate the R5G5B5 color 42 | float s = 6.f / 256 * i; 43 | int n = int(s); 44 | float f = s - n; 45 | float fi = (1 - f); 46 | const float *cf = cb[n]; 47 | const float *cfn = cb[(n + 1) % 6]; 48 | int r = int((fi * cf[0] * 255) + (f * cfn[0] * 255)); 49 | int g = int((fi * cf[1] * 255) + (f * cfn[1] * 255)); 50 | int b = int((fi * cf[2] * 255) + (f * cfn[2] * 255)); 51 | rainbow[i][0] = r; 52 | rainbow[i][1] = g; 53 | rainbow[i][2] = b; 54 | } 55 | } 56 | 57 | float rdist(int x, int y, float x2, float y2) 58 | { 59 | return rsqrt((x - x2) * (x - x2) + (y - y2) * (y - y2) + 1); 60 | } 61 | 62 | float dist(int x, int y, float x2, float y2) 63 | { 64 | return sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2)); 65 | } 66 | 67 | void getPixel(int x, int y, unsigned char *image, unsigned char *pixel) 68 | { 69 | int p = image[(y * 160 + x) * 2 + 1] | (image[(y * 160 + x) * 2] << 8); 70 | pixel[0] = (p >> 11) << 3; 71 | pixel[1] = ((p >> 5) & 0b111111) << 2; 72 | pixel[2] = (p & 0b11111) << 3; 73 | } 74 | 75 | bool pixelMap(int x, int y, int &channel, int &led) 76 | { 77 | if(x < 0 || x >= 48 || y < 0 || y >= 40) 78 | return false; 79 | channel = x >> 3; 80 | led = (x & 7) + y * 8; 81 | return true; 82 | } 83 | -------------------------------------------------------------------------------- /examples/LEDs/NyanCat/NyanCat.ino: -------------------------------------------------------------------------------- 1 | //include libraries 2 | #include 3 | 4 | //include the sprites converted the SpriteConverter. It's an html found in the utilities folder of the library 5 | #include "nyan.h" 6 | 7 | //To know where all the pixels are you need to implement a class with the function map like here: 8 | class LEDWall3: public ParallelLEDGraphics 9 | { 10 | public: 11 | LEDWall3() 12 | :ParallelLEDGraphics(48, 40, 4) 13 | { 14 | } 15 | 16 | //this function maps from x,y to channel and led number. channel, and led are return parameters 17 | virtual bool map(int x, int y, int &channel, int &led) 18 | { 19 | //no checks in this example needed 20 | //if(x < 0 || x >= 48 || y < 0 || y >= 40) 21 | //return false; 22 | channel = x >> 3; 23 | led = (x & 7) + y * 8; 24 | return true; 25 | } 26 | }; 27 | 28 | LEDWall3 gfx; 29 | 30 | //initial setup 31 | void setup() 32 | { 33 | const int pins[] = {16, 12, 13, 15, 14, 2, -1, -1}; 34 | gfx.init(pins, 8 * 40); 35 | gfx.setGamma(3.2f, 2.0f, 4.0f, 3.2f); //color adjustment for LED displays 36 | } 37 | 38 | //just draw each frame 39 | void loop() 40 | { 41 | static int i = 0; 42 | i = (i + 1) % 6; //circulate the 6 sprites 43 | nyan.draw(gfx, i, 24, 20); 44 | gfx.show(); 45 | delay(50); 46 | } 47 | -------------------------------------------------------------------------------- /examples/Raytracer/Raytracer.h: -------------------------------------------------------------------------------- 1 | //cc by-sa 4.0 license 2 | //bitluni 3 | #pragma once 4 | 5 | class Ray 6 | { 7 | public: 8 | Ray(Vector pos, Vector dir) 9 | :p(pos), d(dir) 10 | { 11 | } 12 | Vector p; 13 | Vector d; 14 | }; 15 | 16 | class Raytracable 17 | { 18 | public: 19 | float reflection; 20 | Vector c; 21 | Raytracable() 22 | { 23 | reflection = 0; 24 | } 25 | virtual bool intersection(Ray &ray, Vector &i, float &t) const = 0; 26 | virtual Vector normal(Vector &i) const = 0; 27 | virtual Vector color(Vector &p) const = 0; 28 | }; 29 | 30 | class Sphere : public Raytracable 31 | { 32 | public: 33 | float r; 34 | float r2; 35 | Vector p; 36 | Sphere(Vector pos, float radius) 37 | : 38 | r(radius), 39 | r2(radius * radius), 40 | p(pos) 41 | { 42 | } 43 | 44 | virtual bool intersection(Ray &ray, Vector &i, float &t) const 45 | { 46 | Vector L = p - ray.p; 47 | float tca = L.dot(ray.d); 48 | if(tca < 0) return false; 49 | float d2 = L.dot(L) - tca * tca; 50 | if (d2 >= r2) return false; 51 | float thc = Vector::sqrt(r2 - d2); 52 | float ct = tca - thc; 53 | if(t <= ct) return false; 54 | t = ct; 55 | i = ray.p + ray.d * ct; 56 | return true; 57 | } 58 | 59 | virtual Vector normal(Vector &i) const 60 | { 61 | return (i - p) * (1.f / r); 62 | } 63 | 64 | virtual Vector color(Vector &p) const 65 | { 66 | return c; 67 | } 68 | }; 69 | 70 | class Checker : public Raytracable 71 | { 72 | public: 73 | Checker() 74 | { 75 | } 76 | 77 | virtual bool intersection(Ray &ray, Vector &i, float &t) const 78 | { 79 | if(ray.d[1] >= 0 || ray.p[1] <= 0) return false; 80 | float ct = ray.p[1] / -ray.d[1]; 81 | if(ct >= t) return false; 82 | i = Vector(ray.p[0] + ray.d[0] * ct, 0, ray.p[2] + ray.d[2] * ct); 83 | t = ct; 84 | return true; 85 | } 86 | 87 | virtual Vector normal(Vector &i) const 88 | { 89 | return Vector(0, 1, 0); 90 | } 91 | 92 | virtual Vector color(Vector &p) const 93 | { 94 | float c = ((int)p[0] + (int)p[2] + (p[0] >= 0 ? 1 : 0)) & 1; 95 | return Vector(0.8 + 0.2 * c, c, c); 96 | } 97 | }; 98 | 99 | const float FAR = 10000; 100 | Vector raytrace(Raytracable **objects, int count, Ray &r, Vector &light, int depth, Raytracable *self = 0) 101 | { 102 | if(depth == 0) 103 | return Vector(0, 0, 0); 104 | Vector i; 105 | float t = FAR; 106 | Raytracable *best = 0; 107 | for(int n = 0; n < count; n++) 108 | { 109 | Raytracable *o = objects[n]; 110 | if(o != self && o->intersection(r, i, t)) 111 | best = o; 112 | } 113 | float fog = t * 0.02f; 114 | float fc = 0.5f - (r.d[1] < 0 ? 0 : r.d[1]) * 0.5; 115 | Vector fogc = Vector(fc, fc, 1.0f); 116 | if(fog >= 1) return fogc; 117 | if(!best) 118 | { 119 | return fogc; 120 | } 121 | Vector n = best->normal(i); 122 | float l = light.dot(n) * 0.9; 123 | if(l < 0) 124 | l = 0; 125 | else 126 | { 127 | Ray r2(i, light); 128 | Vector i2; 129 | float t2 = FAR; 130 | for(int n = 0; n < count; n++) 131 | { 132 | Raytracable *o = objects[n]; 133 | if(o == best) continue; 134 | if(o->intersection(r2, i2, t2)) 135 | { 136 | l = 0; 137 | break; 138 | } 139 | } 140 | } 141 | Vector c = (best->color(i) * (0.1f + l)) * (1 - fog) + fogc * fog; 142 | if(best->reflection == 0) 143 | return c; 144 | float dn = r.d.dot(n); 145 | float fr = (0.2f + (1+dn) * 0.8f) * best->reflection; 146 | if(fr < 0) fr = 0; 147 | Vector refl = r.d - n * (dn * 2); 148 | Ray nr = Ray(i, refl); 149 | //return Vector(fr, fr, fr); 150 | c = raytrace(objects, count, nr, light, depth - 1, best) * fr + c * (1 - fr); 151 | return c; 152 | } 153 | -------------------------------------------------------------------------------- /examples/Raytracer/Raytracer.ino: -------------------------------------------------------------------------------- 1 | //A realtime raytraycer utilizing both cores of the ESP32. Please change the pin configuration in the setup if you are not using VGA v0.1 or the Black Edition shields. 2 | //cc by-sa 4.0 license 3 | //bitluni 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Raytracer.h" 10 | 11 | //VGA Device 12 | VGA14Bit videodisplay; 13 | 14 | int taskData[2][3] = 15 | { 16 | {0, 0, 160}, 17 | {0, 160, 320} 18 | }; 19 | 20 | static Sphere sphere(Vector(0, 0.5f, 0), 1); 21 | static Sphere sphere2(Vector(1, 1.5f, 0.5), 0.5f); 22 | static Checker checker; 23 | static Raytracable *objects[] = {&sphere, &sphere2, &checker}; 24 | static Vector light = Vector(5, 4, -5); 25 | 26 | void raytraceTask(void *param) 27 | { 28 | static Vector p(0, 1, -10); 29 | int *data = (int*)param; 30 | while(true) 31 | { 32 | while(!data[0]) delay(1); 33 | for(int y = 0; y < 200; y++) 34 | for(int x = data[1]; x < data[2]; x++) 35 | { 36 | Vector v(float(x - 160) * (1.f / 320), float(100 - y) * (1.f / 320), 1.f); 37 | v.normalize(); 38 | Ray r(p, v); 39 | Vector c = raytrace(objects, 3, r, light, 3); 40 | videodisplay.dotFast(x, y, videodisplay.RGB(c[0] * 255, c[1] * 255, c[2] * 255)); 41 | } 42 | data[0] = 0; 43 | } 44 | } 45 | 46 | //initial setup 47 | void setup() 48 | { 49 | //we need double buffering for smooth animations 50 | videodisplay.setFrameBufferCount(2); 51 | //initializing i2s vga 52 | //Pin presets are avaialable for: VGAv01, VGABlackEdition, VGAWhiteEdition, PicoVGA 53 | //But you can also use custom pins. Check the other examples 54 | videodisplay.init(VGAMode::MODE320x200, videodisplay.VGABlackEdition); 55 | //setting the font 56 | videodisplay.setFont(Font6x8); 57 | light.normalize(); 58 | sphere.reflection = 0.4f; 59 | sphere2.reflection = 0.5f; 60 | checker.reflection = 0.2f; 61 | sphere.c = Vector(0, 1, 0); 62 | sphere2.c = Vector(1, 0, 1); 63 | static uint8_t ucParameterToPass; 64 | TaskHandle_t xHandle = NULL; 65 | xTaskCreatePinnedToCore(raytraceTask, "Raytracer1", 2000, taskData[0], ( 2 | portPRIVILEGE_BIT ), &xHandle, 0); 66 | xTaskCreatePinnedToCore(raytraceTask, "Raytracer2", 2000, taskData[1], ( 2 | portPRIVILEGE_BIT ), &xHandle, 1); 67 | } 68 | 69 | //the loop is done every frame 70 | void loop() 71 | { 72 | taskData[0][0] = 1; 73 | taskData[1][0] = 1; 74 | //waiting for task to finish 75 | while(taskData[0][0] || taskData[1][0]) delay(1); 76 | sphere2.p.v[0] = sin(millis() * 0.0005f) * 2; 77 | sphere2.p.v[2] = cos(millis() * 0.0005f) * 2; 78 | sphere.p.v[1] = sphere2.p[0] * 0.3 + 1; 79 | //setting the text cursor to the lower left corner of the screen 80 | videodisplay.setCursor(0, 0); 81 | //setting the text color to white with opaque black background 82 | videodisplay.setTextColor(videodisplay.RGB(0xffffff), videodisplay.RGBA(0, 0, 0, 0)); 83 | //printing the fps 84 | videodisplay.print("ms/frame: "); 85 | static long t = 0; 86 | long ct = millis(); 87 | videodisplay.print(ct - t); 88 | t = ct; 89 | videodisplay.show(); 90 | } 91 | -------------------------------------------------------------------------------- /examples/TextMode/TextMode.ino: -------------------------------------------------------------------------------- 1 | //This example shows a simple "Hello world!" on a VGA screen. 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | 9 | //pin configuration 10 | const int redPin = 14; 11 | const int greenPin = 19; 12 | const int bluePin = 27; 13 | const int hsyncPin = 32; 14 | const int vsyncPin = 33; 15 | 16 | //VGA Device 17 | VGATextI videodisplay; 18 | 19 | const uint8_t frontColors[] = {0x2,0x0,0x1,0x4,0x1,0x7,0x3}; 20 | const uint8_t backColors[] = {0x0,0x7,0x0,0x6,0x7,0x0,0x4}; 21 | 22 | void setup() 23 | { 24 | //selecting the font 25 | //IMPORTANT: for text mode this MUST be done BEFORE init 26 | // and font can not be changed after init 27 | videodisplay.setFont(Font6x8); 28 | //initializing vga at the specified pins 29 | videodisplay.init(VGAMode::MODE320x240, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 30 | videodisplay.setCursor(videodisplay.xres/2-6,videodisplay.yres/2-1); 31 | //displaying the text 32 | //default coloring 33 | videodisplay.println("Hello World!"); 34 | delay(10000); 35 | //custom coloring 36 | for(int i = 0; i < 10; i++) 37 | { 38 | videodisplay.setFrontGlobalColor(0,0,255); 39 | videodisplay.setBackGlobalColor(0,0,0); 40 | delay(500); 41 | videodisplay.setFrontGlobalColor(255,255,0); 42 | videodisplay.setBackGlobalColor(0,0,255); 43 | delay(500); 44 | } 45 | delay(2000); 46 | videodisplay.clear(); 47 | } 48 | 49 | void loop() 50 | { 51 | for(int i = 0; i < 10; i++) 52 | { 53 | videodisplay.setCursor(random(1,videodisplay.xres-6),random(1,videodisplay.yres-1)); 54 | videodisplay.println("Hello World!"); 55 | delay(250); 56 | } 57 | delay(1500); 58 | videodisplay.clear(); 59 | static int currentpalette = 0; 60 | videodisplay.frontGlobalColor = frontColors[currentpalette]; 61 | videodisplay.backGlobalColor = backColors[currentpalette]; 62 | currentpalette = (currentpalette + 1)%sizeof(frontColors); 63 | } 64 | -------------------------------------------------------------------------------- /examples/VGA3DEngine/VGA3DEngine.ino: -------------------------------------------------------------------------------- 1 | //This example displays a 3D model on a VGA screen. Double buffering is used to avoid flickering. 2 | //You need to connect a VGA screen cable and an external DAC (simple R2R does the job) to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | //include libraries 7 | #include 8 | #include 9 | 10 | //include model 11 | #include "thinker.h" 12 | Mesh model(thinker::vertexCount, thinker::vertices, 0, 0, thinker::triangleCount, thinker::triangles, thinker::triangleNormals); 13 | 14 | //pin configuration 15 | const int redPins[] = {2, 4, 12, 13, 14}; 16 | const int greenPins[] = {15, 16, 17, 18, 19}; 17 | const int bluePins[] = {21, 22, 23, 27}; 18 | const int hsyncPin = 32; 19 | const int vsyncPin = 33; 20 | 21 | //VGA Device 22 | VGA14Bit videodisplay; 23 | //3D engine 24 | Engine3D engine(1337); 25 | 26 | //initial setup 27 | void setup() 28 | { 29 | //need double buffering 30 | videodisplay.setFrameBufferCount(2); 31 | //initializing i2s vga 32 | videodisplay.init(VGAMode::MODE200x150, redPins, greenPins, bluePins, hsyncPin, vsyncPin); 33 | //setting the font 34 | videodisplay.setFont(Font6x8); 35 | } 36 | 37 | ///a colorful triangle shader actually calculated per triangle 38 | VGA14Bit::Color myTriangleShader(int trinangleNo, short *v0, short *v1, short *v2, const signed char *normal, VGA14Bit::Color color) 39 | { 40 | //normals packed in 1 signed byte per axis 41 | const float scaleN = 1.0f / 127.0f; 42 | const float nx = normal[0] * scaleN; 43 | const float ny = normal[1] * scaleN; 44 | const float nz = normal[2] * scaleN; 45 | //return R5G5B4 color each normal axis controls each color component 46 | return (int(15 * nx + 16)) | (int(15 * nz + 16) << 5) | (int(7 * ny + 8) << 10); 47 | } 48 | 49 | //render 3d model 50 | void drawModel() 51 | { 52 | //perspective transformation 53 | static Matrix perspective = Matrix::translation(videodisplay.xres / 2, videodisplay.yres / 2, 0) * Matrix::scaling(100 * videodisplay.pixelAspect(), 100, 100) * Matrix::perspective(90, 1, 10); 54 | static float u = 0; 55 | u += 0.02; 56 | //rotate model 57 | Matrix rotation = Matrix::rotation(-1.7, 1, 0, 0) * Matrix::rotation(u, 0, 0, 1); 58 | Matrix m0 = perspective * Matrix::translation(0, 1.7 * 0, 7) * rotation * Matrix::scaling(7); 59 | //transform the vertices and normals 60 | model.transform(m0, rotation); 61 | //begin adding triangles to render pipeline 62 | engine.begin(); 63 | //add this model to the render pipeline. it will sort the triangles from back to front and remove backfaced. The tiangle shader will determine the color of the tirangle. 64 | //the RGB color gien in the second parameter is not used in this case but could be used for calculations in the triangle shader 65 | model.drawTriangles(engine, videodisplay.RGB(128, 70, 20), myTriangleShader); 66 | //render all triangles in the pipeline. if you render multiple models you want to do this once at the end 67 | engine.end(videodisplay); 68 | } 69 | 70 | //just draw each frame 71 | void loop() 72 | { 73 | //calculate the milliseconds passed from last pass 74 | static int lastMillis = 0; 75 | int t = millis(); 76 | //calculate fps (smooth) 77 | static float oldFps = 0; 78 | float fps = oldFps * 0.9f + 100.f / (t - lastMillis); 79 | oldFps = fps; 80 | lastMillis = t; 81 | //clear the back buffer 82 | videodisplay.clear(0); 83 | //draw the model 84 | drawModel(); 85 | //reset the text cursor 86 | videodisplay.setCursor(0, 0); 87 | //print the stats 88 | videodisplay.print("fps: "); 89 | videodisplay.print(fps, 1, 4); 90 | videodisplay.print(" tris/s: "); 91 | videodisplay.print(int(fps * model.triangleCount)); 92 | videodisplay.show(); 93 | } 94 | -------------------------------------------------------------------------------- /examples/VGACustomResolution/VGACustomResolution.ino: -------------------------------------------------------------------------------- 1 | //This example shows how a custom VGA resolution can be created for one of the base modes 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | //including the needed header 7 | #include 8 | #include 9 | 10 | //pin configuration 11 | const int redPin = 14; 12 | const int greenPin = 19; 13 | const int bluePin = 27; 14 | const int hsyncPin = 32; 15 | const int vsyncPin = 33; 16 | 17 | //VGA Device using an interrupt to unpack the pixels from 4bit to 16bit for the I²S 18 | //This takes some CPU time in the background but is able to fit a frame buffer in the memory 19 | VGA3Bit videodisplay; 20 | 21 | void setup() 22 | { 23 | Serial.begin(115200); 24 | //enabling double buffering 25 | videodisplay.setFrameBufferCount(2); 26 | //Mode::custom(xres, yres, fixedYDivider = 1) calculates the parameters for our custom resolution. 27 | //the y resolution is only scaling integer divisors (yet). 28 | //if you don't like to let it scale automatically pass a fixed parameter with a fixed divider. 29 | Mode myMode = VGAMode::MODE640x480.custom(80, 60); 30 | //print the parameters 31 | myMode.print(Serial); 32 | //use the mode 33 | videodisplay.init(myMode, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 34 | //setting the font 35 | videodisplay.setFont(Font6x8); 36 | } 37 | 38 | ///draws a bouncing balls 39 | void balls() 40 | { 41 | //some basic gravity physics 42 | static VGA3BitI::Color c[4] = {videodisplay.RGB(0, 255, 0), videodisplay.RGB(0, 255, 255), videodisplay.RGB(255, 0, 255), videodisplay.RGB(255, 255, 0)}; 43 | static float y[4] = {20, 20, 20, 20}; 44 | static float x[4] = {20, 20, 20, 20}; 45 | static float vx[4] = {.01, -0.07, .05, -.03}; 46 | static float vy[4] = {0, 1, 2, 3}; 47 | static unsigned long lastT = 0; 48 | unsigned long t = millis(); 49 | float dt = (t - lastT) * 0.001f; 50 | lastT = t; 51 | const int r = 6; 52 | for (int i = 0; i < 4; i++) 53 | { 54 | int rx = r; 55 | int ry = r; 56 | vy[i] += -9.81f * dt * 100; 57 | x[i] += vx[i]; 58 | y[i] += vy[i] * dt; 59 | //check for boundaries and bounce back 60 | if (y[i] < r && vy[i] < 0) 61 | { 62 | vy[i] = 200 + i * 10; 63 | ry = y[i]; 64 | } 65 | if (x[i] < r && vx[i] < 0) 66 | { 67 | vx[i] = -vx[i]; 68 | rx = x[i]; 69 | } 70 | if (x[i] >= videodisplay.xres - r && vx[i] > 0) 71 | { 72 | vx[i] = -vx[i]; 73 | rx = videodisplay.xres - x[i]; 74 | } 75 | //draw a filled ellipse 76 | videodisplay.fillEllipse(x[i], videodisplay.yres - y[i] - 1, rx, ry, c[i]); 77 | videodisplay.ellipse(x[i], videodisplay.yres - y[i] - 1, rx, ry, 0); 78 | } 79 | } 80 | 81 | //mainloop 82 | void loop() 83 | { 84 | //draw a background 85 | for (int y = 0; y * 10 < videodisplay.yres; y++) 86 | for (int x = 0; x * 10 < videodisplay.xres; x++) 87 | videodisplay.fillRect(x * 10, y * 10, 10, 10, (x + y) & 1 ? videodisplay.RGB(255, 0, 0) : videodisplay.RGB(255, 255, 255)); 88 | //text position 89 | videodisplay.setCursor(2, 2); 90 | //black text color no background color 91 | videodisplay.setTextColor(videodisplay.RGB(0)); 92 | //show the remaining memory 93 | videodisplay.print(videodisplay.xres); 94 | videodisplay.print("x"); 95 | videodisplay.println(videodisplay.yres); 96 | videodisplay.print("free memory: "); 97 | videodisplay.print((int)heap_caps_get_free_size(MALLOC_CAP_DEFAULT)); 98 | //draw bouncing balls 99 | balls(); 100 | //show the backbuffer (only needed when using backbuffering) 101 | videodisplay.show(); 102 | } 103 | -------------------------------------------------------------------------------- /examples/VGADemo14Bit/VGADemo14Bit.ino: -------------------------------------------------------------------------------- 1 | //This example shows how to animate graphics on a VGA screen. No backbuffering is used... just try it. 2 | //You need to connect a VGA screen cable and an external DAC (simple R2R does the job) to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | //pin configuration 11 | const int redPins[] = {2, 4, 12, 13, 14}; 12 | const int greenPins[] = {15, 16, 17, 18, 19}; 13 | const int bluePins[] = {21, 22, 23, 27}; 14 | const int hsyncPin = 32; 15 | const int vsyncPin = 33; 16 | 17 | //VGA Device 18 | VGA14Bit videodisplay; 19 | 20 | //initial setup 21 | void setup() 22 | { 23 | //initializing i2s vga (with only one framebuffer) 24 | videodisplay.init(VGAMode::MODE200x150, redPins, greenPins, bluePins, hsyncPin, vsyncPin); 25 | //setting the font 26 | videodisplay.setFont(Font6x8); 27 | } 28 | 29 | //the loop is done every frame 30 | void loop() 31 | { 32 | //setting the text cursor to the lower left corner of the screen 33 | videodisplay.setCursor(0, videodisplay.yres - 8); 34 | //setting the text color to white with opaque black background 35 | videodisplay.setTextColor(videodisplay.RGB(0xffffff), videodisplay.RGBA(0, 0, 0, 255)); 36 | //printing the fps 37 | videodisplay.print("fps: "); 38 | static long f = 0; 39 | videodisplay.print(long((f++ * 1000) / millis())); 40 | 41 | //circle parameters 42 | float factors[][2] = {{1, 1.1f}, {0.9f, 1.02f}, {1.1, 0.8}}; 43 | int colors[] = {videodisplay.RGB(0xff0000), videodisplay.RGB(0x00ff00), videodisplay.RGB(0x0000ff)}; 44 | //animate them with milliseconds 45 | float p = millis() * 0.002f; 46 | for (int i = 0; i < 3; i++) 47 | { 48 | //calculate the position 49 | int x = videodisplay.xres / 2 + sin(p * factors[i][0]) * videodisplay.xres / 3; 50 | int y = videodisplay.yres / 2 + cos(p * factors[i][1]) * videodisplay.yres / 3; 51 | //clear the center with a black filled circle 52 | videodisplay.fillCircle(x, y, 8, 0); 53 | //draw the circle with the color from the array 54 | videodisplay.circle(x, y, 10, colors[i]); 55 | } 56 | //render the flame effect 57 | for (int y = 0; y < videodisplay.yres - 9; y++) 58 | for (int x = 1; x < videodisplay.xres - 1; x++) 59 | { 60 | //take the avarage from the surrounding pixels below 61 | int c0 = videodisplay.get(x, y); 62 | int c1 = videodisplay.get(x, y + 1); 63 | int c2 = videodisplay.get(x - 1, y + 1); 64 | int c3 = videodisplay.get(x + 1, y + 1); 65 | int r = ((c0 & 0x1f) + (c1 & 0x1f) + ((c2 & 0x1f) + (c3 & 0x1f)) / 2) / 3; 66 | int g = (((c0 & 0x3e0) + (c1 & 0x3e0) + ((c2 & 0x3e0) + (c3 & 0x3e0)) / 2) / 3) & 0x3e0; 67 | int b = (((c0 & 0x3c00) + (c1 & 0x3c00) + ((c2 & 0x3c00) + (c3 & 0x3c00)) / 2) / 3) & 0x3c00; 68 | //draw the new pixel 69 | videodisplay.dotFast(x, y, r | g | b); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /examples/VGAFonts/VGAFonts.ino: -------------------------------------------------------------------------------- 1 | //This example shows how to use different fonts on a VGA screen. 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | //pin configuration 15 | const int redPin = 14; 16 | const int greenPin = 19; 17 | const int bluePin = 27; 18 | const int hsyncPin = 32; 19 | const int vsyncPin = 33; 20 | 21 | //VGA Device 22 | VGA3Bit videodisplay; 23 | 24 | void setup() 25 | { 26 | //initializing vga at the specified pins 27 | videodisplay.init(VGAMode::MODE640x400, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 28 | //selecting the font 29 | videodisplay.setFont(Font6x8); 30 | //set color 31 | videodisplay.setTextColor(videodisplay.RGB(255, 0, 0), videodisplay.RGB(0, 0, 255)); 32 | //displaying the character set 33 | videodisplay.println("Font6x8"); 34 | for (int i = 0; i < 256; i++) 35 | videodisplay.print((char)i); 36 | videodisplay.println(); 37 | videodisplay.setFont(CodePage437_8x8); 38 | videodisplay.setTextColor(videodisplay.RGB(0, 255, 0), videodisplay.RGB(255, 0, 0)); 39 | videodisplay.println("CodePage437_8x8"); 40 | for (int i = 0; i < 256; i++) 41 | videodisplay.print((char)i); 42 | videodisplay.println(); 43 | videodisplay.setFont(CodePage437_8x14); 44 | videodisplay.setTextColor(videodisplay.RGB(0, 0, 255), videodisplay.RGB(0, 255, 0)); 45 | videodisplay.println("CodePage437_8x14"); 46 | for (int i = 0; i < 256; i++) 47 | videodisplay.print((char)i); 48 | videodisplay.println(); 49 | videodisplay.setFont(CodePage437_8x16); 50 | videodisplay.setTextColor(videodisplay.RGB(255, 255, 0), videodisplay.RGB(0, 255, 255)); 51 | videodisplay.println("CodePage437_8x16"); 52 | for (int i = 0; i < 256; i++) 53 | videodisplay.print((char)i); 54 | videodisplay.println(); 55 | videodisplay.setFont(CodePage437_8x19); 56 | videodisplay.setTextColor(videodisplay.RGB(255, 0, 255), videodisplay.RGB(255, 255, 0)); 57 | videodisplay.println("CodePage437_8x19"); 58 | for (int i = 0; i < 256; i++) 59 | videodisplay.print((char)i); 60 | videodisplay.println(); 61 | videodisplay.setFont(CodePage437_9x16); 62 | videodisplay.setTextColor(videodisplay.RGB(0, 255, 255), videodisplay.RGB(255, 0, 255)); 63 | videodisplay.println("CodePage437_9x16"); 64 | for (int i = 0; i < 256; i++) 65 | videodisplay.print((char)i); 66 | videodisplay.println(); 67 | } 68 | 69 | void loop() 70 | { 71 | } 72 | -------------------------------------------------------------------------------- /examples/VGAHelloWorld/VGAHelloWorld.ino: -------------------------------------------------------------------------------- 1 | //This example shows a simple "Hello world!" on a VGA screen. 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | 9 | //pin configuration 10 | const int redPin = 14; 11 | const int greenPin = 19; 12 | const int bluePin = 27; 13 | const int hsyncPin = 32; 14 | const int vsyncPin = 33; 15 | 16 | //VGA Device 17 | VGA3Bit videodisplay; 18 | 19 | void setup() 20 | { 21 | //initializing vga at the specified pins 22 | videodisplay.init(VGAMode::MODE320x240, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 23 | //selecting the font 24 | videodisplay.setFont(Font6x8); 25 | //displaying the text 26 | videodisplay.println("Hello World!"); 27 | } 28 | 29 | void loop() 30 | { 31 | } 32 | -------------------------------------------------------------------------------- /examples/VGAHighRes/VGAHighRes.ino: -------------------------------------------------------------------------------- 1 | //This example shows a high VGA resolution 3Bit mode 2 | //The VGA3BitI implementation uses the I²S interrupt to transcode a dense frame buffer to the needed 3 | //8Bit/sample. Using the dense frame buffer allows to fit the big frame buffer in memory at the price of 4 | //a lot cpu performance. 5 | //You need to connect a VGA screen cable to the pins specified below. 6 | //cc by-sa 4.0 license 7 | //bitluni 8 | 9 | //including the needed header 10 | #include 11 | #include 12 | 13 | //pin configuration 14 | const int redPin = 14; 15 | const int greenPin = 19; 16 | const int bluePin = 27; 17 | const int hsyncPin = 32; 18 | const int vsyncPin = 33; 19 | 20 | //VGA Device using an interrupt to unpack the pixels from 4bit to 8bit for the I²S 21 | //This takes some CPU time in the background but is able to fit a frame buffer in the memory 22 | VGA3BitI videodisplay; 23 | 24 | ///draws the bitluni logo 25 | void bitluni(int x, int y, int s) 26 | { 27 | videodisplay.fillCircle(x + 2 * s, y + 2 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 28 | videodisplay.fillCircle(x + 22 * s, y + 2 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 29 | videodisplay.fillCircle(x + 2 * s, y + 22 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 30 | videodisplay.fillCircle(x + 22 * s, y + 22 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 31 | videodisplay.fillRect(x, y + 2 * s, 24 * s, 20 * s, videodisplay.RGB(128, 0, 0)); 32 | videodisplay.fillRect(x + 2 * s, y, 20 * s, 24 * s, videodisplay.RGB(128, 0, 0)); 33 | videodisplay.fillCircle(x + 7 * s, y + 4 * s, 2 * s, videodisplay.RGB(255, 255, 255)); 34 | videodisplay.fillCircle(x + 15 * s, y + 6 * s, 2 * s, videodisplay.RGB(255, 255, 255)); 35 | videodisplay.fillCircle(x + 11 * s, y + 16 * s, 6 * s, videodisplay.RGB(255, 255, 255)); 36 | videodisplay.fillCircle(x + 13 * s, y + 16 * s, 6 * s, videodisplay.RGB(255, 255, 255)); 37 | videodisplay.fillCircle(x + 11 * s, y + 16 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 38 | videodisplay.fillCircle(x + 13 * s, y + 16 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 39 | videodisplay.fillRect(x + 11 * s, y + 14 * s, 2 * s, 4 * s, videodisplay.RGB(128, 0, 0)); 40 | videodisplay.fillRect(x + 9 * s, y + 14 * s, 2 * s, 2 * s, videodisplay.RGB(128, 0, 0)); 41 | videodisplay.fillRect(x + 5 * s, y + 4 * s, 4 * s, 12 * s, videodisplay.RGB(255, 255, 255)); 42 | videodisplay.fillRect(x + 9 * s, y + 10 * s, 4 * s, s, videodisplay.RGB(255, 255, 255)); 43 | } 44 | 45 | void setup() 46 | { 47 | //initializing the graphics mode 48 | videodisplay.init(VGAMode::MODE800x600, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 49 | //setting the font 50 | videodisplay.setFont(Font6x8); 51 | //clearing with white background 52 | videodisplay.clear(videodisplay.RGB(0xffffff)); 53 | //text position 54 | videodisplay.setCursor(10, 10); 55 | //black text color no background color 56 | videodisplay.setTextColor(videodisplay.RGB(0)); 57 | //show the remaining memory 58 | videodisplay.print("free memory: "); 59 | videodisplay.print((int)heap_caps_get_free_size(MALLOC_CAP_DEFAULT)); 60 | //draw the logo 61 | bitluni(150, 60, 20); 62 | } 63 | 64 | //mainloop 65 | void loop() 66 | { 67 | } 68 | -------------------------------------------------------------------------------- /examples/VGAMadness/3DStarfield/3DStarfield.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "VGA/VGA6MonochromeVGAMadnessMultimonitor.h" 4 | 5 | //pin configuration 6 | //red pins 7 | const int redPin0 = 17; 8 | const int redPin1 = 2; 9 | const int redPin2 = 19; 10 | const int redPin3 = 12; 11 | const int redPin4 = 23; 12 | const int redPin5 = 26; 13 | //green pins 14 | const int greenPin0 = 16; 15 | const int greenPin1 = 15; 16 | const int greenPin2 = 18; 17 | const int greenPin3 = 14; 18 | const int greenPin4 = 22; 19 | const int greenPin5 = 25; 20 | //blue pins 21 | const int bluePin0 = 4; 22 | const int bluePin1 = 13; 23 | const int bluePin2 = 5; 24 | const int bluePin3 = 27; 25 | const int bluePin4 = 21; 26 | const int bluePin5 = 0; 27 | const int hsyncPin = 32; 28 | const int vsyncPin = 33; 29 | 30 | //VGA Device 31 | VGA6MonochromeVGAMadnessMultimonitor gfx; 32 | 33 | const int xres = 320 * 3; 34 | const int yres = 200 * 2; 35 | 36 | const int starCount = 4000; 37 | float stars[starCount][3]; 38 | Mesh model(starCount, stars, 0, 0, 0, 0, 0); 39 | 40 | void initStars() 41 | { 42 | for(int i = 0; i < starCount; i++) 43 | { 44 | stars[i][0] = random(201) - 100; 45 | stars[i][1] = random(201) - 100; 46 | stars[i][2] = random(201) - 100; 47 | } 48 | } 49 | 50 | //3D engine 51 | Engine3D engine(1); 52 | 53 | void setup() 54 | { 55 | const int pinCount = 3 * 6 + 2; 56 | Serial.begin(115200); 57 | //initializing vga at the specified pins 58 | gfx.setFrameBufferCount(2); 59 | gfx.init(VGAMode::MODE320x240, 60 | redPin0,greenPin0,bluePin0, 61 | redPin1,greenPin1,bluePin1, 62 | redPin2,greenPin2,bluePin2, 63 | redPin3,greenPin3,bluePin3, 64 | redPin4,greenPin4,bluePin4, 65 | redPin5,greenPin5,bluePin5, 66 | hsyncPin, vsyncPin, -1, 3, 2); 67 | //selecting the font 68 | gfx.setFont(Font6x8); 69 | initStars(); 70 | } 71 | 72 | 73 | void loop() 74 | { 75 | gfx.clear(); 76 | //perspective transformation 77 | static Matrix perspective = Matrix::translation(gfx.xres / 2, gfx.yres / 2, 0) * Matrix::scaling(1000 * gfx.pixelAspect(), 1000, 1000) * Matrix::perspective(90, 1, 10); 78 | static float u = 0; 79 | static float v = 0; 80 | static float w = 0; 81 | u += 0.02; 82 | v += 0.01; 83 | w += 0.005; 84 | //rotate model 85 | Matrix rotation = Matrix::rotation(u, 1, 0, 0) * Matrix::rotation(v, 0, 1, 0) * Matrix::rotation(w, 0, 0, 1); 86 | Matrix m0 = perspective * Matrix::translation(0, 1.7 * 0, 200) * rotation; 87 | //transform the vertices and normals 88 | model.transform(m0, rotation); 89 | //begin adding triangles to render pipeline 90 | //engine.begin(); 91 | //add this model to the render pipeline. it will sort the triangles from back to front and remove backfaced. The tiangle shader will determine the color of the tirangle. 92 | //the RGB color gien in the second parameter is not used in this case but could be used for calculations in the triangle shader 93 | model.drawVertices(gfx, gfx.RGB(255, 255, 255)); 94 | //render all triangles in the pipeline. if you render multiple models you want to do this once at the end 95 | //engine.end(gfx); 96 | gfx.show(); 97 | } 98 | -------------------------------------------------------------------------------- /examples/VGAMadness/VGABitlunisMadnessColor/VGABitlunisMadnessColor.ino: -------------------------------------------------------------------------------- 1 | //This example shows a simple "Hello world!" on a VGA screen. 2 | //You need to connect a VGA screen cable to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | #include 7 | #include 8 | #include "VGA/VGA4ColorMultimonitor.h" 9 | 10 | //pin configuration 11 | 12 | //red pins 13 | const int redPin = 17; 14 | const int redPin2 = 2; 15 | const int redPin3 = 19; 16 | const int redPin4 = 12; 17 | //const int M4Pin = 23; 18 | //const int M5Pin = 26; 19 | //green pins 20 | const int greenPin = 16; 21 | const int greenPin2 = 15; 22 | const int greenPin3 = 18; 23 | const int greenPin4 = 14; 24 | //const int M4Pin = 22; 25 | //const int M5Pin = 25; 26 | //blue pins 27 | const int bluePin = 4; 28 | const int bluePin2 = 13; 29 | const int bluePin3 = 5; 30 | const int bluePin4 = 27; 31 | //const int M4Pin = 21; 32 | //const int M5Pin = 0; 33 | const int hsyncPin = 32; 34 | const int vsyncPin = 33; 35 | 36 | //VGA Device 37 | VGA4ColorMultimonitor videodisplay; 38 | 39 | void setup() 40 | { 41 | //initializing vga at the specified pins 42 | videodisplay.init(VGAMode::MODE320x240, redPin, greenPin, bluePin, 43 | redPin2, greenPin2, bluePin2, 44 | redPin3, greenPin3, bluePin3, 45 | redPin4, greenPin4, bluePin4, 46 | -1, -1, hsyncPin, vsyncPin, -1,2,2); 47 | //selecting the font 48 | videodisplay.setFont(Font6x8); 49 | //displaying the text 50 | videodisplay.fillCircle(140,10,5,1); 51 | videodisplay.fillCircle(140+20+videodisplay.mode.hRes,10,5,1); 52 | videodisplay.fillCircle(140+20*2+videodisplay.mode.hRes*2,10,5,1); 53 | videodisplay.fillCircle(140,30+videodisplay.mode.vRes,5,1); 54 | videodisplay.fillCircle(140+20+videodisplay.mode.hRes,30+videodisplay.mode.vRes,5,1); 55 | videodisplay.fillCircle(140+20*2+videodisplay.mode.hRes*2,30+videodisplay.mode.vRes,5,1); 56 | videodisplay.fillCircle(videodisplay.mode.hRes/2,videodisplay.mode.vRes/videodisplay.mode.vDiv,80,videodisplay.RGB(255,255,0)); 57 | videodisplay.fillCircle(videodisplay.mode.hRes,videodisplay.mode.vRes/videodisplay.mode.vDiv/2,80,videodisplay.RGB(255,0,255)); 58 | 59 | videodisplay.setFont(Font6x8); 60 | 61 | for(int xmon = 0; xmon < 3; xmon++) 62 | { 63 | for(int ymon = 0; ymon < 2; ymon++) 64 | { 65 | videodisplay.line(xmon*320 + 160-14,ymon*240+120+3,xmon*320 + 160+22,ymon*240+120+3,videodisplay.RGB(0,255,255)); 66 | videodisplay.line(xmon*320 + 160-2,ymon*240+120-12,xmon*320 + 160-2,ymon*240+120+18,videodisplay.RGB(0,255,0)); 67 | } 68 | } 69 | 70 | videodisplay.setCursor(160-12,120-5); 71 | videodisplay.println("1!"); 72 | videodisplay.setCursor(160+320,120-5); 73 | videodisplay.println("2!"); 74 | videodisplay.setCursor(160-12,120+240+5); 75 | videodisplay.println("3!"); 76 | videodisplay.setCursor(160+320,120+240+5); 77 | videodisplay.println("4!"); 78 | 79 | } 80 | 81 | void loop() 82 | { 83 | } 84 | -------------------------------------------------------------------------------- /examples/VGAMadness/VGABitlunisMadnessMonochrome/VGABitlunisMadnessMonochrome.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "VGA/VGA6MonochromeVGAMadnessMultimonitor.h" 4 | 5 | //pin configuration 6 | //red pins 7 | const int redPin0 = 17; 8 | const int redPin1 = 2; 9 | const int redPin2 = 19; 10 | const int redPin3 = 12; 11 | const int redPin4 = 23; 12 | const int redPin5 = 26; 13 | //green pins 14 | const int greenPin0 = 16; 15 | const int greenPin1 = 15; 16 | const int greenPin2 = 18; 17 | const int greenPin3 = 14; 18 | const int greenPin4 = 22; 19 | const int greenPin5 = 25; 20 | //blue pins 21 | const int bluePin0 = 4; 22 | const int bluePin1 = 13; 23 | const int bluePin2 = 5; 24 | const int bluePin3 = 27; 25 | const int bluePin4 = 21; 26 | const int bluePin5 = 0; 27 | const int hsyncPin = 32; 28 | const int vsyncPin = 33; 29 | 30 | //VGA Device 31 | VGA6MonochromeVGAMadnessMultimonitor videodisplay; 32 | 33 | void setup() 34 | { 35 | Serial.begin(115200); 36 | //selecting the foreground or background color 37 | //IMPORTANT: for monochrome mode this MUST be done BEFORE init 38 | // and color can not be changed after init 39 | //uncomment the line to test changing foreground color in all outputs 40 | //videodisplay.setFrontGlobalColor(255,255,0); //yellow 41 | //uncomment the line to test changing background color in all outputs 42 | //videodisplay.setBackGlobalColor(255,0,0); //red 43 | //because of hardware limitations only BackGlobalColors compatible with FrontGlobalColor will set a non-black background: 44 | // FrontGlobalColor - cyan, BackGlobalColors - green or blue 45 | // FrontGlobalColor - magenta, BackGlobalColors - red or blue 46 | // FrontGlobalColor - yellow, BackGlobalColors - red or green 47 | // FrontGlobalColor - white, BackGlobalColors - any 48 | 49 | //initializing vga at the specified pins 50 | videodisplay.init(VGAMode::MODE320x240, 51 | redPin0,greenPin0,bluePin0, 52 | redPin1,greenPin1,bluePin1, 53 | redPin2,greenPin2,bluePin2, 54 | redPin3,greenPin3,bluePin3, 55 | redPin4,greenPin4,bluePin4, 56 | redPin5,greenPin5,bluePin5, 57 | hsyncPin, vsyncPin, -1,3,2); 58 | //selecting the font 59 | videodisplay.setFont(Font6x8); 60 | 61 | for(int xmon = 0; xmon < 3; xmon++) 62 | { 63 | for(int ymon = 0; ymon < 2; ymon++) 64 | { 65 | videodisplay.line(xmon*320 + 160-14,ymon*240+120+3,xmon*320 + 160+22,ymon*240+120+3,1); 66 | videodisplay.line(xmon*320 + 160-2,ymon*240+120-12,xmon*320 + 160-2,ymon*240+120+18,1); 67 | videodisplay.line(xmon*320 + 160+10,ymon*240+120-12,xmon*320 + 160+10,ymon*240+120+18,1); 68 | } 69 | } 70 | 71 | videodisplay.setCursor(160-12,120-5); 72 | videodisplay.println("1!"); 73 | videodisplay.setCursor(160+320,120-5); 74 | videodisplay.println("2!"); 75 | videodisplay.setCursor(160+320+320+12,120-5); 76 | videodisplay.println("3!"); 77 | videodisplay.setCursor(160-12,120+240+5); 78 | videodisplay.println("4!"); 79 | videodisplay.setCursor(160+320,120+240+5); 80 | videodisplay.println("5!"); 81 | videodisplay.setCursor(160+320+320+12,120+240+5); 82 | videodisplay.println("6!"); 83 | } 84 | 85 | 86 | void loop() { 87 | } 88 | -------------------------------------------------------------------------------- /examples/VGASprites/VGASprites.ino: -------------------------------------------------------------------------------- 1 | //This example shows the three methods of how sprites can be rendered on a VGA screen 2 | //You need to connect a VGA screen cable and an external DAC (simple R2R does the job) to the pins specified below. 3 | //cc by-sa 4.0 license 4 | //bitluni 5 | 6 | //include libraries 7 | #include 8 | #include 9 | 10 | //include the sprites converted the SpriteConverter. Check the documentation for further infos. 11 | #include "explosion.h" 12 | 13 | //pin configuration 14 | const int redPins[] = {2, 4, 12, 13, 14}; 15 | const int greenPins[] = {15, 16, 17, 18, 19}; 16 | const int bluePins[] = {21, 22, 23, 27}; 17 | const int hsyncPin = 32; 18 | const int vsyncPin = 33; 19 | 20 | //VGA Device 21 | VGA14Bit videodisplay; 22 | 23 | //initial setup 24 | void setup() 25 | { 26 | //need double buffering 27 | videodisplay.setFrameBufferCount(2); 28 | //initializing i2s vga 29 | videodisplay.init(VGAMode::MODE200x150, redPins, greenPins, bluePins, hsyncPin, vsyncPin); 30 | //setting the font 31 | videodisplay.setFont(Font6x8); 32 | } 33 | 34 | //just draw each frame 35 | void loop() 36 | { 37 | //draw a background 38 | for (int y = 0; y < videodisplay.yres / 10; y++) 39 | for (int x = 0; x < videodisplay.xres / 10; x++) 40 | videodisplay.fillRect(x * 10, y * 10, 10, 10, (x + y) & 1 ? videodisplay.RGB(0, 128, 0) : videodisplay.RGB(0, 0, 128)); 41 | //print some labels 42 | videodisplay.setCursor(36, 41); 43 | videodisplay.print("draw drawMix drawAdd"); 44 | //there are 20 sprites for the explosion. The second parameter is the index of the sprite. 45 | //We used the milliseconds to calculate the current index of the animation. 46 | //the last two parameters is the position. During the conversion of the sprite the origin of each sprite is defined. 47 | //check the Utilities folder for the converter 48 | //"draw" draws the sprite opaque ignoring any existing alpha channel 49 | explosion.draw(videodisplay, (millis() / 50) % 20, videodisplay.xres / 4, videodisplay.yres / 2); 50 | //"drawMix" uses the alpha channel 51 | explosion.drawMix(videodisplay, (millis() / 50) % 20, videodisplay.xres / 2, videodisplay.yres / 2); 52 | //"drawAdd" adds the color components of the back ground and the sprite 53 | explosion.drawAdd(videodisplay, (millis() / 50) % 20, videodisplay.xres * 3 / 4, videodisplay.yres / 2); 54 | //swap the frame buffers and show the rendering 55 | videodisplay.show(); 56 | } 57 | -------------------------------------------------------------------------------- /examples/VGAWiFiTextTerminal/VGAWiFiTextTerminal.ino: -------------------------------------------------------------------------------- 1 | //This example acts like a websever. It can create an access point or join an existing WiFI network. 2 | //All text that's entered in the served page will bis displayed on the connected VGA screen. 3 | //You need to connect a VGA screen cable to the pins specified below. 4 | //cc by-sa 4.0 license 5 | //bitluni 6 | 7 | #include 8 | #include 9 | #include 10 | //ESP32Lib video headers 11 | #include 12 | #include 13 | 14 | //true: creates an access point, false: connects to an existing wifi 15 | const bool AccessPointMode = true; 16 | //wifi credentials (enter yours if you arne not using the AccessPointMode) 17 | const char *ssid = "VGA"; 18 | const char *password = ""; 19 | 20 | //pin configuration, change if you need to 21 | const int redPin = 14; 22 | const int greenPin = 19; 23 | const int bluePin = 27; 24 | const int hsyncPin = 32; 25 | const int vsyncPin = 33; 26 | 27 | //the webserver at pot 80 28 | WebServer server(80); 29 | 30 | //The VGA Device 31 | VGA3Bit videodisplay; 32 | 33 | //include html page 34 | const char *page = 35 | #include "page.h" 36 | ; 37 | 38 | ///Html page is sent on root 39 | void sendPage() 40 | { 41 | server.send(200, "text/html", page); 42 | } 43 | 44 | ///Received text will be displayed on the screen 45 | void text() 46 | { 47 | server.send(200, "text/plain", "ok"); 48 | videodisplay.println(server.arg(0).c_str()); 49 | } 50 | 51 | ///initialization 52 | void setup() 53 | { 54 | Serial.begin(115200); 55 | //Handle the WiFi AP or STA mode and display results on the screen 56 | if (AccessPointMode) 57 | { 58 | Serial.println("Creating access point..."); 59 | WiFi.softAP(ssid, password, 6, 0); 60 | } 61 | else 62 | { 63 | Serial.print("Connecting to SSID "); 64 | Serial.println(ssid); 65 | WiFi.begin(ssid, password); 66 | while (WiFi.status() != WL_CONNECTED) 67 | { 68 | delay(500); 69 | videodisplay.print("."); 70 | } 71 | } 72 | //start vga on the specified pins 73 | videodisplay.init(VGAMode::MODE400x300, redPin, greenPin, bluePin, hsyncPin, vsyncPin); 74 | //make the background blue 75 | videodisplay.clear(videodisplay.RGBA(0, 0, 255)); 76 | videodisplay.backColor = videodisplay.RGB(0, 0, 255); 77 | //select the font 78 | videodisplay.setFont(Font6x8); 79 | 80 | //send page on http:/// 81 | server.on("/", sendPage); 82 | //receive text on http:///text 83 | server.on("/text", text); 84 | //start the server 85 | server.begin(); 86 | 87 | //display some text header on the screen including the ip 88 | videodisplay.clear(videodisplay.RGBA(0, 0, 255)); 89 | videodisplay.setCursor(0, 0); 90 | videodisplay.println("----------------------"); 91 | videodisplay.println("bitluni's VGA Terminal"); 92 | if (AccessPointMode) 93 | { 94 | videodisplay.print("SSID: "); 95 | videodisplay.println(ssid); 96 | if (strlen(password)) 97 | { 98 | videodisplay.print("password: "); 99 | videodisplay.println(password); 100 | } 101 | videodisplay.println("http://192.168.4.1"); 102 | } 103 | else 104 | { 105 | videodisplay.print("http://"); 106 | videodisplay.println(WiFi.localIP().toString().c_str()); 107 | } 108 | videodisplay.println("----------------------"); 109 | } 110 | 111 | void loop() 112 | { 113 | //process the server stuff 114 | server.handleClient(); 115 | delay(10); 116 | } 117 | -------------------------------------------------------------------------------- /examples/VGAWiFiTextTerminal/page.h: -------------------------------------------------------------------------------- 1 | R"( 2 | 3 | 4 | 5 | bitluni's VGA text terminal 6 | 20 | 71 | 72 | 73 | 74 |

bitluni's VGA text terminal

75 | 76 | 77 | 78 | 79 | 80 | 81 | 85 | 86 |
82 | 84 |
87 | 88 | 89 | 90 | 91 | 92 | )" -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitluni/ESP32Lib/de3d73f3c68f879976a3351315b90f366dae8967/keywords.txt -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitluni ESP32Lib", 3 | "keywords": "VGA, audio, I2S, 3d, game, engine, mesh, gamepad, controller, NES, SNES, input, output, graphics, font, arduino, esp32, driver, display, bitluni", 4 | "description": "Provides VGA, Game Controller (NES, SNES), Audio support for the ESP32. The graphics engine supports sprites, animations and 3d meshes.", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/bitluni/ESP32Lib.git" 9 | }, 10 | "authors": 11 | [ 12 | { 13 | "name": "bitluni", 14 | "email": "platformio@bitluni.net", 15 | "url": "https://github.com/bitluni", 16 | "maintainer": true 17 | } 18 | ], 19 | "version": "0.4.0", 20 | "frameworks": "arduino", 21 | "platforms": ["espressif8266", "espressif32"] 22 | } 23 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=bitluni ESP32Lib 2 | version=0.4.0 3 | author=bitluni 4 | maintainer=bitluni 5 | sentence=Multimedia library for the ESP32 6 | paragraph=Provides VGA, Game Controller (NES, SNES), Audio support for the ESP32. The graphics engine supports sprites, animations and 3d meshes. 7 | url=https://github.com/bitluni/ESP32Lib 8 | architectures=esp32,esp8266 9 | includes=ESP32Lib.h 10 | category=Other 11 | -------------------------------------------------------------------------------- /src/Audio/AudioOutput.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: bitluni 2024 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://youtube.com/bitlunislab 9 | https://github.com/bitluni 10 | http://bitluni.net 11 | */ 12 | 13 | 14 | #ifdef ESP8266 15 | #include "AudioSystem.h" 16 | 17 | class AudioOutput 18 | { 19 | public: 20 | AudioSystem *audioSystem; 21 | 22 | void init(AudioSystem &audioSystem) 23 | { 24 | } 25 | }; 26 | #endif 27 | 28 | #ifdef ESP32 29 | 30 | //#include "components/esp32/include/esp_clk.h" 31 | #include "soc/i2s_reg.h" 32 | #include "soc/timer_group_struct.h" 33 | #include "driver/periph_ctrl.h" 34 | #include "driver/timer.h" 35 | #include "AudioSystem.h" 36 | 37 | class AudioOutput; 38 | void IRAM_ATTR timerInterrupt(AudioOutput *audioOutput); 39 | 40 | #ifndef TIMER_BASE_CLK 41 | #define TIMER_BASE_CLK 240000000 42 | #endif 43 | //esp_clk_apb_freq() 44 | class AudioOutput 45 | { 46 | public: 47 | AudioSystem *audioSystem; 48 | 49 | void init(AudioSystem &audioSystem) 50 | { 51 | this->audioSystem = &audioSystem; 52 | timer_config_t config; 53 | config.alarm_en = (timer_alarm_t)1; 54 | config.auto_reload = (timer_autoreload_t)1; 55 | config.counter_dir = TIMER_COUNT_UP; 56 | config.divider = 16; 57 | config.intr_type = TIMER_INTR_LEVEL; 58 | config.counter_en = TIMER_PAUSE; 59 | timer_init((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0, &config); 60 | timer_pause((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0); 61 | timer_set_counter_value((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0, 0x00000000ULL); 62 | timer_set_alarm_value((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0, 1.0/audioSystem.samplingRate * TIMER_BASE_CLK / config.divider); 63 | timer_enable_intr((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0); 64 | timer_isr_register((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0, (void (*)(void*))timerInterrupt, (void*) this, ESP_INTR_FLAG_IRAM, NULL); 65 | timer_start((timer_group_t)TIMER_GROUP_0, (timer_idx_t)TIMER_0); 66 | } 67 | }; 68 | 69 | void IRAM_ATTR timerInterrupt(AudioOutput *audioOutput) 70 | { 71 | uint32_t intStatus = TIMERG0.int_st_timers.val; 72 | if(intStatus & BIT(TIMER_0)) 73 | { 74 | TIMERG0.hw_timer[TIMER_0].update.tx_update = 1; 75 | TIMERG0.int_clr_timers.t0_int_clr = 1; 76 | TIMERG0.hw_timer[TIMER_0].config.tx_alarm_en = 1; 77 | 78 | WRITE_PERI_REG(I2S_CONF_SIGLE_DATA_REG(0), audioOutput->audioSystem->nextSample() << 24); 79 | } 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/Composite/CompMode.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: Martin-Laclaustra 2020 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://github.com/bitluni 9 | */ 10 | #pragma once 11 | 12 | #include "ModeComposite.h" 13 | 14 | class CompMode 15 | { 16 | public: 17 | CompMode(){}; 18 | 19 | static const ModeComposite MODEPAL288P; // OOM in CompositeGrayPDM8/4-8266 20 | static const ModeComposite MODEPALHalf144P; // insufficient sync in CompositeGrayPDM2-8266 21 | static const ModeComposite MODEPALQuarter144P; // CompositeGrayPDM8-8266 (stripes), CompositeGrayPDM4/2-8266 (unusable stripes) 22 | static const ModeComposite MODEPAL288Pmax; // OOM in DAC, in 8266 23 | static const ModeComposite MODEPAL288Pmin; // does not work in ladder, CompositeGrayPDM8/4-8266 (unusable stripes), insufficient sync in CompositeGrayPDM2-8266 24 | static const ModeComposite MODEPAL576I; // OOM in DAC, in 8266 25 | static const ModeComposite MODEPAL576Imax; // OOM in DAC, in Ladder, in 8266 26 | static const ModeComposite MODEPAL576Imin; // does not work in ladder, OOM in CompositeGrayPDM8-8266, CompositeGrayPDM4-8266 (unusable stripes), insufficient sync in CompositeGrayPDM2-8266 27 | static const ModeComposite MODEPAL576Idiv3; // OOM in CompositeGrayPDM8/4-8266 28 | static const ModeComposite MODEPALColor288P; // OOM in CompositeGrayPDM8/4-8266 29 | static const ModeComposite MODEPALColor288Pmid; // OOM in CompositeGrayPDM8/4-8266 30 | 31 | static const ModeComposite MODENTSC240P; // OOM in CompositeGrayPDM8/4-8266, incorrect sync in CompositeGrayPDM2-8266 32 | static const ModeComposite MODENTSCHalf120P; // incorrect sync in CompositeGrayPDM?-8266 33 | static const ModeComposite MODENTSC240Pmax; 34 | static const ModeComposite MODENTSC480I; // OOM in DAC, in 8266 35 | static const ModeComposite MODENTSC480Imax; // OOM in DAC, in Ladder, in 8266 36 | static const ModeComposite MODENTSCColor240P; 37 | static const ModeComposite MODENTSCColor120P; 38 | 39 | //OLD MODES 40 | 41 | static const ModeComposite MODE400x300; 42 | static const ModeComposite MODEPAL312P; 43 | }; 44 | 45 | -------------------------------------------------------------------------------- /src/Composite/CompositeL8.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: bitluni 2019 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://youtube.com/bitlunislab 9 | https://github.com/bitluni 10 | http://bitluni.net 11 | */ 12 | #pragma once 13 | #include "Composite.h" 14 | #include "../Graphics/GraphicsL8CompositeSwapped.h" 15 | 16 | class CompositeL8 : public Composite, public GraphicsL8CompositeSwapped 17 | { 18 | public: 19 | CompositeL8() //8 bit based modes only work with I2S1 20 | : Composite(1) 21 | { 22 | } 23 | 24 | 25 | bool init(const ModeComposite &mode, 26 | const int C0Pin, const int C1Pin, 27 | const int C2Pin, const int C3Pin, 28 | const int C4Pin, const int C5Pin, 29 | const int C6Pin, const int C7Pin) 30 | { 31 | int pinMap[8] = { 32 | C0Pin, C1Pin, 33 | C2Pin, C3Pin, 34 | C4Pin, C5Pin, 35 | C6Pin, C7Pin 36 | }; 37 | 38 | return Composite::init(mode, pinMap, 8); 39 | } 40 | 41 | bool init(const ModeComposite &mode, const int *compositePins) 42 | { 43 | return Composite::init(mode, compositePins, 8); 44 | } 45 | 46 | bool init(const ModeComposite &mode, const PinConfigComposite &pinConfig) 47 | { 48 | int pins[8]; 49 | pinConfig.fill(pins); 50 | return Composite::init(mode, pins, 8); 51 | } 52 | 53 | virtual int bytesPerSample() const 54 | { 55 | return 1; 56 | } 57 | 58 | virtual float pixelAspect() const 59 | { 60 | return 1; 61 | } 62 | 63 | virtual void propagateResolution(const int xres, const int yres) 64 | { 65 | setResolution(xres, yres); 66 | } 67 | 68 | void *vSyncInactiveBuffer; 69 | void *vSyncActiveBuffer; 70 | void *inactiveBuffer; 71 | void *blankActiveBuffer; 72 | 73 | virtual Color **allocateFrameBuffer() 74 | { 75 | return (Color **)DMABufferDescriptor::allocateDMABufferArray(yres, mode.hRes * bytesPerSample(), true, 75 * 0x1010101); 76 | } 77 | 78 | virtual void allocateLineBuffers() 79 | { 80 | Composite::allocateLineBuffers((void **)frameBuffers[0]); 81 | } 82 | 83 | virtual void show(bool vSync = false) 84 | { 85 | if (!frameBufferCount) 86 | return; 87 | if (vSync) 88 | { 89 | //TODO read the I2S docs to find out 90 | } 91 | Graphics::show(vSync); 92 | if(dmaBufferDescriptors) 93 | for (int i = 0; i < yres * mode.vDiv; i++) 94 | dmaBufferDescriptors[(mode.vFront + mode.vSync + mode.vBack + i) * 2 + 1].setBuffer(frontBuffer[i / mode.vDiv], mode.hRes * bytesPerSample()); 95 | } 96 | 97 | virtual void scroll(int dy, Color color) 98 | { 99 | Graphics::scroll(dy, color); 100 | if (frameBufferCount == 1) 101 | show(); 102 | } 103 | 104 | protected: 105 | virtual void interrupt() 106 | { 107 | Serial.print('.'); 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /src/Composite/CompositePinConfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Author: bitluni 2019 Modified by Martin-Laclaustra 2021 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://github.com/bitluni 9 | */ 10 | #include "CompositePinConfig.h" 11 | 12 | //PinConfigComposite arguments order: 13 | //============================== 14 | // c0, c1, c2, c3, c4, c5, c6, c7 15 | 16 | const PinConfigComposite CompositePinConfig::GameWing(22, 14, 32, 15, 33, 27, 12, 13); 17 | const PinConfigComposite CompositePinConfig::XPlayer(32, 27, 14, 12, 13, 4, 21, 22); 18 | -------------------------------------------------------------------------------- /src/Composite/CompositePinConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: bitluni 2019 Modified by Martin-Laclaustra 2021 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://github.com/bitluni 9 | */ 10 | #pragma once 11 | 12 | #include "PinConfigComposite.h" 13 | 14 | class CompositePinConfig 15 | { 16 | public: 17 | CompositePinConfig(){}; 18 | 19 | static const PinConfigComposite GameWing; 20 | static const PinConfigComposite XPlayer; 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /src/Composite/PinConfigComposite.h: -------------------------------------------------------------------------------- 1 | /* 2 | Author: bitluni 2019 3 | License: 4 | Creative Commons Attribution ShareAlike 4.0 5 | https://creativecommons.org/licenses/by-sa/4.0/ 6 | 7 | For further details check out: 8 | https://youtube.com/bitlunislab 9 | https://github.com/bitluni 10 | http://bitluni.net 11 | */ 12 | #pragma once 13 | 14 | class PinConfigComposite 15 | { 16 | public: 17 | int c0, c1, c2, c3, c4, c5, c6, c7; 18 | PinConfigComposite( 19 | const int c0 = -1, 20 | const int c1 = -1, 21 | const int c2 = -1, 22 | const int c3 = -1, 23 | const int c4 = -1, 24 | const int c5 = -1, 25 | const int c6 = -1, 26 | const int c7 = -1) 27 | : c0(c0), 28 | c1(c1), 29 | c2(c2), 30 | c3(c3), 31 | c4(c4), 32 | c5(c5), 33 | c6(c6), 34 | c7(c7) 35 | { 36 | } 37 | void fill(int *pins) const 38 | { 39 | pins[0] = c0; 40 | pins[1] = c1; 41 | pins[2] = c2; 42 | pins[3] = c3; 43 | pins[4] = c4; 44 | pins[5] = c5; 45 | pins[6] = c6; 46 | pins[7] = c7; 47 | } 48 | }; -------------------------------------------------------------------------------- /src/ESP32Lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include