【无标题】

本文介绍了如何在Ubuntu 20.04环境下通过底层操作控制显存绘制简单图形,包括圆形、直线和矩形,展示了如何使用`mmap`函数获取显存地址并设置颜色。涉及关键函数如`mmap`、`ioctl`和显存操作技巧。
摘要由CSDN通过智能技术生成

ubuntu中使用 控制显存方法 绘制简单形状。

  • ubuntu版本U20.04,不同版本的显示宽度可能不同
  • ubuntu自带桌面会影响绘图,可以使用sudo init 3 老版可用:ctrl+alt+F1切换到字符界面,F1-F6是六个字符界面,F7是图形界面,ctrl+alt+F7返回图形界面。

基本显示原理:显示器会自动将显存中的数据输出到屏幕上(不同位置的数据对应不同的坐标点),数据格式是:四个字节:(不透明度、R、G、B) 如:0xffff0000,表示的是这个不透明的红色点、坐标和在显存中的地址有关系。

1.获取(0,0)的点的显示地址;

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

完整代码如下:


/*===============================================
* 文件名称:mycat.c
* 创 建 者:
* 创建日期:2022年06月24日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdio.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define OUTINFO 1
//显示器显示宽度
#define LINE_LENGTH 1176

int *addr = NULL;

void drawing_round(int x, int y, int r, int color);

void drawing_wire(int x1, int y1, int x2, int y2, unsigned int color);
void drawing_H(int x1, int x2, int y, int color);
void drawing_V(int y1, int y2, int x, int color);

void draw_rect(int x, int y, int w, int h);
void draw_rect_color(int x, int y, int w, int h, int color, int icolor);

void draw_point(int x, int y, int color);

int main(int argc, char *argv[])
{
    int ret;
    struct fb_var_screeninfo fbi_var; //定义可变参数
    struct fb_fix_screeninfo fbi_fix; //定义固定参数
    struct fb_cmap cmap;
    //打开屏幕设备
    int fd = open("/dev/fb0", O_RDWR);
    if (fd < 0)
    {
        perror("open");
        close(fd);
    }
    // 得到虚拟屏幕参数 ret = ioctl(fd, FBIOGET_VSCREENINFO, &fbi_var);
    if (ret < 0)
    {
        perror("ioctl");
        return NULL;
    }
#if OUTINFO
    printf("fbi.var.xres:%u ,fbi.var.yres:%u ,var.bpp:%d\n", fbi_var.xres, fbi_var.yres, fbi_var.bits_per_pixel);
    printf("fbi.var.xoffset:%u ,fbi.var.yoffset:%u\n", fbi_var.xoffset, fbi_var.yoffset);
#endif
    //得到实际屏幕参数
    ret = ioctl(fd, FBIOGET_FSCREENINFO, &fbi_fix);
    if (ret < 0)
    {
        perror("ioctl");
        return NULL;
    }
#if OUTINFO
    printf("fbi.fix.smem_start:%lu,fbi.fix.smem_len:%u\n", fbi_fix.smem_start, fbi_fix.smem_len);
    printf("line_length: %u\n", fbi_fix.line_length);
#endif
    //获取显存起始地址
    addr = mmap(NULL, fbi_fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (addr == NULL)
    {
        perror("mmap");
        ret = munmap(addr, fbi_fix.smem_len);
        return NULL;
    }
#if 0
    puts("Please enter the starting position and the length and width (both are shaped and separated by Spaces):");
    int x, y, w, h;
    scanf("%d %d %d %d", &x, &y, &w, &h);
    getchar();
    puts("Please enter the border color and fill color: HEX value. (Space separated) Enter the default");
    char buf[128] = {0};
    fgets(buf, sizeof(buf), stdin);
    int color = 0xffff0000, icolor = 0xff0000ff;
    if (strlen(buf) > 1)
    {
        sscanf(buf, "%x %x", &color, &icolor);
    }
    draw_rect_color(x, y, w, h, color, icolor);
#endif

#if 0

    drawing_wire(200, 200, 350, 250, 0xff00ff00);
    drawing_wire(200, 200, 150, 250, 0xff00ff00);
    drawing_wire(150, 250, 350, 250, 0xff00ff00);
#endif

#if 1
    int r = 100;
    drawing_round(300, 300, 100, 0xff00ff00);
    for (int i = 0; i < 100; i++)
    {
        drawing_round(300, 300, i + 10, i * 0xff | 0xff00ff00);
    }

#endif
    close(fd);
    return 0;
}

void drawing_round(int x1, int y1, int r, int color)
{
    int x;
    int y = sqrt(r * r - (x - x1) * (x - x1)) + y1;
    int temp;
    for (x = x1 - r; x <= x1 + r; x++)
    {
        // y = sqrt(r * r - (x - x1) * (x - x1)) + y1;
        temp = sqrt(r * r - (x - x1) * (x - x1));
        draw_point(x, temp + y1, color);
        draw_point(x, y1 - temp, color);
    }
}

void draw_rect_color(int x, int y, int w, int h, int color, int icolor)
{
    drawing_H(x, x + w, y, color);
    for (int i = 1; i < h; i++)
    {
        drawing_H(x, x + w, y + i, icolor);
    }
    drawing_H(x, x + w, y + h, color);

    drawing_V(y, y + h, x, color);

    drawing_V(y, y + h, x + w, color);
}

void draw_rect(int x, int y, int w, int h)
{
    drawing_H(x, x + w, y, 0xff00ff00);
    drawing_V(y, y + h, x, 0xff00ff00);

    drawing_H(x, x + w, y + h, 0xff00ff00);
    drawing_V(y, y + h, x + w, 0xff00ff00);
}

void drawing_H(int x1, int x2, int y, int color)
{
    int width = x2 - x1;
    int *addrH = addr + y * LINE_LENGTH + x1;
    while (width > 0)
    {
        *addrH = color;
        addrH++;
        width--;
    }
}

void drawing_V(int y1, int y2, int x, int color)
{
    //画竖线
    int *addr_h = addr + y1 * LINE_LENGTH + x;
    int length = y2 - y1;
    for (int i = 0; i < length; i++)
    {
        *addr_h = color;
        addr_h += LINE_LENGTH;
    }
}

void draw_point(int x, int y, int color)
{
    int *addr_temp = addr + y * LINE_LENGTH + x;
    *addr_temp = color;
}

void drawing_wire(int x1, int y1, int x2, int y2, unsigned int color)
{
    if (x2 == x1)
    {
        drawing_V(y1, y2, x1, color);
    }
    if (y2 == y1)
    {
        drawing_H(x1, x2, y2, color);
    }
    double k = (double)(y2 - y1) / (x2 - x1);
    int x = x1 > x2 ? x2 : x1;
    int y;
    for (x = (x1 > x2 ? x2 : x1); x < (x1 > x2 ? x1 : x2); x++)
    {
        y = k * (x - x1) + y1;
        draw_point(x, y, color);
    }
}

运行结果:
在这里插入图片描述

注:本片中可能存在一些错误,自行甄别,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值