/* This file is part of VGA_t4 library. VGA_t4 library is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Copyright (C) 2020 J-M Harvengt Inspired from the original Teensy3 uVGA library of Eric PREVOTEAU. QTIMER/FlexIO code based on Teensy4 examples of KurtE, Manitou and easone from the Teensy4 forum (https://forum.pjrc.com) */ #include "VGA_t4.h" #include "VGA_font8x8.h" #include "pico/stdlib.h" #include "pico/multicore.h" #include "scanvideo.h" #include "composable_scanline.h" #include "pico/sync.h" #include "hardware/irq.h" #include #include "platform_config.h" #include "iopins.h" #ifdef USE_VGA #define R16(rgb) ((rgb>>8)&0xf8) #define G16(rgb) ((rgb>>3)&0xfc) #define B16(rgb) ((rgb<<3)&0xf8) #define PIO_FB_OFFSET 4 // 8 bits 320x240 frame buffer => 64K static vga_pixel * visible_framebuffer = NULL; static vga_pixel * framebuffer = NULL; static vga_pixel * fb0 = NULL; uint32_t * pio_fb = NULL; int pio_fbwidth=0; static vga_pixel * fb1 = NULL; static int fb_width; static int fb_height; static int fb_stride; static int left_border; static int top_border; static scanvideo_mode_t vga_mode; static semaphore_t core1_initted; static void core1_func(); PolyDef PolySet; // will contain a polygon data #define RGBVAL16(r,g,b) ( (((b>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | (((r>>3)&0x1f)<<0) ) #define PICO_SCANVIDEO_PIXEL_FROM_RGBVAL8(rgb) (((rgb&0x3)<<(PICO_SCANVIDEO_PIXEL_BSHIFT))|(((rgb&0x1C)>>2)<<(PICO_SCANVIDEO_PIXEL_GSHIFT))|(((rgb&0xE0)>>5)<<(PICO_SCANVIDEO_PIXEL_RSHIFT))) static void core1_sio_irq(); static void core1_func() { // initialize video scanvideo_setup(&vga_mode); scanvideo_timing_enable(true); multicore_fifo_clear_irq(); irq_set_exclusive_handler(SIO_IRQ_PROC1,core1_sio_irq); //irq_set_priority (SIO_IRQ_PROC1, 129); irq_set_enabled(SIO_IRQ_PROC1,true); sem_release(&core1_initted); while (true) { tight_loop_contents(); } } static void init_pio_framebuffer(uint8_t * fb) { // Code for the PIO + buffer data initialized with random //memset((void*)fb,0, fb_stride*fb_height*sizeof(vga_pixel)); uint8_t col = 0; for( int i=0; i=0) && (x<=fb_width) && (y>=0) && (y<=fb_height)) framebuffer[y*fb_stride+x] = color; } vga_pixel VGA_T4::getPixel(int x, int y){ return(framebuffer[y*fb_stride+x]); } vga_pixel * VGA_T4::getLineBuffer(int j) { return (&framebuffer[j*fb_stride]); } void VGA_T4::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, vga_pixel color) { int i,j,l=y; for (j=0; j> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; l++; } dst=&framebuffer[l*fb_stride+x]; bits = *charpt++; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; l++; } x +=8; } } void VGA_T4::drawSprite(int16_t x, int16_t y, const int16_t *bitmap) { drawSprite(x,y,bitmap, 0,0,0,0); } void VGA_T4::drawSprite(int16_t x, int16_t y, const int16_t *bitmap, uint16_t arx, uint16_t ary, uint16_t arw, uint16_t arh) { int bmp_offx = 0; int bmp_offy = 0; int16_t *bmp_ptr; int w =*bitmap++; int h = *bitmap++; if ( (arw == 0) || (arh == 0) ) { // no crop window arx = x; ary = y; arw = w; arh = h; } else { if ( (x>(arx+arw)) || ((x+w)(ary+arh)) || ((y+h) arx) && (x<(arx+arw)) ) { arw = arw - (x-arx); arx = arx + (x-arx); } else { bmp_offx = arx; } if ( ((x+w) > arx) && ((x+w)<(arx+arw)) ) { arw -= (arx+arw-x-w); } if ( (y > ary) && (y<(ary+arh)) ) { arh = arh - (y-ary); ary = ary + (y-ary); } else { bmp_offy = ary; } if ( ((y+h) > ary) && ((y+h)<(ary+arh)) ) { arh -= (ary+arh-y-h); } } int l=ary; bitmap = bitmap + bmp_offy*w + bmp_offx; for (int row=0;row 2) ) y += (fb_height-height)/2; vga_pixel * dst=&framebuffer[y*fb_stride]; if (width > fb_width) { #ifdef TFT_LINEARINT int delta = (width/(width-fb_width))-1; int pos = delta; for (int i=0; i> 8]]; pos +=step; } #endif } else if ((width*2) == fb_width) { for (int i=0; i 2) ) y += (fb_height-height)/2; uint8_t * dst=&framebuffer[y*fb_stride]; if (width > fb_width) { int step = ((width << 8)/fb_width); int pos = 0; for (int i=0; i> 8]; pos +=step; } } else if ((width*2) == fb_width) { for (int i=0; i 2) ) y += (fb_height-height)/2; uint8_t * dst=&framebuffer[y*fb_stride]; if (width > fb_width) { int step = ((width << 8)/fb_width); int pos = 0; for (int i=0; i> 8]; *dst++ = VGA_RGB(R16(pix),G16(pix),B16(pix)); pos +=step; } } else if ((width*2) == fb_width) { for (int i=0; i 2) ) { ysrc += (fb_height-height)/2; ydst += (fb_height-height)/2; } uint8_t * src=&framebuffer[ysrc*fb_stride]; uint8_t * dst=&framebuffer[ydst*fb_stride]; memcpy(dst,src,width); } //-------------------------------------------------------------- // Draw a line between 2 points // x1,y1 : 1st point // x2,y2 : 2nd point // Color : 16bits color //-------------------------------------------------------------- void VGA_T4::drawline(int16_t x1, int16_t y1, int16_t x2, int16_t y2, vga_pixel color){ uint8_t yLonger = 0; int incrementVal, endVal; int shortLen = y2-y1; int longLen = x2-x1; int decInc; int j = 0, i = 0; if(ABS(shortLen) > ABS(longLen)) { int swap = shortLen; shortLen = longLen; longLen = swap; yLonger = 1; } endVal = longLen; if(longLen < 0) { incrementVal = -1; longLen = -longLen; endVal--; } else { incrementVal = 1; endVal++; } if(longLen == 0) decInc = 0; else decInc = (shortLen << 16) / longLen; if(yLonger) { for(i = 0;i != endVal;i += incrementVal) { drawPixel(x1 + (j >> 16),y1 + i,color); j += decInc; } } else { for(i = 0;i != endVal;i += incrementVal) { drawPixel(x1 + i,y1 + (j >> 16),color); j += decInc; } } } //-------------------------------------------------------------- // Draw a horizontal line // x1,y1 : starting point // lenght : lenght in pixels // color : 16bits color //-------------------------------------------------------------- void VGA_T4::draw_h_line(int16_t x, int16_t y, int16_t lenght, vga_pixel color){ drawline(x , y , x + lenght , y , color); } //-------------------------------------------------------------- // Draw a vertical line // x1,y1 : starting point // lenght : lenght in pixels // color : 16bits color //-------------------------------------------------------------- void VGA_T4::draw_v_line(int16_t x, int16_t y, int16_t lenght, vga_pixel color){ drawline(x , y , x , y + lenght , color); } //-------------------------------------------------------------- // Draw a circle. // x, y - center of circle. // r - radius. // color - color of the circle. //-------------------------------------------------------------- void VGA_T4::drawcircle(int16_t x, int16_t y, int16_t radius, vga_pixel color){ int16_t a, b, P; a = 0; b = radius; P = 1 - radius; do { drawPixel(a+x, b+y, color); drawPixel(b+x, a+y, color); drawPixel(x-a, b+y, color); drawPixel(x-b, a+y, color); drawPixel(b+x, y-a, color); drawPixel(a+x, y-b, color); drawPixel(x-a, y-b, color); drawPixel(x-b, y-a, color); if(P < 0) P+= 3 + 2*a++; else P+= 5 + 2*(a++ - b--); } while(a <= b); } //-------------------------------------------------------------- // Displays a full circle. // x : specifies the X position // y : specifies the Y position // radius : specifies the Circle Radius // fillcolor : specifies the Circle Fill Color // bordercolor: specifies the Circle Border Color //-------------------------------------------------------------- void VGA_T4::drawfilledcircle(int16_t x, int16_t y, int16_t radius, vga_pixel fillcolor, vga_pixel bordercolor){ int32_t D; /* Decision Variable */ uint32_t CurX;/* Current X Value */ uint32_t CurY;/* Current Y Value */ D = 3 - (radius << 1); CurX = 0; CurY = radius; while (CurX <= CurY) { if(CurY > 0) { draw_v_line(x - CurX, y - CurY, 2*CurY, fillcolor); draw_v_line(x + CurX, y - CurY, 2*CurY, fillcolor); } if(CurX > 0) { draw_v_line(x - CurY, y - CurX, 2*CurX, fillcolor); draw_v_line(x + CurY, y - CurX, 2*CurX, fillcolor); } if (D < 0) { D += (CurX << 2) + 6; } else { D += ((CurX - CurY) << 2) + 10; CurY--; } CurX++; } drawcircle(x, y, radius,bordercolor); } //-------------------------------------------------------------- // Displays an Ellipse. // cx: specifies the X position // cy: specifies the Y position // radius1: minor radius of ellipse. // radius2: major radius of ellipse. // color: specifies the Color to use for draw the Border from the Ellipse. //-------------------------------------------------------------- void VGA_T4::drawellipse(int16_t cx, int16_t cy, int16_t radius1, int16_t radius2, vga_pixel color){ int x = -radius1, y = 0, err = 2-2*radius1, e2; float K = 0, rad1 = 0, rad2 = 0; rad1 = radius1; rad2 = radius2; if (radius1 > radius2) { do { K = (float)(rad1/rad2); drawPixel(cx-x,cy+(uint16_t)(y/K),color); drawPixel(cx+x,cy+(uint16_t)(y/K),color); drawPixel(cx+x,cy-(uint16_t)(y/K),color); drawPixel(cx-x,cy-(uint16_t)(y/K),color); e2 = err; if (e2 <= y) { err += ++y*2+1; if (-x == y && e2 <= x) e2 = 0; } if (e2 > x) err += ++x*2+1; } while (x <= 0); } else { y = -radius2; x = 0; do { K = (float)(rad2/rad1); drawPixel(cx-(uint16_t)(x/K),cy+y,color); drawPixel(cx+(uint16_t)(x/K),cy+y,color); drawPixel(cx+(uint16_t)(x/K),cy-y,color); drawPixel(cx-(uint16_t)(x/K),cy-y,color); e2 = err; if (e2 <= x) { err += ++x*2+1; if (-y == x && e2 <= y) e2 = 0; } if (e2 > y) err += ++y*2+1; } while (y <= 0); } } // Draw a filled ellipse. // cx: specifies the X position // cy: specifies the Y position // radius1: minor radius of ellipse. // radius2: major radius of ellipse. // fillcolor : specifies the Color to use for Fill the Ellipse. // bordercolor: specifies the Color to use for draw the Border from the Ellipse. void VGA_T4::drawfilledellipse(int16_t cx, int16_t cy, int16_t radius1, int16_t radius2, vga_pixel fillcolor, vga_pixel bordercolor){ int x = -radius1, y = 0, err = 2-2*radius1, e2; float K = 0, rad1 = 0, rad2 = 0; rad1 = radius1; rad2 = radius2; if (radius1 > radius2) { do { K = (float)(rad1/rad2); draw_v_line((cx+x), (cy-(uint16_t)(y/K)), (2*(uint16_t)(y/K) + 1) , fillcolor); draw_v_line((cx-x), (cy-(uint16_t)(y/K)), (2*(uint16_t)(y/K) + 1) , fillcolor); e2 = err; if (e2 <= y) { err += ++y*2+1; if (-x == y && e2 <= x) e2 = 0; } if (e2 > x) err += ++x*2+1; } while (x <= 0); } else { y = -radius2; x = 0; do { K = (float)(rad2/rad1); draw_h_line((cx-(uint16_t)(x/K)), (cy+y), (2*(uint16_t)(x/K) + 1) , fillcolor); draw_h_line((cx-(uint16_t)(x/K)), (cy-y), (2*(uint16_t)(x/K) + 1) , fillcolor); e2 = err; if (e2 <= x) { err += ++x*2+1; if (-y == x && e2 <= y) e2 = 0; } if (e2 > y) err += ++y*2+1; } while (y <= 0); } drawellipse(cx,cy,radius1,radius2,bordercolor); } //-------------------------------------------------------------- // Draw a Triangle. // ax,ay, bx,by, cx,cy - the triangle points. // color - color of the triangle. //-------------------------------------------------------------- void VGA_T4::drawtriangle(int16_t ax, int16_t ay, int16_t bx, int16_t by, int16_t cx, int16_t cy, vga_pixel color){ drawline(ax , ay , bx , by , color); drawline(bx , by , cx , cy , color); drawline(cx , cy , ax , ay , color); } //-------------------------------------------------------------- // Draw a Filled Triangle. // ax,ay, bx,by, cx,cy - the triangle points. // fillcolor - specifies the Color to use for Fill the triangle. // bordercolor - specifies the Color to use for draw the Border from the triangle. //-------------------------------------------------------------- void VGA_T4::drawfilledtriangle(int16_t ax, int16_t ay, int16_t bx, int16_t by, int16_t cx, int16_t cy, vga_pixel fillcolor, vga_pixel bordercolor){ float ma, mb, mc ; //'gradient of the lines float start, finish ; //'draw a line from start to finish! float tempspace ; //'temporary storage for swapping values... double x1,x2,x3 ; double y1,y2,y3 ; int16_t n ; //' need to sort out ay, by and cy into order.. highest to lowest //' if(ay < by) { //'swap x's tempspace = ax; ax = bx; bx = tempspace; //'swap y's tempspace = ay; ay = by; by = tempspace; } if(ay < cy) { //'swap x's tempspace = ax; ax = cx; cx = tempspace; //'swap y's tempspace = ay; ay = cy; cy = tempspace; } if(by < cy) { //'swap x's tempspace = bx; bx = cx; cx = tempspace; //'swap y's tempspace = by; by = cy; cy = tempspace; } //' Finally - copy the values in order... x1 = ax; x2 = bx; x3 = cx; y1 = ay; y2 = by; y3 = cy; //'bodge if y coordinates are the same if(y1 == y2) y2 = y2 + 0.01; if(y2 == y3) y3 = y3 + 0.01; if(y1 == y3) y3 = y3 + 0.01; ma = (x1 - x2) / (y1 - y2); mb = (x3 - x2) / (y2 - y3); mc = (x3 - x1) / (y1 - y3); //'from y1 to y2 for(n = 0;n >= (y2 - y1);n--) { start = n * mc; finish = n * ma; drawline((int16_t)(x1 - start), (int16_t)(n + y1), (int16_t)(x1 + finish), (int16_t)(n + y1), fillcolor); } //'and from y2 to y3 for(n = 0;n >= (y3 - y2);n--) { start = n * mc; finish = n * mb; drawline((int16_t)(x1 - start - ((y2 - y1) * mc)), (int16_t)(n + y2), (int16_t)(x2 - finish), (int16_t)(n + y2), fillcolor); } // draw the border color triangle drawtriangle(ax,ay,bx,by,cx,cy,bordercolor); } //-------------------------------------------------------------- // Displays a Rectangle at a given Angle. // centerx : specifies the center of the Rectangle. // centery // w,h : specifies the size of the Rectangle. // angle : specifies the angle for drawing the rectangle // color : specifies the Color to use for Fill the Rectangle. //-------------------------------------------------------------- void VGA_T4::drawquad(int16_t centerx, int16_t centery, int16_t w, int16_t h, int16_t angle, vga_pixel color){ int16_t px[4],py[4]; float l; float raddeg = 3.14159 / 180; float w2 = w / 2.0; float h2 = h / 2.0; float vec = (w2*w2)+(h2*h2); float w2l; float pangle[4]; l = sqrtf(vec); w2l = w2 / l; pangle[0] = acosf(w2l) / raddeg; pangle[1] = 180.0 - (acosf(w2l) / raddeg); pangle[2] = 180.0 + (acosf(w2l) / raddeg); pangle[3] = 360.0 - (acosf(w2l) / raddeg); px[0] = (int16_t)(calcco[((int16_t)(pangle[0]) + angle) % 360] * l + centerx); py[0] = (int16_t)(calcsi[((int16_t)(pangle[0]) + angle) % 360] * l + centery); px[1] = (int16_t)(calcco[((int16_t)(pangle[1]) + angle) % 360] * l + centerx); py[1] = (int16_t)(calcsi[((int16_t)(pangle[1]) + angle) % 360] * l + centery); px[2] = (int16_t)(calcco[((int16_t)(pangle[2]) + angle) % 360] * l + centerx); py[2] = (int16_t)(calcsi[((int16_t)(pangle[2]) + angle) % 360] * l + centery); px[3] = (int16_t)(calcco[((int16_t)(pangle[3]) + angle) % 360] * l + centerx); py[3] = (int16_t)(calcsi[((int16_t)(pangle[3]) + angle) % 360] * l + centery); // here we draw the quad drawline(px[0],py[0],px[1],py[1],color); drawline(px[1],py[1],px[2],py[2],color); drawline(px[2],py[2],px[3],py[3],color); drawline(px[3],py[3],px[0],py[0],color); } //-------------------------------------------------------------- // Displays a filled Rectangle at a given Angle. // centerx : specifies the center of the Rectangle. // centery // w,h : specifies the size of the Rectangle. // angle : specifies the angle for drawing the rectangle // fillcolor : specifies the Color to use for Fill the Rectangle. // bordercolor : specifies the Color to use for draw the Border from the Rectangle. //-------------------------------------------------------------- void VGA_T4::drawfilledquad(int16_t centerx, int16_t centery, int16_t w, int16_t h, int16_t angle, vga_pixel fillcolor, vga_pixel bordercolor){ int16_t px[4],py[4]; float l; float raddeg = 3.14159 / 180; float w2 = w / 2.0; float h2 = h / 2.0; float vec = (w2*w2)+(h2*h2); float w2l; float pangle[4]; l = sqrtf(vec); w2l = w2 / l; pangle[0] = acosf(w2l) / raddeg; pangle[1] = 180.0 - (acosf(w2l) / raddeg); pangle[2] = 180.0 + (acosf(w2l) / raddeg); pangle[3] = 360.0 - (acosf(w2l) / raddeg); px[0] = (int16_t)(calcco[((int16_t)(pangle[0]) + angle) % 360] * l + centerx); py[0] = (int16_t)(calcsi[((int16_t)(pangle[0]) + angle) % 360] * l + centery); px[1] = (int16_t)(calcco[((int16_t)(pangle[1]) + angle) % 360] * l + centerx); py[1] = (int16_t)(calcsi[((int16_t)(pangle[1]) + angle) % 360] * l + centery); px[2] = (int16_t)(calcco[((int16_t)(pangle[2]) + angle) % 360] * l + centerx); py[2] = (int16_t)(calcsi[((int16_t)(pangle[2]) + angle) % 360] * l + centery); px[3] = (int16_t)(calcco[((int16_t)(pangle[3]) + angle) % 360] * l + centerx); py[3] = (int16_t)(calcsi[((int16_t)(pangle[3]) + angle) % 360] * l + centery); // We draw 2 filled triangle for made the quad // To be uniform we have to use only the Fillcolor drawfilledtriangle(px[0],py[0],px[1],py[1],px[2],py[2],fillcolor,fillcolor); drawfilledtriangle(px[2],py[2],px[3],py[3],px[0],py[0],fillcolor,fillcolor); // here we draw the BorderColor from the quad drawline(px[0],py[0],px[1],py[1],bordercolor); drawline(px[1],py[1],px[2],py[2],bordercolor); drawline(px[2],py[2],px[3],py[3],bordercolor); drawline(px[3],py[3],px[0],py[0],bordercolor); } //-------------------------------------------------------------- // Displays a Polygon. // centerx : are specified with PolySet.Center.x and y. // centery // cx : Translate the polygon in x direction // cy : Translate the polygon in y direction // bordercolor : specifies the Color to use for draw the Border from the polygon. // polygon points : are specified with PolySet.Pts[n].x and y // After the last polygon point , set PolySet.Pts[n + 1].x to 10000 // Max number of point for the polygon is set by MaxPolyPoint previously defined. //-------------------------------------------------------------- void VGA_T4::drawpolygon(int16_t cx, int16_t cy, vga_pixel bordercolor){ uint8_t n = 1; while((PolySet.Pts[n].x < 10000) && (n < MaxPolyPoint)){ drawline(PolySet.Pts[n].x + cx, PolySet.Pts[n].y + cy, PolySet.Pts[n - 1].x + cx , PolySet.Pts[n - 1].y + cy, bordercolor); n++; } // close the polygon drawline(PolySet.Pts[0].x + cx, PolySet.Pts[0].y + cy, PolySet.Pts[n - 1].x + cx, PolySet.Pts[n - 1].y + cy, bordercolor); } //-------------------------------------------------------------- // Displays a filled Polygon. // centerx : are specified with PolySet.Center.x and y. // centery // cx : Translate the polygon in x direction // cy : Translate the polygon in y direction // fillcolor : specifies the Color to use for filling the polygon. // bordercolor : specifies the Color to use for draw the Border from the polygon. // polygon points : are specified with PolySet.Pts[n].x and y // After the last polygon point , set PolySet.Pts[n + 1].x to 10000 // Max number of point for the polygon is set by MaxPolyPoint previously defined. //-------------------------------------------------------------- void VGA_T4::drawfullpolygon(int16_t cx, int16_t cy, vga_pixel fillcolor, vga_pixel bordercolor){ int n,i,j,k,dy,dx; int y,temp; int a[MaxPolyPoint][2],xi[MaxPolyPoint]; float slope[MaxPolyPoint]; n = 0; while((PolySet.Pts[n].x < 10000) && (n < MaxPolyPoint)){ a[n][0] = PolySet.Pts[n].x; a[n][1] = PolySet.Pts[n].y; n++; } a[n][0]=PolySet.Pts[0].x; a[n][1]=PolySet.Pts[0].y; for(i=0;iy))|| ((a[i][1]>y)&&(a[i+1][1]<=y))) { xi[k]=(int)(a[i][0]+slope[i]*(y-a[i][1])); k++; } } for(j=0;jxi[i+1]) { temp=xi[i]; xi[i]=xi[i+1]; xi[i+1]=temp; } } for(i=0;i= (fb_width-hscr_mask)) return; if ((y + SPRITES_H) <= 0) return; if (y >= fb_height) return; vga_pixel * src=&spritesbuffer[index*SPRITES_W*SPRITES_H]; int i,j; vga_pixel pix; for (j=0; j (fb_width-hscr_mask)) || ((y+j) < 0) || ((y+j) >= fb_height) ) dst++; else *dst++ = pix; } } } static void drawTile(unsigned char tile, int x, int y) { vga_pixel * src=&tilesbuffer[tile*TILES_W*TILES_H]; int i,j; for (j=0; j (fb_width-hscr_mask)) *dst++=0; else *dst++ = pix; } } } static void drawTransTile(unsigned char tile, int x, int y) { vga_pixel * src=&tilesbuffer[tile*TILES_W*TILES_H]; vga_pixel pix; int i,j; for (j=0; j (fb_width-hscr_mask)) src++; else if ((pix=*src++)) *dst++ = pix; else *dst++; } } } static void tileText(unsigned char index, int16_t x, int16_t y, const char * text, vga_pixel fgcolor, vga_pixel bgcolor, vga_pixel *dstbuffer, int dstwidth, int dstheight) { vga_pixel c; vga_pixel * dst; while ((c = *text++)) { const unsigned char * charpt=&font8x8[c][0]; int l=y; for (int i=0;i<8;i++) { unsigned char bits; dst=&dstbuffer[(index*dstheight+l)*dstwidth+x]; bits = *charpt++; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else *dst++=bgcolor; l++; } x +=8; } } static void tileTextOverlay(int16_t x, int16_t y, const char * text, vga_pixel fgcolor) { vga_pixel c; vga_pixel * dst; while ((c = *text++)) { const unsigned char * charpt=&font8x8[c][0]; int l=y; for (int i=0;i<8;i++) { unsigned char bits; dst=&framebuffer[+l*fb_stride+x]; bits = *charpt++; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; bits = bits >> 1; if (bits&0x01) *dst++=fgcolor; else dst++; l++; } x +=8; } } static const char * hex = "0123456789ABCDEF"; void VGA_T4::begin_gfxengine(int nblayers, int nbtiles, int nbsprites) { // Try double buffering if (fb1 == NULL) { void *mallocpt = malloc(fb_stride*fb_height*sizeof(vga_pixel)+4); fb1 = (vga_pixel *)((void*)((intptr_t)mallocpt & ~3)); } if (fb1 != NULL) { init_pio_framebuffer(fb1); framebuffer = fb1+PIO_FB_OFFSET; } nb_layers = nblayers; nb_tiles = nbtiles; nb_sprites = nbsprites; if (spritesbuffer == NULL) spritesbuffer = (vga_pixel*)malloc(SPRITES_W*SPRITES_H*sizeof(vga_pixel)*nb_sprites); if (tilesbuffer == NULL) tilesbuffer = (vga_pixel*)malloc(TILES_W*TILES_H*sizeof(vga_pixel)*nb_tiles); if (tilesram == NULL) tilesram = (unsigned char*)malloc(TILES_COLS*TILES_ROWS*nb_layers); if (spritesdata == NULL) spritesdata = (Sprite_t *)malloc(SPRITES_MAX*sizeof(Sprite_t)); memset((void*)spritesbuffer,0, SPRITES_W*SPRITES_H*sizeof(vga_pixel)*nb_sprites); memset((void*)tilesbuffer,0, TILES_W*TILES_H*sizeof(vga_pixel)*nb_tiles); memset((void*)tilesram,0,TILES_COLS*TILES_ROWS*nb_layers); /* Random test tiles */ char numhex[3]; for (int i=0; i>4) & 0xf]; numhex[1] = hex[i & 0xf]; numhex[2] = 0; if (TILES_W == 16 )tileText(i, 0, 0, numhex, VGA_RGB(0xff,0xff,0xff), VGA_RGB(0x40,0x40,0x40), tilesbuffer,TILES_W,TILES_H); } } /* Random test sprites */ for (int i=0; i>4) & 0xf]; numhex[1] = hex[i & 0xf]; numhex[2] = 0; tileText(i, 0, 0, numhex, VGA_RGB(0xff,0xff,0x00), VGA_RGB(0x00,0x00,0x00),spritesbuffer,SPRITES_W,SPRITES_H); } } } void VGA_T4::run_gfxengine() { waitSync(); if (fb1 != NULL) { if (pio_fb == (uint32_t*)fb0) { pio_fb = (uint32_t*)fb1; visible_framebuffer = fb1+PIO_FB_OFFSET; framebuffer = fb0+PIO_FB_OFFSET; } else { pio_fb = (uint32_t*)fb0; visible_framebuffer = fb0+PIO_FB_OFFSET; framebuffer = fb1+PIO_FB_OFFSET; } } unsigned char * tilept; // Layer 0 for (int j=0; j=hscr_beg[0]) && (j<=hscr_end[0]) ) { int modcol = (hscr[0] >> TILES_HBITS) % TILES_COLS; for (int i=0; i 1) { int lcount = 1; while (lcount < nb_layers) { for (int j=0; j=hscr_beg[lcount]) && (j<=hscr_end[lcount]) ) { int modcol = (hscr[lcount] >> TILES_HBITS) % TILES_COLS; for (int i=0; i> 8); cnt = cnt & (sampleBufferSize*2-1); if (cnt == 0) { fillfirsthalf = false; //irq_set_pending(RTC_IRQ+1); multicore_fifo_push_blocking(0); } else if (cnt == sampleBufferSize) { fillfirsthalf = true; //irq_set_pending(RTC_IRQ+1); multicore_fifo_push_blocking(0); } } static void core1_sio_irq() { irq_clear(SIO_IRQ_PROC1); while(multicore_fifo_rvalid()) { uint16_t raw = multicore_fifo_pop_blocking(); SOFTWARE_isr(); } multicore_fifo_clear_irq(); } void VGA_T4::begin_audio(int samplesize, void (*callback)(short * stream, int len)) { fillsamples = callback; i2s_tx_buffer = (uint32_t*)malloc(samplesize*sizeof(uint32_t)); if (i2s_tx_buffer == NULL) { printf("sound buffer could not be allocated!!!!!\n"); return; } memset((void*)i2s_tx_buffer,0, samplesize*sizeof(uint32_t)); printf("sound buffer allocated\n"); i2s_tx_buffer16 = (short*)i2s_tx_buffer; sampleBufferSize = samplesize; gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM); int audio_pin_slice = pwm_gpio_to_slice_num(AUDIO_PIN); // Setup PWM interrupt to fire when PWM cycle is complete pwm_clear_irq(audio_pin_slice); pwm_set_irq_enabled(audio_pin_slice, true); irq_set_exclusive_handler(PWM_IRQ_WRAP, AUDIO_isr); irq_set_priority (PWM_IRQ_WRAP, 128); irq_set_enabled(PWM_IRQ_WRAP, true); //irq_set_exclusive_handler(RTC_IRQ+1,SOFTWARE_isr); //irq_set_priority (RTC_IRQ+1, 120); //irq_set_enabled(RTC_IRQ+1,true); // Setup PWM for audio output pwm_config config = pwm_get_default_config(); // pwm_config_set_clkdiv(&config, 5.5f); pwm_config_set_clkdiv(&config, 50.0f); pwm_config_set_wrap(&config, 254); pwm_init(audio_pin_slice, &config, true); pwm_set_gpio_level(AUDIO_PIN, 0); printf("sound initialized\n"); } void VGA_T4::end_audio() { if (i2s_tx_buffer != NULL) { free(i2s_tx_buffer); } } #endif