在MCU上移植使用tinygl

文摘   2024-11-11 17:13   湖南  

一. 前言

有时候我们需要在MCU上进行一些图像处理,比如变换,3D显示等,希望有类似opengl的工具,恰好Tinygl就是这样一个不错的选择。其官方网页为:https://bellard.org/TinyGL/。它的作者就是开发出了ffmpeg等项目的大牛FabriceBellard,可以见其网站https://bellard.org/, 可以看到该网站上还有很多的项目,包括QEMU,TCC,每一个都是核弹级别。我们这一篇就来介绍其中一个项目tinygl, 分享tinyglMCU上的移植使用。

二. Tinygl简介

网址:https://bellard.org/TinyGL/,最新版本为0.4.1下载地址https://bellard.org/TinyGL/TinyGL-0.4.1.tar.gz

TinyGL OpenGL 的一个小型实现,适用于嵌入式系统。纯实现,实现了OpenGL 的主要调用。优势在于速度快、简单易用,因为它无需完全兼容OpenGL。特别是,它的纹理映射和几何变换速度非常快。例如,与Mesa Solaris OpenWin OpenGL 实现相比,TinyGL 的速度要快得多,后者是VReng 虚拟现实引擎的OpenGL 实现。

TinyGL的主要特点如下:

OpenGL兼容的头文件。

类似于Zlib的许可协议,便于在商业设计中进行集成。

GLX的子集,便于在X Window上进行测试。

类似于GLXAPINGLX),用于与NanoX一起使用。

BeOS下的BGLView子集。

类似于OpenGL的光照效果。

有限的OpenGL 1.1数组支持。

完整的OpenGL选择模式处理,用于对象选择。

16Z缓冲区。16RGB显示。可以进行高速调色板8位处理。可以进行高速24位或32位转换。

优化的16RGB Gouraud着色,以实现快速阴影绘制。

具有透视校正和纹理对象的快速纹理映射功能。

仅使用32位浮点数进行算术运算。

非常小巧:在x86上编译后的代码大小约为40 KB

支持32位和64位架构的GCC C源代码。在x86-Linuxsparc-Solaris上成功测试。

架构:

由以下四个主要模块组成,

数学函数库(zmath)。

OpenGL类似仿真(zgl)。

Z缓冲区和光栅化(zbuffer)。

GLX接口(zglx)。

三. 移植到MCU

3.1添加源码

我们使用github上的一个基于原版改造的版本,更适合移植。

下载代码

git clone https://github.com/jserv/tinygl

文件如下

tinygl/|-- INTEGRATION|-- LICENSE|-- Makefile|-- README.md|-- assets|   |-- blend.gif|   |-- capture.gif|   |-- capture2.gif|   |-- helloworld.gif|   |-- model.gif|   |-- model2.gif|   |-- model2_lit.gif|   |-- model_hole.gif|   |-- model_lit.gif|   |-- specular.gif|   |-- texture_test.png|   `-- tgl_minimal.png|-- config.mk|-- examples|   |-- 3dmath.h|   |-- raw|   |   |-- Makefile|   |   `-- gears.c|   |-- sdl|   |   |-- Makefile|   |   |-- extrude.obj|   |   |-- game.c|   |   |-- gears.c|   |   |-- hello.c|   |   |-- model.c|   |   |-- monkey3.obj|   |   |-- tex.jpg|   |   |-- tex_hole.png|   |   |-- tex_old.jpg|   |   |-- texture.c|   |   `-- texture.png|   `-- tobjparse.h|-- include|   |-- TGL|   |   `-- gl.h|   |-- zbuffer.h|   `-- zfeatures.h|-- lib`-- src    |-- Makefile    |-- api.c    |-- arrays.c    |-- clear.c    |-- clip.c    |-- error_check.h    |-- error_check_no_context.h    |-- font8x8_basic.h    |-- get.c    |-- image_util.c    |-- init.c    |-- light.c    |-- list.c    |-- matrix.c    |-- memory.c    |-- misc.c    |-- msghandling.c    |-- msghandling.h    |-- opinfo.h    |-- select.c    |-- specbuf.c    |-- texture.c    |-- vertex.c    |-- zbuffer.c    |-- zgl.h    |-- zline.c    |-- zline.h    |-- zmath.c    |-- zmath.h    |-- zpostprocess.c    |-- zraster.c    |-- ztext.c    |-- ztriangle.c    `-- ztriangle.h
8 directories, 70 files

