├── .gitignore ├── README.md ├── examples ├── flower.png ├── hello_cario.go ├── hello_gg.go └── hello_gofb.go └── framebuffer ├── framebuffer.go └── framebuffer_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | *.out 3 | *.iml 4 | doc/ 5 | .idea 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gofb 2 | ============================ 3 | Write the linux framebuffer device. 4 | 5 | Usage 6 | ---------------------------- 7 | There are some examples in the example directory. 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/flower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blackspace/gofb/3f19a2588496244b218b696c1ea7dba913442b4e/examples/flower.png -------------------------------------------------------------------------------- /examples/hello_cario.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/ungerik/go-cairo" 5 | "gofb/framebuffer" 6 | "fmt" 7 | ) 8 | 9 | 10 | func main() { 11 | fb := framebuffer.NewFramebuffer() 12 | fb.Init() 13 | defer fb.Release() 14 | surface := cairo.NewSurface(cairo.FORMAT_ARGB32, fb.Xres, fb.Yres) 15 | 16 | 17 | surface.SetSourceRGBA(0,0,0,1) 18 | surface.Rectangle(0,0,float64(fb.Xres), float64(fb.Yres)) 19 | surface.Fill() 20 | surface.SelectFontFace("serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) 21 | surface.SetFontSize(32.0) 22 | surface.SetSourceRGBA(1,1,1,1) 23 | surface.MoveTo(10.0, 50.0) 24 | surface.ShowText("道可道 非常道") 25 | data:=surface.GetData() 26 | fb.DrawData(0,0,data,fb.Xres, fb.Yres) 27 | 28 | 29 | surface.Finish() 30 | 31 | fmt.Scanln() 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /examples/hello_gg.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gofb/framebuffer" 5 | "fmt" 6 | "github.com/fogleman/gg" 7 | "image" 8 | "os" 9 | ) 10 | 11 | func main() { 12 | 13 | fb := framebuffer.NewFramebuffer() 14 | defer fb.Release() 15 | 16 | fb.Init() 17 | 18 | const S = 1024 19 | w:=1680 20 | h:=1050 21 | dc := gg.NewContext(w,h) 22 | dc.DrawRectangle(0,0,float64(w),float64(h)) 23 | dc.SetRGB(1, 1, 1) 24 | dc.Fill() 25 | 26 | 27 | f,err:=os.Open("./flower.png") 28 | if err!=nil { 29 | panic(err.Error()) 30 | } 31 | 32 | flower,_,err:=image.Decode(f) 33 | if err!=nil { 34 | panic(err.Error()) 35 | } 36 | 37 | dc.DrawImage(flower,w-flower.Bounds().Max.X,h-flower.Bounds().Max.Y) 38 | 39 | dc.SetRGBA(0, 0, 0, 0.1) 40 | for i := 0; i < 360; i += 15 { 41 | dc.Push() 42 | dc.RotateAbout(gg.Radians(float64(i)), S/2, S/2) 43 | dc.DrawEllipse(S/2, S/2, S*7/16, S/8) 44 | dc.Fill() 45 | dc.Pop() 46 | } 47 | 48 | 49 | fb.DrawImage(0,0,dc.Image()) 50 | 51 | 52 | fmt.Scanln() 53 | } 54 | 55 | -------------------------------------------------------------------------------- /examples/hello_gofb.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gofb/framebuffer" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | 10 | fb := framebuffer.NewFramebuffer() 11 | defer fb.Release() 12 | 13 | fb.Init() 14 | fb.Fill(255,255,255,0) 15 | 16 | fmt.Scanln() 17 | } 18 | 19 | -------------------------------------------------------------------------------- /framebuffer/framebuffer.go: -------------------------------------------------------------------------------- 1 | package framebuffer 2 | 3 | /* 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int OpenFrameBuffer(char * name) { 12 | return open(name, O_RDWR); 13 | } 14 | 15 | static int GetFixedScreenInformation(int fd,struct fb_fix_screeninfo *finfo) 16 | { 17 | 18 | return ioctl(fd, FBIOGET_FSCREENINFO, finfo); 19 | } 20 | 21 | 22 | static int GetVarScreenInformation(int fd,struct fb_var_screeninfo *vinfo) { 23 | return ioctl(fd, FBIOGET_VSCREENINFO, vinfo); 24 | } 25 | */ 26 | import "C" 27 | import ( 28 | "errors" 29 | "fmt" 30 | "unsafe" 31 | "image" 32 | "os/exec" 33 | ) 34 | 35 | type Framebuffer struct { 36 | Fd int 37 | BitsPerPixel int 38 | Xres int 39 | Yres int 40 | Data []byte 41 | Xoffset int 42 | Yoffset int 43 | LineLength int 44 | Screensize int 45 | } 46 | 47 | func NewFramebuffer() *Framebuffer { 48 | return &Framebuffer{} 49 | } 50 | 51 | func _HideCursor() { 52 | fmt.Print("\033[?25l") 53 | exec.Command(`kill `) 54 | } 55 | 56 | func _ShowCursor() { 57 | fmt.Printf("\033[?25h") 58 | } 59 | 60 | func (f *Framebuffer)Init() { 61 | _HideCursor() 62 | dev_file:=C.CString("/dev/fb0") 63 | fd,err:=C.OpenFrameBuffer(dev_file) 64 | C.free(unsafe.Pointer(dev_file)) 65 | 66 | if err!= nil { 67 | panic(errors.New("Open the framebuffer failed")) 68 | } 69 | 70 | var finfo C.struct_fb_fix_screeninfo 71 | if _, err := C.GetFixedScreenInformation(fd, &finfo); err != nil { 72 | fmt.Println(err) 73 | } 74 | 75 | var vinfo C.struct_fb_var_screeninfo 76 | if _, err := C.GetVarScreenInformation(fd, &vinfo); err != nil { 77 | fmt.Println(err) 78 | } 79 | 80 | f.Xres=int(vinfo.xres) 81 | f.Yres=int(vinfo.yres) 82 | f.BitsPerPixel=int(vinfo.bits_per_pixel) 83 | f.Xoffset=int(vinfo.xoffset) 84 | f.Yoffset=int(vinfo.yoffset) 85 | f.LineLength=int(finfo.line_length) 86 | 87 | f.Screensize=int(finfo.smem_len) 88 | 89 | addr:= uintptr(C.mmap(nil, C.size_t(f.Screensize), C.PROT_READ | C.PROT_WRITE, C.MAP_SHARED, fd, 0)) 90 | 91 | 92 | var sl = struct { 93 | addr uintptr 94 | len int 95 | cap int 96 | }{addr, f.Screensize, f.Screensize} 97 | 98 | f.Data= *(*[]byte)(unsafe.Pointer(&sl)) 99 | 100 | 101 | } 102 | 103 | func (f *Framebuffer)Release() { 104 | C.munmap(unsafe.Pointer(&f.Data[0]), C.size_t(f.Screensize)) 105 | C.close(C.int(f.Fd)) 106 | _ShowCursor() 107 | } 108 | 109 | func (f *Framebuffer)SetPixel(x int,y int,r uint32,g uint32,b uint32,a uint32) { 110 | if x<0 || x>f.Xres { 111 | panic(errors.New("X is too big or is negative")) 112 | } 113 | 114 | if y<0 || y>f.Yres { 115 | panic(errors.New("Y is too big or is negative")) 116 | } 117 | 118 | location := (x + f.Xoffset) *(f.BitsPerPixel / 8) + (y + f.Yoffset) * f.LineLength 119 | 120 | f.Data[location+3]=byte(a&0xff) 121 | f.Data[location+2]=byte(r&0xff) 122 | f.Data[location+1]=byte(g&0xff) 123 | f.Data[location]=byte(b&0xff) 124 | } 125 | 126 | func (f *Framebuffer)DrawImage(xoffset int,yoffset int,image image.Image) { 127 | 128 | b:=image.Bounds() 129 | 130 | for y:=0;yf.Xres { 141 | panic(errors.New("The width of data must NOT be bigger the Xres of the framebuffer")) 142 | } 143 | 144 | for y:=0;ylen(data) { 146 | panic(errors.New("The length of image data is too small or w(h) argument is wrong")) 147 | } 148 | 149 | 150 | line_start := (xoffset + f.Xoffset) *(f.BitsPerPixel / 8) + (y + yoffset + f.Yoffset) * f.LineLength 151 | line_end := (xoffset + f.Xoffset) *(f.BitsPerPixel / 8) + (y +1+ yoffset + f.Yoffset) * f.LineLength-1 152 | 153 | if line_start +w>line_end { 154 | panic(errors.New("The lines is too long beyond the framebuffer")) 155 | } 156 | 157 | data_line :=data[y*w*4:(y+1)*w*4] 158 | copy(f.Data[line_start:line_start +w*4], data_line) 159 | } 160 | 161 | } 162 | 163 | func (f *Framebuffer)Fill(r,g,b,a uint32) { 164 | for y:=0;y