From 6d8557b624a959766063c6f91d29de4a667232a7 Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Thu, 24 Sep 2026 09:57:25 -0300 Subject: [PATCH 1/2] graphics/tinygl: add TinyGL software OpenGL library Add TinyGL (https://github.com/C-Chads/tinygl), a small software-only implementation of a subset of OpenGL 1.1 written in portable C99, by Fabrice Bellard, Gek and C-Chads, under a zlib-style license. Like graphics/lvgl, the sources are not kept in the repository: the build downloads a pinned git revision from GitHub (CONFIG_TINYGL_VERSION) and applies the NuttX patches that live next to the Makefile: 0001 zfeatures: allow overriding the feature switches at build time 0002 Fix -Wstrict-prototypes warnings 0003 zbuffer: do not over-read the source in ZB_copyFrameBuffer() 0004 zbuffer.h: make the default allocator wrappers static inline The TinyGL compile time features (pixel depth, GL_SELECT, GL_POLYGON, blending, texture size, ...) are exposed as CONFIG_TINYGL_* Kconfig options. They change public structures, so Make.defs / CMakeLists.txt export them to every application that includes or . Both the make and the CMake builds are supported. An unpack stamp file makes sure an object directory created inside the source tree is never mistaken for downloaded sources. Assisted-by: Claude Opus 5.5 (1M context) Signed-off-by: Alan Carvalho de Assis --- graphics/tinygl/.gitignore | 2 + ...overriding-the-feature-switches-at-b.patch | 228 ++++++++++++++++++ ...0002-Fix-Wstrict-prototypes-warnings.patch | 131 ++++++++++ ...ver-read-the-source-in-ZB_copyFrameB.patch | 43 ++++ ...he-default-allocator-wrappers-static.patch | 34 +++ ...t-array-parameters-const-as-OpenGL-d.patch | 182 ++++++++++++++ graphics/tinygl/CMakeLists.txt | 153 ++++++++++++ graphics/tinygl/Kconfig | 108 +++++++++ graphics/tinygl/Make.defs | 55 +++++ graphics/tinygl/Makefile | 100 ++++++++ 10 files changed, 1036 insertions(+) create mode 100644 graphics/tinygl/.gitignore create mode 100644 graphics/tinygl/0001-zfeatures-allow-overriding-the-feature-switches-at-b.patch create mode 100644 graphics/tinygl/0002-Fix-Wstrict-prototypes-warnings.patch create mode 100644 graphics/tinygl/0003-zbuffer-do-not-over-read-the-source-in-ZB_copyFrameB.patch create mode 100644 graphics/tinygl/0004-zbuffer.h-make-the-default-allocator-wrappers-static.patch create mode 100644 graphics/tinygl/0005-Declare-the-input-array-parameters-const-as-OpenGL-d.patch create mode 100644 graphics/tinygl/CMakeLists.txt create mode 100644 graphics/tinygl/Kconfig create mode 100644 graphics/tinygl/Make.defs create mode 100644 graphics/tinygl/Makefile diff --git a/graphics/tinygl/.gitignore b/graphics/tinygl/.gitignore new file mode 100644 index 00000000000..5723a78b863 --- /dev/null +++ b/graphics/tinygl/.gitignore @@ -0,0 +1,2 @@ +/tinygl +/tinygl-*.tar.gz diff --git a/graphics/tinygl/0001-zfeatures-allow-overriding-the-feature-switches-at-b.patch b/graphics/tinygl/0001-zfeatures-allow-overriding-the-feature-switches-at-b.patch new file mode 100644 index 00000000000..06ed1760f04 --- /dev/null +++ b/graphics/tinygl/0001-zfeatures-allow-overriding-the-feature-switches-at-b.patch @@ -0,0 +1,228 @@ +From 7b0dd7f5ccc8826f8c49977b1d26f640fd959738 Mon Sep 17 00:00:00 2001 +From: Alan Carvalho de Assis +Date: Thu, 24 Sep 2026 09:45:18 -0300 +Subject: [PATCH 1/2] zfeatures: allow overriding the feature switches at build + time + +Wrap every tunable TGL_FEATURE_* (and related) definition in +include/zfeatures.h, and POLYGON_MAX_VERTEX in src/zgl.h, with #ifndef +so that a build system can select the features with -D compiler flags +instead of editing the header. + +NuttX uses this to drive the TinyGL features from Kconfig +(CONFIG_TINYGL_*). The defaults are unchanged. +--- + include/zfeatures.h | 66 +++++++++++++++++++++++++++++++++++++++++++++ + src/zgl.h | 2 ++ + 2 files changed, 68 insertions(+) + +diff --git a/include/zfeatures.h b/include/zfeatures.h +index aa7a14c..a67249e 100644 +--- a/include/zfeatures.h ++++ b/include/zfeatures.h +@@ -6,80 +6,134 @@ + Enables setting the error flags when there's an error, so you can check it with glGetError + Disabling this has slight performance gains. + */ ++#ifndef TGL_FEATURE_ERROR_CHECK + #define TGL_FEATURE_ERROR_CHECK 0 ++#endif + /* + Strict out-of-memory checking. All OpenGL function calls are invalidated (ALL OF THEM) if a GL_OUT_OF_MEMORY error occurs. + This means that TinyGL has to constantly check all gl_malloc() attempts for errors and the state of the error state variable. + The checks slow down the renderer so it is not recommended , but + it's in the GL spec that this should occur. + */ ++#ifndef TGL_FEATURE_STRICT_OOM_CHECKS + #define TGL_FEATURE_STRICT_OOM_CHECKS 0 ++#endif + + /* + Swap between using the inline'd malloc(), calloc(), and free() in zbuffer.h, or + a replacement gl_malloc(), gl_zalloc(), and gl_free() in memory.c + */ ++#ifndef TGL_FEATURE_CUSTOM_MALLOC + #define TGL_FEATURE_CUSTOM_MALLOC 0 ++#endif + + /* + Use Fast Inverse Square Root. Toggleable because it's actually slower on some platforms, + And because some systems may have float types which are incompatible with it. + */ ++#ifndef TGL_FEATURE_FISR + #define TGL_FEATURE_FISR 0 ++#endif + ++#ifndef TGL_FEATURE_ARRAYS + #define TGL_FEATURE_ARRAYS 1 ++#endif + ++#ifndef TGL_FEATURE_DISPLAYLISTS + #define TGL_FEATURE_DISPLAYLISTS 1 ++#endif + ++#ifndef TGL_FEATURE_LIT_TEXTURES + #define TGL_FEATURE_LIT_TEXTURES 1 ++#endif + /*Enable the patternized "discard"-ing of pixels.*/ ++#ifndef TGL_FEATURE_POLYGON_STIPPLE + #define TGL_FEATURE_POLYGON_STIPPLE 1 ++#endif + /*Enable the use of GL_SELECT and GL_FEEDBACK*/ ++#ifndef TGL_FEATURE_ALT_RENDERMODES + #define TGL_FEATURE_ALT_RENDERMODES 0 ++#endif + /* + Enable the rendering of large polygons (in terms of vertex count) + Also enabled the rendering of line loops. + the maximum number of vertices in a polygon is defined in zgl.h + */ ++#ifndef TGL_FEATURE_GL_POLYGON + #define TGL_FEATURE_GL_POLYGON 0 ++#endif + ++#ifndef TGL_FEATURE_BLEND + #define TGL_FEATURE_BLEND 1 ++#endif + ++#ifndef TGL_FEATURE_BLEND_DRAW_PIXELS + #define TGL_FEATURE_BLEND_DRAW_PIXELS 0 ++#endif + /*The width of textures as a power of 2. The default is 8, or 256x256 textures.*/ ++#ifndef TGL_FEATURE_TEXTURE_POW2 + #define TGL_FEATURE_TEXTURE_POW2 8 ++#endif + #define TGL_FEATURE_TEXTURE_DIM (1< +Date: Thu, 24 Sep 2026 09:47:19 -0300 +Subject: [PATCH 2/2] Fix -Wstrict-prototypes warnings + +Declare functions that take no arguments as (void) instead of (). In +C, () means "unspecified arguments", which newer compilers warn about +and which C23 changes meaning of. The public glGetError() declaration +in is included by every application, so the warning showed +up in all users of the library too. +--- + include/GL/gl.h | 2 +- + src/init.c | 2 +- + src/matrix.c | 2 +- + src/memory.c | 2 +- + src/misc.c | 4 ++-- + src/texture.c | 2 +- + src/zgl.h | 6 +++--- + 7 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/include/GL/gl.h b/include/GL/gl.h +index da16f81..ab4a10b 100644 +--- a/include/GL/gl.h ++++ b/include/GL/gl.h +@@ -932,7 +932,7 @@ void glHint(GLint target,GLint mode); + void glGetIntegerv(GLint pname,GLint *params); + void glGetFloatv(GLint pname, GLfloat *v); + const GLubyte* glGetString(GLenum name); +-GLenum glGetError(); ++GLenum glGetError(void); + void glFrontFace(GLint mode); + + /* opengl 1.2 arrays */ +diff --git a/src/init.c b/src/init.c +index a394759..9220904 100644 +--- a/src/init.c ++++ b/src/init.c +@@ -69,7 +69,7 @@ static void endSharedState(GLContext* c) { + #if TGL_FEATURE_TINYGL_RUNTIME_COMPAT_TEST == 1 + + #define TGL_FLOAT_ERR(a, b) ((a - b) / b) +-static int TinyGLRuntimeCompatibilityTest() { ++static int TinyGLRuntimeCompatibilityTest(void) { + GLfloat t = -0, tf2; + GLint t2 = 1 << 31; + memcpy(&tf2, &t2, 4); +diff --git a/src/matrix.c b/src/matrix.c +index 6234352..2bba0c6 100644 +--- a/src/matrix.c ++++ b/src/matrix.c +@@ -8,7 +8,7 @@ void gl_print_matrix(const GLfloat* m) { + } + } + +-static void gl_matrix_update() { ++static void gl_matrix_update(void) { + GLContext* c = gl_get_context(); + c->matrix_model_projection_updated = (c->matrix_mode <= 1); + } +diff --git a/src/memory.c b/src/memory.c +index 7cf44c5..5d9ae8a 100644 +--- a/src/memory.c ++++ b/src/memory.c +@@ -2,7 +2,7 @@ + * Memory allocator for TinyGL + */ + +-static inline void required_for_compilation_(){ ++static inline void required_for_compilation_(void){ + return; + } + +diff --git a/src/misc.c b/src/misc.c +index c7f1bb7..1b48fa2 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -192,7 +192,7 @@ void glopPolygonOffset(GLParam* p) { + c->offset_units = p[2].f; + } + +-GLenum glGetError() { ++GLenum glGetError(void) { + #if TGL_FEATURE_ERROR_CHECK == 1 + GLContext* c = gl_get_context(); + GLenum eflag = c->error_flag; +@@ -256,4 +256,4 @@ void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format + /* TODO: implement read pixels.*/ + } + +-void glFinish() { return; } ++void glFinish(void) { return; } +diff --git a/src/texture.c b/src/texture.c +index c2e5364..470a621 100644 +--- a/src/texture.c ++++ b/src/texture.c +@@ -109,7 +109,7 @@ GLTexture* alloc_texture(GLint h) { + return t; + } + +-void glInitTextures() { ++void glInitTextures(void) { + /* textures */ + GLContext* c = gl_get_context(); + c->texture_2d_enabled = 0; +diff --git a/src/zgl.h b/src/zgl.h +index aa1ea70..cd82c00 100644 +--- a/src/zgl.h ++++ b/src/zgl.h +@@ -429,8 +429,8 @@ void glopTranslate(GLParam *p);*/ + void gl_enable_disable_light(GLint light, GLint v); + void gl_shade_vertex(GLVertex* v); + +-void glInitTextures(); +-void glEndTextures(); ++void glInitTextures(void); ++void glEndTextures(void); + GLTexture* alloc_texture(GLint h); + + /* image_util.c */ +@@ -456,7 +456,7 @@ GLSpecBuf* specbuf_get_buffer(const GLint shininess_i, const GLfloat shininess); + /* this clip epsilon is needed to avoid some rounding errors after + several clipping stages */ + +-static void gl_eval_viewport() { ++static void gl_eval_viewport(void) { + GLContext* c = gl_get_context(); + GLViewport* v; + GLfloat zsize = (1 << (ZB_Z_BITS + ZB_POINT_Z_FRAC_BITS)); +-- +2.43.0 + diff --git a/graphics/tinygl/0003-zbuffer-do-not-over-read-the-source-in-ZB_copyFrameB.patch b/graphics/tinygl/0003-zbuffer-do-not-over-read-the-source-in-ZB_copyFrameB.patch new file mode 100644 index 00000000000..02094b7918b --- /dev/null +++ b/graphics/tinygl/0003-zbuffer-do-not-over-read-the-source-in-ZB_copyFrameB.patch @@ -0,0 +1,43 @@ +From cb43569fb11bb988335056622f6f8db4ac2c7a14 Mon Sep 17 00:00:00 2001 +From: Alan Carvalho de Assis +Date: Thu, 24 Sep 2026 09:47:54 -0300 +Subject: [PATCH] zbuffer: do not over-read the source in + ZB_copyFrameBuffer() + +ZB_copyBuffer() copied `linesize` bytes per line, where linesize is the +pitch of the destination buffer. When the destination is wider than +the TinyGL buffer (e.g. a hardware framebuffer whose lines are padded), +this read past the end of every source line and, on the last line, past +the end of the TinyGL pixel buffer. + +Copy zb->linesize bytes, the size of a TinyGL line, and keep using the +destination pitch only to step through the destination. +--- + src/zbuffer.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/zbuffer.c b/src/zbuffer.c +index 6321340..e3e822c 100644 +--- a/src/zbuffer.c ++++ b/src/zbuffer.c +@@ -131,7 +131,7 @@ static void ZB_copyBuffer(ZBuffer* zb, void* buf, GLint linesize) { + *(((PIXEL*)p1) + i) = *(q + i); + } + #else +- memcpy(p1, q, linesize); ++ memcpy(p1, q, zb->linesize); + #endif + + +@@ -148,7 +148,7 @@ static void ZB_copyBuffer(ZBuffer* zb, void* buf, GLint linesize) { + *(((PIXEL*)p1) + i) = *(q + i); + } + #else +- memcpy(p1, q, linesize); ++ memcpy(p1, q, zb->linesize); + #endif + } + #endif +-- +2.43.0 + diff --git a/graphics/tinygl/0004-zbuffer.h-make-the-default-allocator-wrappers-static.patch b/graphics/tinygl/0004-zbuffer.h-make-the-default-allocator-wrappers-static.patch new file mode 100644 index 00000000000..22023d898bd --- /dev/null +++ b/graphics/tinygl/0004-zbuffer.h-make-the-default-allocator-wrappers-static.patch @@ -0,0 +1,34 @@ +From a3c2ac6a18ef6a91fcbbe6027d7d07f7a15a08f6 Mon Sep 17 00:00:00 2001 +From: Alan Carvalho de Assis +Date: Thu, 24 Sep 2026 09:50:16 -0300 +Subject: [PATCH] zbuffer.h: make the default allocator wrappers static inline + +gl_malloc(), gl_zalloc() and gl_free() are defined in the public + as plain static functions when TGL_FEATURE_CUSTOM_MALLOC is +0. Every application that includes the header but does not call them +then gets three -Wunused-function warnings. Declaring them static +inline keeps the same behaviour without the warnings. +--- + include/zbuffer.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/include/zbuffer.h b/include/zbuffer.h +index 886eb72..c54c9bd 100644 +--- a/include/zbuffer.h ++++ b/include/zbuffer.h +@@ -354,9 +354,9 @@ void *gl_zalloc(GLint size); + #else + #include + #include +-static void gl_free(void* p) { free(p); } +-static void* gl_malloc(GLint size) { return malloc(size); } +-static void* gl_zalloc(GLint size) { return calloc(1, size); } ++static inline void gl_free(void* p) { free(p); } ++static inline void* gl_malloc(GLint size) { return malloc(size); } ++static inline void* gl_zalloc(GLint size) { return calloc(1, size); } + #endif + + #endif /* _tgl_zbuffer_h_ */ +-- +2.43.0 + diff --git a/graphics/tinygl/0005-Declare-the-input-array-parameters-const-as-OpenGL-d.patch b/graphics/tinygl/0005-Declare-the-input-array-parameters-const-as-OpenGL-d.patch new file mode 100644 index 00000000000..96726ec1440 --- /dev/null +++ b/graphics/tinygl/0005-Declare-the-input-array-parameters-const-as-OpenGL-d.patch @@ -0,0 +1,182 @@ +From 202a4eba444f29055174ee33394a608607c4d35a Mon Sep 17 00:00:00 2001 +From: Alan Carvalho de Assis +Date: Sat, 26 Sep 2026 13:51:30 -0300 +Subject: [PATCH] Declare the input array parameters const, as OpenGL does + +glMaterialfv(), glLightfv(), glLightModelfv(), the glVertex*v(), +glColor*v(), glNormal*v(), glTexCoord*v() and glRasterPos*v() families +only read the array they are passed, and OpenGL declares that parameter +const. Do the same, so that callers can pass constant data, for +example "static const GLfloat red[4]", without casts or warnings. +--- + include/GL/gl.h | 28 ++++++++++++++-------------- + src/api.c | 16 ++++++++-------- + src/zraster.c | 6 +++--- + 3 files changed, 25 insertions(+), 25 deletions(-) + +diff --git a/include/GL/gl.h b/include/GL/gl.h +index ab4a10b..1f651fc 100644 +--- a/include/GL/gl.h ++++ b/include/GL/gl.h +@@ -804,26 +804,26 @@ void glPlotPixel(GLint x, GLint y, GLuint pixel); + #define PROTO_GL1(name) \ + void gl ## name ## 1f(GLfloat); \ + void gl ## name ## 1d(GLdouble); \ +-void gl ## name ## 1fv(GLfloat *); \ +-void gl ## name ## 1dv(GLdouble *); ++void gl ## name ## 1fv(const GLfloat *); \ ++void gl ## name ## 1dv(const GLdouble *); + + #define PROTO_GL2(name) \ + void gl ## name ## 2f(GLfloat ,GLfloat); \ + void gl ## name ## 2d(GLdouble ,GLdouble); \ +-void gl ## name ## 2fv(GLfloat *); \ +-void gl ## name ## 2dv(GLdouble *); ++void gl ## name ## 2fv(const GLfloat *); \ ++void gl ## name ## 2dv(const GLdouble *); + + #define PROTO_GL3(name) \ + void gl ## name ## 3f(GLfloat ,GLfloat ,GLfloat); \ + void gl ## name ## 3d(GLdouble ,GLdouble ,GLdouble); \ +-void gl ## name ## 3fv(GLfloat *); \ +-void gl ## name ## 3dv(GLdouble *); ++void gl ## name ## 3fv(const GLfloat *); \ ++void gl ## name ## 3dv(const GLdouble *); + + #define PROTO_GL4(name) \ + void gl ## name ## 4f(GLfloat ,GLfloat ,GLfloat, GLfloat ); \ + void gl ## name ## 4d(GLdouble ,GLdouble ,GLdouble, GLdouble ); \ +-void gl ## name ## 4fv(GLfloat *); \ +-void gl ## name ## 4dv(GLdouble *); ++void gl ## name ## 4fv(const GLfloat *); \ ++void gl ## name ## 4dv(const GLdouble *); + + PROTO_GL2(Vertex) + PROTO_GL3(Vertex) +@@ -915,14 +915,14 @@ GLboolean glAreTexturesResident( GLsizei n, + GLboolean glIsTexture( GLuint texture); + /* lighting */ + +-void glMaterialfv(GLint mode,GLint type,GLfloat *v); ++void glMaterialfv(GLint mode,GLint type,const GLfloat *v); + void glMaterialf(GLint mode,GLint type,GLfloat v); + void glColorMaterial(GLint mode,GLint type); + +-void glLightfv(GLint light,GLint type,GLfloat *v); ++void glLightfv(GLint light,GLint type,const GLfloat *v); + void glLightf(GLint light,GLint type,GLfloat v); + void glLightModeli(GLint pname,GLint param); +-void glLightModelfv(GLint pname,GLfloat *param); ++void glLightModelfv(GLint pname,const GLfloat *param); + + /* misc */ + +@@ -978,9 +978,9 @@ void glRasterPos2f(GLfloat, GLfloat); + void glRasterPos3f(GLfloat, GLfloat, GLfloat); + void glRasterPos4f(GLfloat, GLfloat, GLfloat, GLfloat); + +-void glRasterPos2fv(GLfloat* v); +-void glRasterPos3fv(GLfloat* v); +-void glRasterPos4fv(GLfloat* v); ++void glRasterPos2fv(const GLfloat* v); ++void glRasterPos3fv(const GLfloat* v); ++void glRasterPos4fv(const GLfloat* v); + void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void* data); + void glPixelZoom(GLfloat x, GLfloat y); + +diff --git a/src/api.c b/src/api.c +index e310a1b..3f082b5 100644 +--- a/src/api.c ++++ b/src/api.c +@@ -17,7 +17,7 @@ void glVertex2f(GLfloat x, GLfloat y) { glVertex4f(x, y, 0, 1); } + + void glVertex3f(GLfloat x, GLfloat y, GLfloat z) { glVertex4f(x, y, z, 1); } + +-void glVertex3fv(GLfloat* v) { glVertex4f(v[0], v[1], v[2], 1); } ++void glVertex3fv(const GLfloat* v) { glVertex4f(v[0], v[1], v[2], 1); } + + /* glNormal */ + +@@ -40,7 +40,7 @@ void glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { + glEnd(); + } + +-void glNormal3fv(GLfloat* v) { glNormal3f(v[0], v[1], v[2]); } ++void glNormal3fv(const GLfloat* v) { glNormal3f(v[0], v[1], v[2]); } + + /* glColor */ + +@@ -58,7 +58,7 @@ void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { + gl_add_op(p); + } + +-void glColor4fv(GLfloat* v) { ++void glColor4fv(const GLfloat* v) { + GLParam p[8]; + #include "error_check_no_context.h" + p[0].op = OP_Color; +@@ -75,7 +75,7 @@ void glColor4fv(GLfloat* v) { + + void glColor3f(GLfloat x, GLfloat y, GLfloat z) { glColor4f(x, y, z, 1); } + +-void glColor3fv(GLfloat* v) { glColor4f(v[0], v[1], v[2], 1); } ++void glColor3fv(const GLfloat* v) { glColor4f(v[0], v[1], v[2], 1); } + + /* TexCoord */ + +@@ -93,7 +93,7 @@ void glTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) { + + void glTexCoord2f(GLfloat s, GLfloat t) { glTexCoord4f(s, t, 0, 1); } + +-void glTexCoord2fv(GLfloat* v) { glTexCoord4f(v[0], v[1], 0, 1); } ++void glTexCoord2fv(const GLfloat* v) { glTexCoord4f(v[0], v[1], 0, 1); } + + void glEdgeFlag(GLint flag) { + GLParam p[2]; +@@ -360,7 +360,7 @@ void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLd + + /* lightening */ + +-void glMaterialfv(GLint mode, GLint type, GLfloat* v) { ++void glMaterialfv(GLint mode, GLint type, const GLfloat* v) { + GLParam p[7]; + GLint i, n; + #define NEED_CONTEXT +@@ -410,7 +410,7 @@ void glColorMaterial(GLint mode, GLint type) { + gl_add_op(p); + } + +-void glLightfv(GLint light, GLint type, GLfloat* v) { ++void glLightfv(GLint light, GLint type, const GLfloat* v) { + GLParam p[7]; + GLint i; + #include "error_check_no_context.h" +@@ -450,7 +450,7 @@ void glLightModeli(GLint pname, GLint param) { + gl_add_op(p); + } + +-void glLightModelfv(GLint pname, GLfloat* param) { ++void glLightModelfv(GLint pname, const GLfloat* param) { + GLParam p[6]; + GLint i; + #include "error_check_no_context.h" +diff --git a/src/zraster.c b/src/zraster.c +index d19cfb2..334e317 100644 +--- a/src/zraster.c ++++ b/src/zraster.c +@@ -67,9 +67,9 @@ void glopRasterPos(GLParam* p) { + void glRasterPos2f(GLfloat x, GLfloat y) { glRasterPos4f(x, y, 0, 1); } + void glRasterPos3f(GLfloat x, GLfloat y, GLfloat z) { glRasterPos4f(x, y, z, 1); } + +-void glRasterPos2fv(GLfloat* v) { glRasterPos2f(v[0], v[1]); } +-void glRasterPos3fv(GLfloat* v) { glRasterPos3f(v[0], v[1], v[2]); } +-void glRasterPos4fv(GLfloat* v) { glRasterPos4f(v[0], v[1], v[2], v[3]); } ++void glRasterPos2fv(const GLfloat* v) { glRasterPos2f(v[0], v[1]); } ++void glRasterPos3fv(const GLfloat* v) { glRasterPos3f(v[0], v[1], v[2]); } ++void glRasterPos4fv(const GLfloat* v) { glRasterPos4f(v[0], v[1], v[2], v[3]); } + + void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void* data) { + /* TODO: Come up with a clever scheme for storing the data to avoid pointer dependency. */ +-- +2.43.0 + diff --git a/graphics/tinygl/CMakeLists.txt b/graphics/tinygl/CMakeLists.txt new file mode 100644 index 00000000000..a58cb154c3a --- /dev/null +++ b/graphics/tinygl/CMakeLists.txt @@ -0,0 +1,153 @@ +# ############################################################################## +# apps/graphics/tinygl/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_GRAPHICS_TINYGL) + + # ############################################################################ + # Fetch and patch TinyGL + # ############################################################################ + + set(TINYGL_DIR ${CMAKE_CURRENT_LIST_DIR}/tinygl) + + if(NOT EXISTS ${TINYGL_DIR}) + file(GLOB TINYGL_PATCHES + ${CMAKE_CURRENT_LIST_DIR}/[0-9][0-9][0-9][0-9]-*.patch) + list(SORT TINYGL_PATCHES) + set(TINYGL_PATCH_COMMAND "") + foreach(p ${TINYGL_PATCHES}) + list( + APPEND + TINYGL_PATCH_COMMAND + COMMAND + patch + -s + -N + -p1 + -d + ${TINYGL_DIR} + -i + ${p}) + endforeach() + list(POP_FRONT TINYGL_PATCH_COMMAND) + + FetchContent_Declare( + tinygl_fetch + URL ${CONFIG_TINYGL_URL}/${CONFIG_TINYGL_VERSION}.tar.gz SOURCE_DIR + ${TINYGL_DIR} BINARY_DIR + ${NUTTX_BINARY_DIR}/apps/graphics/tinygl/tinygl + PATCH_COMMAND ${TINYGL_PATCH_COMMAND} + DOWNLOAD_NO_PROGRESS true + TIMEOUT 60) + + FetchContent_GetProperties(tinygl_fetch) + + if(NOT tinygl_fetch_POPULATED) + FetchContent_Populate(tinygl_fetch) + endif() + endif() + + # ############################################################################ + # Feature switches (they change public structures, so export them) + # ############################################################################ + + macro(tinygl_bool var cfg) + if(${cfg}) + set(${var} 1) + else() + set(${var} 0) + endif() + endmacro() + + tinygl_bool(TGL_32 CONFIG_TINYGL_RENDER_BITS_32) + tinygl_bool(TGL_16 CONFIG_TINYGL_RENDER_BITS_16) + tinygl_bool(TGL_SELECT CONFIG_TINYGL_SELECT) + tinygl_bool(TGL_POLYGON CONFIG_TINYGL_GL_POLYGON) + tinygl_bool(TGL_BLEND CONFIG_TINYGL_BLEND) + tinygl_bool(TGL_BLEND_DP CONFIG_TINYGL_BLEND_DRAW_PIXELS) + tinygl_bool(TGL_STIPPLE CONFIG_TINYGL_POLYGON_STIPPLE) + tinygl_bool(TGL_NODRAW CONFIG_TINYGL_NO_DRAW_COLOR) + tinygl_bool(TGL_ERRCHK CONFIG_TINYGL_ERROR_CHECK) + + set(TINYGL_DEFINES + TGL_FEATURE_32_BITS=${TGL_32} + TGL_FEATURE_16_BITS=${TGL_16} + TGL_FEATURE_TEXTURE_POW2=${CONFIG_TINYGL_TEXTURE_POW2} + TGL_FEATURE_ALT_RENDERMODES=${TGL_SELECT} + TGL_FEATURE_GL_POLYGON=${TGL_POLYGON} + TGL_FEATURE_BLEND=${TGL_BLEND} + TGL_FEATURE_BLEND_DRAW_PIXELS=${TGL_BLEND_DP} + TGL_FEATURE_POLYGON_STIPPLE=${TGL_STIPPLE} + TGL_FEATURE_NO_DRAW_COLOR=${TGL_NODRAW} + TGL_FEATURE_ERROR_CHECK=${TGL_ERRCHK}) + + if(CONFIG_TINYGL_POLYGON_MAX_VERTEX) + list(APPEND TINYGL_DEFINES + POLYGON_MAX_VERTEX=${CONFIG_TINYGL_POLYGON_MAX_VERTEX}) + endif() + + # ############################################################################ + # Library + # ############################################################################ + + set(SRCS + ${TINYGL_DIR}/src/accum.c + ${TINYGL_DIR}/src/api.c + ${TINYGL_DIR}/src/arrays.c + ${TINYGL_DIR}/src/clear.c + ${TINYGL_DIR}/src/clip.c + ${TINYGL_DIR}/src/get.c + ${TINYGL_DIR}/src/image_util.c + ${TINYGL_DIR}/src/init.c + ${TINYGL_DIR}/src/light.c + ${TINYGL_DIR}/src/list.c + ${TINYGL_DIR}/src/matrix.c + ${TINYGL_DIR}/src/memory.c + ${TINYGL_DIR}/src/misc.c + ${TINYGL_DIR}/src/msghandling.c + ${TINYGL_DIR}/src/select.c + ${TINYGL_DIR}/src/specbuf.c + ${TINYGL_DIR}/src/texture.c + ${TINYGL_DIR}/src/vertex.c + ${TINYGL_DIR}/src/zbuffer.c + ${TINYGL_DIR}/src/zline.c + ${TINYGL_DIR}/src/zmath.c + ${TINYGL_DIR}/src/zpostprocess.c + ${TINYGL_DIR}/src/zraster.c + ${TINYGL_DIR}/src/ztext.c + ${TINYGL_DIR}/src/ztriangle.c) + + nuttx_add_library(tinygl) + target_sources(tinygl PRIVATE ${SRCS}) + target_compile_options( + tinygl PRIVATE -Wno-shadow -Wno-undef -Wno-unused-function + -Wno-unknown-pragmas -Wno-unused-variable) + target_compile_definitions(tinygl PRIVATE NDEBUG) + + set_property( + TARGET nuttx + APPEND + PROPERTY NUTTX_INCLUDE_DIRECTORIES ${TINYGL_DIR}/include) + set_property( + TARGET nuttx + APPEND + PROPERTY NUTTX_DEFINITIONS ${TINYGL_DEFINES}) +endif() diff --git a/graphics/tinygl/Kconfig b/graphics/tinygl/Kconfig new file mode 100644 index 00000000000..f9dda35c706 --- /dev/null +++ b/graphics/tinygl/Kconfig @@ -0,0 +1,108 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig GRAPHICS_TINYGL + bool "TinyGL software OpenGL 1.1 subset" + default n + ---help--- + Enable TinyGL, a small software-only implementation of a subset of + OpenGL 1.1 originally written by Fabrice Bellard and maintained by + C-Chads (https://github.com/C-Chads/tinygl). + + TinyGL renders into a memory buffer (struct ZBuffer). The result + can be copied to a NuttX framebuffer device (/dev/fbN) with + ZB_copyFrameBuffer(), or TinyGL can render directly into the + mmap()ed framebuffer memory. + + The sources are downloaded from GitHub at build time and patched + for NuttX (see the patches in apps/graphics/tinygl). + +if GRAPHICS_TINYGL + +config TINYGL_URL + string "TinyGL download URL" + default "https://github.com/C-Chads/tinygl/archive" + ---help--- + Base URL of the TinyGL source archives. The file + .tar.gz is downloaded from here. + +config TINYGL_VERSION + string "TinyGL git revision" + default "36a7987e7bebfda19615ea33341b1cc0ff9c3b13" + ---help--- + Git commit of C-Chads/tinygl to download. The NuttX patches are + made against this revision. + +choice + prompt "TinyGL pixel format" + default TINYGL_RENDER_BITS_32 + +config TINYGL_RENDER_BITS_32 + bool "32 bits per pixel (XRGB8888)" + +config TINYGL_RENDER_BITS_16 + bool "16 bits per pixel (RGB565)" + +endchoice # TinyGL pixel format + +config TINYGL_TEXTURE_POW2 + int "Texture size (log2)" + default 8 + range 4 10 + ---help--- + TinyGL uses a single, fixed texture size set at compile time. All + textures are resized to (1 << TINYGL_TEXTURE_POW2) pixels square. + The default of 8 means 256x256 textures, which use 256KiB each in + 32-bit mode. + +config TINYGL_SELECT + bool "Support GL_SELECT and GL_FEEDBACK render modes" + default n + ---help--- + Enable glRenderMode(GL_SELECT) (object picking with + glSelectBuffer()/glLoadName()) and GL_FEEDBACK. Enabling this makes + all rendering slightly slower. + +config TINYGL_GL_POLYGON + bool "Support GL_POLYGON and GL_LINE_LOOP" + default y + ---help--- + Enable rendering of general polygons (up to + TINYGL_POLYGON_MAX_VERTEX vertices) and line loops. + +config TINYGL_POLYGON_MAX_VERTEX + int "Maximum number of vertices in a GL_POLYGON" + default 16 + depends on TINYGL_GL_POLYGON + +config TINYGL_BLEND + bool "Support blending (glBlendFunc)" + default y + +config TINYGL_BLEND_DRAW_PIXELS + bool "Apply blending to glDrawPixels()" + default n + depends on TINYGL_BLEND + +config TINYGL_POLYGON_STIPPLE + bool "Support polygon stipple (glPolygonStipple)" + default y + +config TINYGL_NO_DRAW_COLOR + bool "Skip texels with the no-draw color (0xff00ff)" + default y + ---help--- + When enabled, texture mapped pixels whose color is exactly + magenta (0xff00ff) are not drawn, which gives cheap cut-out + textures. + +config TINYGL_ERROR_CHECK + bool "Enable glGetError() error checking" + default n + ---help--- + Set GL error flags on invalid calls so that they can be read with + glGetError(). Useful for debugging, slightly slower. + +endif # GRAPHICS_TINYGL diff --git a/graphics/tinygl/Make.defs b/graphics/tinygl/Make.defs new file mode 100644 index 00000000000..fdf7e5f77d7 --- /dev/null +++ b/graphics/tinygl/Make.defs @@ -0,0 +1,55 @@ +############################################################################ +# apps/graphics/tinygl/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_GRAPHICS_TINYGL),) +CONFIGURED_APPS += $(APPDIR)/graphics/tinygl + +# TinyGL public headers: , and + +CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/tinygl/tinygl/include +CXXFLAGS += ${INCDIR_PREFIX}$(APPDIR)/graphics/tinygl/tinygl/include + +# The TinyGL feature switches change the layout of public structures (for +# example struct ZBuffer and the PIXEL type), so they must be seen by both +# the library and every application that includes the TinyGL headers. + +tgl_bool = $(if $(filter y,$(1)),1,0) + +TINYGL_DEFINES = -DTGL_FEATURE_32_BITS=$(call tgl_bool,$(CONFIG_TINYGL_RENDER_BITS_32)) +TINYGL_DEFINES += -DTGL_FEATURE_16_BITS=$(call tgl_bool,$(CONFIG_TINYGL_RENDER_BITS_16)) +TINYGL_DEFINES += -DTGL_FEATURE_TEXTURE_POW2=$(CONFIG_TINYGL_TEXTURE_POW2) +TINYGL_DEFINES += -DTGL_FEATURE_ALT_RENDERMODES=$(call tgl_bool,$(CONFIG_TINYGL_SELECT)) +TINYGL_DEFINES += -DTGL_FEATURE_GL_POLYGON=$(call tgl_bool,$(CONFIG_TINYGL_GL_POLYGON)) +TINYGL_DEFINES += -DTGL_FEATURE_BLEND=$(call tgl_bool,$(CONFIG_TINYGL_BLEND)) +TINYGL_DEFINES += -DTGL_FEATURE_BLEND_DRAW_PIXELS=$(call tgl_bool,$(CONFIG_TINYGL_BLEND_DRAW_PIXELS)) +TINYGL_DEFINES += -DTGL_FEATURE_POLYGON_STIPPLE=$(call tgl_bool,$(CONFIG_TINYGL_POLYGON_STIPPLE)) +TINYGL_DEFINES += -DTGL_FEATURE_NO_DRAW_COLOR=$(call tgl_bool,$(CONFIG_TINYGL_NO_DRAW_COLOR)) +TINYGL_DEFINES += -DTGL_FEATURE_ERROR_CHECK=$(call tgl_bool,$(CONFIG_TINYGL_ERROR_CHECK)) + +ifneq ($(CONFIG_TINYGL_POLYGON_MAX_VERTEX),) +TINYGL_DEFINES += -DPOLYGON_MAX_VERTEX=$(CONFIG_TINYGL_POLYGON_MAX_VERTEX) +endif + +CFLAGS += $(TINYGL_DEFINES) +CXXFLAGS += $(TINYGL_DEFINES) + +endif diff --git a/graphics/tinygl/Makefile b/graphics/tinygl/Makefile new file mode 100644 index 00000000000..ef45a578d42 --- /dev/null +++ b/graphics/tinygl/Makefile @@ -0,0 +1,100 @@ +############################################################################ +# apps/graphics/tinygl/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# TinyGL software OpenGL library + +TINYGL_URL = $(patsubst "%",%,$(strip $(CONFIG_TINYGL_URL))) +TINYGL_VERSION = $(patsubst "%",%,$(strip $(CONFIG_TINYGL_VERSION))) +TINYGL_TARBALL = tinygl-$(TINYGL_VERSION).tar.gz +TINYGL_UNPACK = tinygl +TINYGL_PATCHES = $(sort $(wildcard $(CURDIR)/[0-9][0-9][0-9][0-9]-*.patch)) + +SRC = $(TINYGL_UNPACK)/src + +CSRCS = $(SRC)/accum.c +CSRCS += $(SRC)/api.c +CSRCS += $(SRC)/arrays.c +CSRCS += $(SRC)/clear.c +CSRCS += $(SRC)/clip.c +CSRCS += $(SRC)/get.c +CSRCS += $(SRC)/image_util.c +CSRCS += $(SRC)/init.c +CSRCS += $(SRC)/light.c +CSRCS += $(SRC)/list.c +CSRCS += $(SRC)/matrix.c +CSRCS += $(SRC)/memory.c +CSRCS += $(SRC)/misc.c +CSRCS += $(SRC)/msghandling.c +CSRCS += $(SRC)/select.c +CSRCS += $(SRC)/specbuf.c +CSRCS += $(SRC)/texture.c +CSRCS += $(SRC)/vertex.c +CSRCS += $(SRC)/zbuffer.c +CSRCS += $(SRC)/zline.c +CSRCS += $(SRC)/zmath.c +CSRCS += $(SRC)/zpostprocess.c +CSRCS += $(SRC)/zraster.c +CSRCS += $(SRC)/ztext.c +CSRCS += $(SRC)/ztriangle.c + +# TinyGL is third party code, silence the warnings that the NuttX build +# enables but that upstream does not care about. + +CFLAGS += -Wno-shadow -Wno-undef -Wno-unused-function -Wno-unknown-pragmas +CFLAGS += -Wno-unused-variable -DNDEBUG + +$(TINYGL_TARBALL): + $(ECHO_BEGIN)"Downloading: $(TINYGL_TARBALL)" + $(Q) curl -L $(if $(V),,-Ss) -o $(TINYGL_TARBALL) \ + $(TINYGL_URL)/$(TINYGL_VERSION).tar.gz + $(ECHO_END) + +# The stamp file marks a complete unpack + patch, so that a partially +# created tree (for example an object directory) is never mistaken for +# the sources. + +TINYGL_STAMP = $(TINYGL_UNPACK)/.nuttx_patched + +$(TINYGL_STAMP): $(TINYGL_TARBALL) + $(ECHO_BEGIN)"Unpacking: $(TINYGL_TARBALL) -> $(TINYGL_UNPACK)" + $(Q) rm -rf $(TINYGL_UNPACK) tinygl-$(TINYGL_VERSION) + $(Q) tar zxf $(TINYGL_TARBALL) + $(Q) mv tinygl-$(TINYGL_VERSION) $(TINYGL_UNPACK) + $(Q) for p in $(TINYGL_PATCHES); do \ + patch -s -N -p1 -d $(TINYGL_UNPACK) < $$p || exit 1; \ + done + $(Q) touch $@ + $(ECHO_END) + +# Download and unpack tarball if no git repo found + +ifeq ($(wildcard $(TINYGL_UNPACK)/.git),) +context:: $(TINYGL_STAMP) + +distclean:: + $(call DELDIR, $(TINYGL_UNPACK)) + $(call DELFILE, $(TINYGL_TARBALL)) +endif + +include $(APPDIR)/Application.mk From e8a619abc19540e38252869085690775e67d25e6 Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Thu, 24 Sep 2026 09:57:25 -0300 Subject: [PATCH 2/2] examples/tinygl: add TinyGL gears demo Render Brian Paul's classic OpenGL "gears" demo with TinyGL on a NuttX framebuffer device. TinyGL draws each frame into its own ZBuffer, which is then copied to the mmap()ed framebuffer (plus FBIO_UPDATE when CONFIG_FB_UPDATE is enabled), so partially drawn frames are never shown. The frame rate is printed every five seconds. Usage: tinygl [frames] [fbdev] Tested on sim:tinygl (640x480, 32 bpp): about 1400 FPS with CONFIG_DEBUG_FULLOPT on an x86_64 host, with both make and CMake. Assisted-By: Claude Opus 5.5 (1M context) Signed-off-by: Alan Carvalho de Assis --- examples/tinygl/CMakeLists.txt | 37 +++ examples/tinygl/Kconfig | 38 +++ examples/tinygl/Make.defs | 25 ++ examples/tinygl/Makefile | 36 +++ examples/tinygl/tinygl_main.c | 532 +++++++++++++++++++++++++++++++++ 5 files changed, 668 insertions(+) create mode 100644 examples/tinygl/CMakeLists.txt create mode 100644 examples/tinygl/Kconfig create mode 100644 examples/tinygl/Make.defs create mode 100644 examples/tinygl/Makefile create mode 100644 examples/tinygl/tinygl_main.c diff --git a/examples/tinygl/CMakeLists.txt b/examples/tinygl/CMakeLists.txt new file mode 100644 index 00000000000..7078261a791 --- /dev/null +++ b/examples/tinygl/CMakeLists.txt @@ -0,0 +1,37 @@ +# ############################################################################## +# apps/examples/tinygl/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_EXAMPLES_TINYGL) + nuttx_add_application( + NAME + ${CONFIG_EXAMPLES_TINYGL_PROGNAME} + SRCS + tinygl_main.c + STACKSIZE + ${CONFIG_EXAMPLES_TINYGL_STACKSIZE} + PRIORITY + ${CONFIG_EXAMPLES_TINYGL_PRIORITY} + MODULE + ${CONFIG_EXAMPLES_TINYGL} + DEPENDS + tinygl) +endif() diff --git a/examples/tinygl/Kconfig b/examples/tinygl/Kconfig new file mode 100644 index 00000000000..a6f6b70cf38 --- /dev/null +++ b/examples/tinygl/Kconfig @@ -0,0 +1,38 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_TINYGL + tristate "TinyGL gears demo" + default n + depends on GRAPHICS_TINYGL && VIDEO_FB + ---help--- + Render the classic OpenGL "gears" demo with TinyGL on a framebuffer + device. The framebuffer must use the same pixel format as TinyGL + (RGB32 or RGB565, see CONFIG_TINYGL_RENDER_BITS_*). + + Usage: tinygl [frames] [fbdev] + +if EXAMPLES_TINYGL + +config EXAMPLES_TINYGL_DEFAULTFB + string "Default framebuffer driver" + default "/dev/fb0" + +config EXAMPLES_TINYGL_PROGNAME + string "Program name" + default "tinygl" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_TINYGL_PRIORITY + int "Task priority" + default 100 + +config EXAMPLES_TINYGL_STACKSIZE + int "Stack size" + default 16384 + +endif diff --git a/examples/tinygl/Make.defs b/examples/tinygl/Make.defs new file mode 100644 index 00000000000..e0fa1e479b7 --- /dev/null +++ b/examples/tinygl/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/examples/tinygl/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_TINYGL),) +CONFIGURED_APPS += $(APPDIR)/examples/tinygl +endif diff --git a/examples/tinygl/Makefile b/examples/tinygl/Makefile new file mode 100644 index 00000000000..b4939f4fce2 --- /dev/null +++ b/examples/tinygl/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/examples/tinygl/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# TinyGL gears demo built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_TINYGL_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_TINYGL_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_TINYGL_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_TINYGL) + +# TinyGL gears demo + +MAINSRC = tinygl_main.c + +include $(APPDIR)/Application.mk diff --git a/examples/tinygl/tinygl_main.c b/examples/tinygl/tinygl_main.c new file mode 100644 index 00000000000..9da6ffecf51 --- /dev/null +++ b/examples/tinygl/tinygl_main.c @@ -0,0 +1,532 @@ +/**************************************************************************** + * apps/examples/tinygl/tinygl_main.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* The gear drawing code is based on the classic "gears" demo by Brian Paul, + * which is in the public domain, as shipped with TinyGL in + * Raw_Demos/gears.c. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#if TGL_FEATURE_RENDER_BITS == 32 +# define TINYGL_FB_FMT FB_FMT_RGB32 +# define TINYGL_ZB_MODE ZB_MODE_RGBA +#else +# define TINYGL_FB_FMT FB_FMT_RGB16_565 +# define TINYGL_ZB_MODE ZB_MODE_5R6G5B +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct tinygl_fb_s +{ + int fd; + FAR uint8_t *fbmem; + struct fb_videoinfo_s vinfo; + struct fb_planeinfo_s pinfo; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static GLfloat g_view_rotx = 20.0f; +static GLfloat g_view_roty = 30.0f; +static GLfloat g_angle; +static GLint g_gear1; +static GLint g_gear2; +static GLint g_gear3; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: gear + * + * Description: + * Draw a gear wheel into the current display list. + * + * Input Parameters: + * inner_radius - radius of the hole at the center + * outer_radius - radius at the center of the teeth + * width - width of the gear + * teeth - number of teeth + * tooth_depth - depth of a tooth + * + ****************************************************************************/ + +static void gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, + GLint teeth, GLfloat tooth_depth) +{ + GLfloat r0 = inner_radius; + GLfloat r1 = outer_radius - tooth_depth / 2.0f; + GLfloat r2 = outer_radius + tooth_depth / 2.0f; + GLfloat da = 2.0f * M_PI / teeth / 4.0f; + GLfloat angle; + GLfloat u; + GLfloat v; + GLfloat len; + GLint i; + + glNormal3f(0.0f, 0.0f, 1.0f); + + /* Front face */ + + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), width * 0.5f); + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), width * 0.5f); + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), width * 0.5f); + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + width * 0.5f); + } + + glEnd(); + + /* Front sides of the teeth */ + + glBegin(GL_QUADS); + for (i = 0; i < teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), width * 0.5f); + glVertex3f(r2 * cosf(angle + da), r2 * sinf(angle + da), + width * 0.5f); + glVertex3f(r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), + width * 0.5f); + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + width * 0.5f); + } + + glEnd(); + + glNormal3f(0.0f, 0.0f, -1.0f); + + /* Back face */ + + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), -width * 0.5f); + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), -width * 0.5f); + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + -width * 0.5f); + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), -width * 0.5f); + } + + glEnd(); + + /* Back sides of the teeth */ + + glBegin(GL_QUADS); + for (i = 0; i < teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + -width * 0.5f); + glVertex3f(r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), + -width * 0.5f); + glVertex3f(r2 * cosf(angle + da), r2 * sinf(angle + da), + -width * 0.5f); + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), -width * 0.5f); + } + + glEnd(); + + /* Outward faces of the teeth */ + + glBegin(GL_QUAD_STRIP); + for (i = 0; i < teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), width * 0.5f); + glVertex3f(r1 * cosf(angle), r1 * sinf(angle), -width * 0.5f); + u = r2 * cosf(angle + da) - r1 * cosf(angle); + v = r2 * sinf(angle + da) - r1 * sinf(angle); + len = sqrtf(u * u + v * v); + u /= len; + v /= len; + glNormal3f(v, -u, 0.0f); + glVertex3f(r2 * cosf(angle + da), r2 * sinf(angle + da), + width * 0.5f); + glVertex3f(r2 * cosf(angle + da), r2 * sinf(angle + da), + -width * 0.5f); + glNormal3f(cosf(angle), sinf(angle), 0.0f); + glVertex3f(r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), + width * 0.5f); + glVertex3f(r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), + -width * 0.5f); + u = r1 * cosf(angle + 3 * da) - r2 * cosf(angle + 2 * da); + v = r1 * sinf(angle + 3 * da) - r2 * sinf(angle + 2 * da); + glNormal3f(v, -u, 0.0f); + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + width * 0.5f); + glVertex3f(r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), + -width * 0.5f); + glNormal3f(cosf(angle), sinf(angle), 0.0f); + } + + glVertex3f(r1, 0.0f, width * 0.5f); + glVertex3f(r1, 0.0f, -width * 0.5f); + glEnd(); + + /* Inside radius cylinder */ + + glBegin(GL_QUAD_STRIP); + for (i = 0; i <= teeth; i++) + { + angle = i * 2.0f * M_PI / teeth; + glNormal3f(-cosf(angle), -sinf(angle), 0.0f); + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), -width * 0.5f); + glVertex3f(r0 * cosf(angle), r0 * sinf(angle), width * 0.5f); + } + + glEnd(); +} + +/**************************************************************************** + * Name: gears_init + ****************************************************************************/ + +static void gears_init(int width, int height) +{ + static GLfloat pos[4] = + { + 5.0f, 5.0f, 10.0f, 0.0f + }; + + static GLfloat red[4] = + { + 0.8f, 0.1f, 0.0f, 1.0f + }; + + static GLfloat green[4] = + { + 0.0f, 0.8f, 0.2f, 1.0f + }; + + static GLfloat blue[4] = + { + 0.2f, 0.2f, 1.0f, 1.0f + }; + + static GLfloat white[4] = + { + 1.0f, 1.0f, 1.0f, 1.0f + }; + + static GLfloat shininess = 5.0f; + GLfloat h = (GLfloat)height / (GLfloat)width; + + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -45.0f); + + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glLightfv(GL_LIGHT0, GL_DIFFUSE, white); + glLightfv(GL_LIGHT0, GL_SPECULAR, white); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + /* Build one display list per gear */ + + g_gear1 = glGenLists(1); + glNewList(g_gear1, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_DIFFUSE, red); + glMaterialfv(GL_FRONT, GL_SPECULAR, white); + glMaterialfv(GL_FRONT, GL_SHININESS, &shininess); + glColor3fv(red); + gear(1.0f, 4.0f, 1.0f, 20, 0.7f); + glEndList(); + + g_gear2 = glGenLists(1); + glNewList(g_gear2, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_DIFFUSE, green); + glMaterialfv(GL_FRONT, GL_SPECULAR, white); + glColor3fv(green); + gear(0.5f, 2.0f, 2.0f, 10, 0.7f); + glEndList(); + + g_gear3 = glGenLists(1); + glNewList(g_gear3, GL_COMPILE); + glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); + glMaterialfv(GL_FRONT, GL_SPECULAR, white); + glColor3fv(blue); + gear(1.3f, 2.0f, 0.5f, 10, 0.7f); + glEndList(); +} + +/**************************************************************************** + * Name: gears_draw + ****************************************************************************/ + +static void gears_draw(void) +{ + g_angle += 2.0f; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix(); + glRotatef(g_view_rotx, 1.0f, 0.0f, 0.0f); + glRotatef(g_view_roty, 0.0f, 1.0f, 0.0f); + + glPushMatrix(); + glTranslatef(-3.0f, -2.0f, 0.0f); + glRotatef(g_angle, 0.0f, 0.0f, 1.0f); + glCallList(g_gear1); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(3.1f, -2.0f, 0.0f); + glRotatef(-2.0f * g_angle - 9.0f, 0.0f, 0.0f, 1.0f); + glCallList(g_gear2); + glPopMatrix(); + + glPushMatrix(); + glTranslatef(-3.1f, 4.2f, 0.0f); + glRotatef(-2.0f * g_angle - 25.0f, 0.0f, 0.0f, 1.0f); + glCallList(g_gear3); + glPopMatrix(); + + glPopMatrix(); +} + +/**************************************************************************** + * Name: tinygl_fb_open + ****************************************************************************/ + +static int tinygl_fb_open(FAR const char *path, FAR struct tinygl_fb_s *fb) +{ + int ret; + + fb->fd = open(path, O_RDWR); + if (fb->fd < 0) + { + ret = -errno; + fprintf(stderr, "ERROR: open(%s) failed: %d\n", path, ret); + return ret; + } + + if (ioctl(fb->fd, FBIOGET_VIDEOINFO, + (unsigned long)((uintptr_t)&fb->vinfo)) < 0 || + ioctl(fb->fd, FBIOGET_PLANEINFO, + (unsigned long)((uintptr_t)&fb->pinfo)) < 0) + { + ret = -errno; + fprintf(stderr, "ERROR: FBIOGET_VIDEOINFO/PLANEINFO failed: %d\n", + ret); + goto errout; + } + + if (fb->vinfo.fmt != TINYGL_FB_FMT) + { + fprintf(stderr, "ERROR: framebuffer format %d, TinyGL needs %d\n", + fb->vinfo.fmt, TINYGL_FB_FMT); + ret = -EINVAL; + goto errout; + } + + fb->fbmem = mmap(NULL, fb->pinfo.fblen, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FILE, fb->fd, 0); + if (fb->fbmem == MAP_FAILED) + { + ret = -errno; + fprintf(stderr, "ERROR: mmap() failed: %d\n", ret); + goto errout; + } + + return OK; + +errout: + close(fb->fd); + return ret; +} + +/**************************************************************************** + * Name: tinygl_fb_update + ****************************************************************************/ + +static void tinygl_fb_update(FAR struct tinygl_fb_s *fb, FAR ZBuffer *zb) +{ + ZB_copyFrameBuffer(zb, fb->fbmem, fb->pinfo.stride); + +#ifdef CONFIG_FB_UPDATE + struct fb_area_s area; + + area.x = 0; + area.y = 0; + area.w = zb->xsize; + area.h = zb->ysize; + ioctl(fb->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)&area)); +#endif +} + +/**************************************************************************** + * Name: now_ms + ****************************************************************************/ + +static uint32_t now_ms(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + * + * Description: + * tinygl [frames] [fbdev] + * + * Render the TinyGL gears demo on a framebuffer. "frames" is the number + * of frames to draw (0, the default, runs forever) and "fbdev" the + * framebuffer device (CONFIG_EXAMPLES_TINYGL_DEFAULTFB by default). + * + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + FAR const char *fbdev = CONFIG_EXAMPLES_TINYGL_DEFAULTFB; + struct tinygl_fb_s fb; + FAR ZBuffer *zb; + uint32_t start; + uint32_t now; + int frames = 0; + int count = 0; + int total = 0; + int ret; + + if (argc > 1) + { + frames = atoi(argv[1]); + } + + if (argc > 2) + { + fbdev = argv[2]; + } + + ret = tinygl_fb_open(fbdev, &fb); + if (ret < 0) + { + return EXIT_FAILURE; + } + + printf("tinygl: %s %dx%d, %d bpp, stride %" PRIu32 "\n", fbdev, + fb.vinfo.xres, fb.vinfo.yres, fb.pinfo.bpp, fb.pinfo.stride); + + /* Let TinyGL render into its own buffer and copy each finished frame to + * the framebuffer, so that a half drawn frame is never visible. + */ + + zb = ZB_open(fb.vinfo.xres, fb.vinfo.yres, TINYGL_ZB_MODE, NULL); + if (zb == NULL) + { + fprintf(stderr, "ERROR: ZB_open() failed\n"); + ret = EXIT_FAILURE; + goto errout_with_fb; + } + + glInit(zb); + gears_init(zb->xsize, zb->ysize); + + start = now_ms(); + while (frames == 0 || total < frames) + { + gears_draw(); + tinygl_fb_update(&fb, zb); + + count++; + total++; + now = now_ms(); + if (now - start >= 5000) + { + printf("tinygl: %d frames in %" PRIu32 " ms = %d.%d FPS\n", + count, now - start, count * 1000 / (int)(now - start), + (count * 10000 / (int)(now - start)) % 10); + count = 0; + start = now; + } + } + + printf("tinygl: rendered %d frames\n", total); + + glDeleteList(g_gear1); + glDeleteList(g_gear2); + glDeleteList(g_gear3); + glClose(); + ZB_close(zb); + ret = EXIT_SUCCESS; + +errout_with_fb: + munmap(fb.fbmem, fb.pinfo.fblen); + close(fb.fd); + return ret; +}