添加tinygl/src下所有c文件到自己的工程

设置头文件包含路径tinygl/include/

3.2依赖

math.h

sin

cos

Fabs

sqrt

按需替换

src/memory.c

malloccallocfree接口按需替换

M_PI

3.3修改编译告警

include/TGL/gl.h

GLenum glGetError();

改为

GLenum glGetError(void);

否则报错

acore/tinygl/include/TGL/gl.h:1111:1: warning: function declaration isn't a prototype [-Wstrict-prototypes]

1111 | GLenum glGetError();

还有其他很多类似的参数为空, 按照编译器要求添加(void).

tinygl/src/init.c

glInitTextures(c);

改为

glInitTextures();

该函数无需参数。

3.4配置

tinygl/include/zfeatures.h

显示如果采用16位则配置为

#define TGL_FEATURE_16_BITS 1

#define TGL_FEATURE_32_BITS 0

32位则配置为

#define TGL_FEATURE_16_BITS 0

#define TGL_FEATURE_32_BITS 1

3.5添加测试代码

添加tinygl/examples/raw/gears.c到工程

int main(int argc, char **argv)

改为

int gears_main(int argc, char **argv)

在自己合适的地方调用

删除

#define STBIW_ASSERT(x)

#define STB_IMAGE_WRITE_IMPLEMENTATION

#include "stb_image_write.h"

添加自己的显示接口头文件,比如我这里是

#include lcd.h

gears_main

int winSizeX = 640, winSizeY = 480;

改为自己显示设备的实际大小

        uint8_t *pbuf = malloc(3 * winSizeX * winSizeY);        for (int i = 0; i < winSizeX * winSizeY; i++) {            pbuf[3 * i + 0] = GET_RED(imbuf[i]);            pbuf[3 * i + 1] = GET_GREEN(imbuf[i]);            pbuf[3 * i + 2] = GET_BLUE(imbuf[i]);        }        stbi_write_png("render.png", winSizeX, winSizeY, 3, pbuf, 0);        free(imbuf);        free(pbuf);

改为自己的显示操作, 即将imbuf的内容进行显示,和前面设置BITS对应,32位即对应RGB88816位为RGB565

比如lcd_fill((uint8_t*)imbuf);

或者按点操作

      for (int i = 0; i < winSizeX * winSizeY; i++) {

          dis_itf_set_pixel_0(i, GET_RED(imbuf[i]), GET_GREEN(imbuf[i]), GET_BLUE(imbuf[i]));

      }

或者直接将frameBuffer的内容写入显存显示无需再调用

ZB_copyFrameBuffer

减少一次内存拷贝。

按需替换以下接口

printf

free

malloc

calloc

sin

cos

sqrt

注释掉

  //fflush(stdout);

最开始添加宏

#ifndef M_PI

#define M_PI 3.14159265

#endif

static void draw()

改为

static void draw(void)

还有其他类似的根据编译器告警修改即可。

3.6注意

ZB_open

Imbuf

开辟帧缓存需要堆比较大。

Gears.c

#include "zfeatures.h"

否则宏不同步

#if TGL_FEATURE_RENDER_BITS == 32

if (frames > 0)

break;

改为以下,这样可以不断更新帧,动态显示动起来

  if (frames > 10000)            break;        for (int i = 0; i < winSizeX * winSizeY; i++) {            dis_itf_set_pixel_0(i, GET_RED(imbuf[i]), GET_GREEN(imbuf[i]), GET_BLUE(imbuf[i]));         }

3.7测试

我这里是通过UVC显示

四. 总结

Tinygl的移植比较简单,只依赖mathsin,cos,sqrt以及,malloc,free等少数接口,嵌入式平台需要按需移植。

操作流程是

开辟缓存 frameBuffer = ZB_open

初始化gl glInit(frameBuffer);

... gl接口操作

...缓存frameBuffer 显示

清除缓存ZB_close(frameBuffer);

关闭glClose();



嵌入式Lee
嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。
 最新文章