lvgl / lvgl

Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
https://lvgl.io
MIT License
16.13k stars 3.16k forks source link

3D render options? #16

Closed 8bitbunny closed 4 years ago

8bitbunny commented 7 years ago

Is there any chance of 3D functions to the engine? Like lights, polygons, meshes, vertexes. (There are some repos on GitHub for MCU's that have some of these features)

kisvegabor commented 7 years ago

Thank you for the idea!

8bitbunny commented 6 years ago

Sorry for my late comment,

it would be usefull for minigames, but also ui elements, like pebble did with their smartwatches

A small gif https://developer.pebble.com/assets/images/tutorials/advanced/action-completed.gif

Will look up some repos up right now

8bitbunny commented 6 years ago

Here's one: https://github.com/Nand-e/Tiny3D-engine-STM32

kisvegabor commented 6 years ago

Thank you. It seems resource friendly. But unfortunately it is written in C++. :(

it would be usefull for minigames

Yes, it would be eye-catching to see a 3D demo game. But I'm not sure it worth the effort. In addition LittlevGL is GUI library, it rather looks a brand new project.

A small gif https://developer.pebble.com/assets/images/tutorials/advanced/action-completed.gif

I think it is a gif (or more images played) and not a 3D rendered model.

So in my opinion 3D like elements in an embedded GUI library could appear as an animation of pre rendered images. What do you think?

8bitbunny commented 6 years ago

To be precise: it is not a sees of images on the Pebble hardware, those animations are rendered real time, with drawing paths, to let em look like 3D and animated like a gif.

So, yeah, since 3D won't be a standard feature, maybe make a extension to lvgl? Like a separate repo which is optional to have?

kisvegabor commented 6 years ago

The seperated repo sounds better! A compatible 3D engine would be nice to play and to try/learn 3D.

Probably in v6 it could be in the library. (For v5 already has a lot of new things)

Do you have any experience in 3D field and would you like to contribute in this feature?

8bitbunny commented 6 years ago

I sadly don't have experience with 3D rendering at all, so I can't help much at all

tevfik commented 6 years ago

I have some codes with my custom Gui. It needs polygon drawing functions. 3d calculations are made with quaternion and/or Euler arithmetic (rotation matrices). It requires drawing object pixel size buffer. (may be it's better to use line buffers or sprites but I couldn't handle this yet.). You need to import 3d model as vertices and colors. But could be modified for 2d graphics. Library doesn't have z-buffering, lighting, shading and texturing feature, only rotation, scaling and flat shading is available now. I don't have much time but anyone want to contribute I could help.

I used this routines with Funkos' modified fooeyGUI framework. So It could run even on a sensor node (like ti's sensortag with a sharp memory display). that gui running as a thread with contiki operating system.

tevfik commented 6 years ago

By the way library complately optimized with fixed point math library don't use any floating point numbers so it's fast enough If I have time I would upload an video soon...

kisvegabor commented 6 years ago

@tevfik It sounds very well. However LittlevGL is not a 3D library an optional 3D extension can be useful in some cases. Maybe you already know LittelvGL has a buffered mode where we have a pixel buffer. You said there is no z-buffering now. Without it can you render models properly with overlapping triangles?.

I'm really looking forward to see the video :)

By the way we are talking about polygon drawing in this topic: #146

8bitbunny commented 6 years ago

gui just a small thing i saw in the airplane last night in their entertainment systems. the plane and globe were both a 3D model, and you could do simple navigation around the plane and globe. this might be a optional, but useful thing.

kisvegabor commented 6 years ago

Wow, it look great! Thank you! Once we will have 3D render extension creating a demo like this would be awesome.

kisvegabor commented 6 years ago

I'm organizing the issues and however, it's an interesting one, I close it because adding a 3D engine is a very big work and here is not plans to add it in the near future.

Despite of it if you or somebody make some progress or experiment in this field feel free to comment here and reopen the issue.

barbiani commented 4 years ago

Hello everybody,

I have made some progress in this topic today. Got TinyGL running GLgears smoothly on the ESP32 (M5stack).

video

image

kisvegabor commented 4 years ago

Wow, that's amazing! Congratulations!

Would you mind sharing your code? We have lv_lib_... repos for 3rd parts libs. TinyGL could be added similarly if you are open to it.

barbiani commented 4 years ago

I am not finding the libraries repository. Also, i am not able to reopen this issue to discuss possible optimizations to this implementation.

embeddedt commented 4 years ago

I am not finding the libraries repository.

We would create a new external library repository. Here is the current list.

barbiani commented 4 years ago

Wow, that's amazing! Congratulations!

Would you mind sharing your code? We have lv_lib_... repos for 3rd parts libs. TinyGL could be added similarly if you are open to it.

The solution is quite simple. Let TinyGL render to a canvas buffer... but I am having trouble getting the colors right with 16 and 32 bit colors.

First attempt had 2 buffers for GL and the canvas copying the frame after it was rendered.

The second rendered directly to the canvas buffer and invalidating it after.

While lvgl is 32: ARGB8888, TinyGL is RGBA8888. This troubles SDL... TinyGL has a RGB_TO_PIXEL(r, g, b) macro to handle the pixel format, but the alpha byte is not used. I set it to FF manually.

TinyGL rendering to 16: RGB565 fits the embedded systems, but the canvas does not seem to suport it yet.

kisvegabor commented 4 years ago

The solution is quite simple. Let TinyGL render to a canvas buffer... but I am having trouble getting the colors right with 16 and 32 bit colors.

I'm not familiar with TinyGL so don't how difficult to make it work.

TinyGL rendering to 16: RGB565 fits the embedded systems, but the canvas does not seem to suport it yet.

The canvas should support RGB565 mode if LV_COLOR_DEPTH is 16 in lv_conf.h.

Could you add a link to your project? I could take look to see what can be the problem. Besides, I'm very curious and would like to try it :slightly_smiling_face:

barbiani commented 4 years ago

The solution is quite simple. Let TinyGL render to a canvas buffer... but I am having trouble getting the colors right with 16 and 32 bit colors.

I'm not familiar with TinyGL so don't how difficult to make it work.

TinyGL rendering to 16: RGB565 fits the embedded systems, but the canvas does not seem to suport it yet.

The canvas should support RGB565 mode if LV_COLOR_DEPTH is 16 in lv_conf.h.

Could you add a link to your project? I could take look to see what can be the problem. Besides, I'm very curious and would like to try it 🙂

Here

TinyGL source code is written to be fast and with some hard to follow macros.

It can be used as it is, or maybe we can replace these pixel and line (zline.c) functions to use the anti aliased canvas functions.

embeddedt commented 4 years ago

Quickly copied over the necessary files and tested it on STM32. It appears to be running quite smoothly although I don't have time to check the frame rate tonight. :+1:

kisvegabor commented 4 years ago

Thank you! I've tried it in the simulator and it works well here too.

@barbiani Do you know if there is a way to load model and its textures to TinyGL and set camera position?

barbiani commented 4 years ago

Thank you! I've tried it in the simulator and it works well here too.

Do expect wrong colors in the rendering!

@barbiani Do you know if there is a way to load model and its textures to TinyGL and set camera position?

I will start here https://en.m.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Load_OBJ http://kixor.net/dev/objloader/ http://tfc.duke.free.fr/coding/src/obj.c

TinyGL can render at least triangle lists, light sources, textures and camera positioning. Says its readme.

embeddedt commented 4 years ago

I was able to make the last loader @barbiani sent work, with some modifications.

You need this OBJ file, this MTL file, and the code I've attached below. You can then replace the call to gears_update with showmodel_update and change gears_init to showmodel_init (CANVAS_WIDTH, CANVAS_HEIGHT, cbuf, "test.obj").

At this point the viewport gets filled with color, so I assume I'm looking at a 3D model. However, I must admit that I have no idea how to move the camera with TinyGL, so I don't know whether this is actually being drawn properly or not.


/*
 * showmodel.c -- obj model loader (modified for TinyGL+LittlevGL)
 *
 * Copyright (c) 2005-2007 David HENRY
 * Modifications made by embeddedt
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include "tinygl/gl.h"
#include "tinygl/zbuffer.h"
#include "tinygl/gears.h"

ZBuffer* frameBuffer;

/* Vectors */
typedef float vec3_t[3];
typedef float vec4_t[4];

/* Vertex */
struct obj_vertex_t
{
  vec4_t xyzw;
};

/* Texture coordinates */
struct obj_texCoord_t
{
  vec3_t uvw;
};

/* Normal vector */
struct obj_normal_t
{
  vec3_t ijk;
};

/* Polygon */
struct obj_face_t
{
  GLenum type;        /* primitive type */
  int num_elems;      /* number of vertices */

  int *vert_indices;  /* vertex indices */
  int *uvw_indices;   /* texture coordinate indices */
  int *norm_indices;  /* normal vector indices */
};

/* OBJ model structure */
struct obj_model_t
{
  int num_verts;                     /* number of vertices */
  int num_texCoords;                 /* number of texture coords. */
  int num_normals;                   /* number of normal vectors */
  int num_faces;                     /* number of polygons */

  int has_texCoords;                 /* has texture coordinates? */
  int has_normals;                   /* has normal vectors? */

  struct obj_vertex_t *vertices;     /* vertex list */
  struct obj_texCoord_t *texCoords;  /* tex. coord. list */
  struct obj_normal_t *normals;      /* normal vector list */
  struct obj_face_t *faces;          /* model's polygons */
};

/*** An OBJ model ***/
struct obj_model_t objfile;

/**
 * Free resources allocated for the model.
 */
void
FreeModel (struct obj_model_t *mdl)
{
  int i;

  if (mdl)
    {
      if (mdl->vertices)
    {
      free (mdl->vertices);
      mdl->vertices = NULL;
    }

      if (mdl->texCoords)
    {
      free (mdl->texCoords);
      mdl->texCoords = NULL;
    }

      if (mdl->normals)
    {
      free (mdl->normals);
      mdl->normals = NULL;
    }

      if (mdl->faces)
    {
      for (i = 0; i < mdl->num_faces; ++i)
        {
          if (mdl->faces[i].vert_indices)
        free (mdl->faces[i].vert_indices);

          if (mdl->faces[i].uvw_indices)
        free (mdl->faces[i].uvw_indices);

          if (mdl->faces[i].norm_indices)
        free (mdl->faces[i].norm_indices);
        }

      free (mdl->faces);
      mdl->faces = NULL;
    }
    }
}

/**
 * Allocate resources for the model after first pass.
 */
int
MallocModel (struct obj_model_t *mdl)
{
  if (mdl->num_verts)
    {
      mdl->vertices = (struct obj_vertex_t *)
    malloc (sizeof (struct obj_vertex_t) * mdl->num_verts);
      if (!mdl->vertices)
    return 0;
    }

  if (mdl->num_texCoords)
    {
      mdl->texCoords = (struct obj_texCoord_t *)
    malloc (sizeof (struct obj_texCoord_t) * mdl->num_texCoords);
      if (!mdl->texCoords)
    return 0;
    }

  if (mdl->num_normals)
    {
      mdl->normals = (struct obj_normal_t *)
    malloc (sizeof (struct obj_normal_t) * mdl->num_normals);
      if (!mdl->normals)
    return 0;
    }

  if (mdl->num_faces)
    {
      mdl->faces = (struct obj_face_t *)
    calloc (mdl->num_faces, sizeof (struct obj_face_t));
      if (!mdl->faces)
    return 0;
    }

  return 1;
}

/**
 * Load an OBJ model from file -- first pass.
 * Get the number of triangles/vertices/texture coords for
 * allocating buffers.
 */
int
FirstPass (FILE *fp, struct obj_model_t *mdl)
{
  int v, t, n;
  char buf[256];

  while (!feof (fp))
    {
      /* Read whole line */
      fgets (buf, sizeof (buf), fp);

      switch (buf[0])
    {
    case 'v':
      {
        if (buf[1] == ' ')
          {
        /* Vertex */
        mdl->num_verts++;
          }
        else if (buf[1] == 't')
          {
        /* Texture coords. */
        mdl->num_texCoords++;
          }
        else if (buf[1] == 'n')
          {
        /* Normal vector */
        mdl->num_normals++;
          }
        else
          {
        printf ("Warning: unknown token \"%s\"! (ignoring)\n", buf);
          }

        break;
      }

    case 'f':
      {
        /* Face */
        if (sscanf (buf + 2, "%d/%d/%d", &v, &n, &t) == 3)
          {
        mdl->num_faces++;
        mdl->has_texCoords = 1;
        mdl->has_normals = 1;
          }
        else if (sscanf (buf + 2, "%d//%d", &v, &n) == 2)
          {
        mdl->num_faces++;
        mdl->has_texCoords = 0;
        mdl->has_normals = 1;
          }
        else if (sscanf (buf + 2, "%d/%d", &v, &t) == 2)
          {
        mdl->num_faces++;
        mdl->has_texCoords = 1;
        mdl->has_normals = 0;
          }
        else if (sscanf (buf + 2, "%d", &v) == 1)
          {
        mdl->num_faces++;
        mdl->has_texCoords = 0;
        mdl->has_normals = 0;
          }
        else
          {
        /* Should never be there or the model is very crappy */
        fprintf(stderr,"Error: found face with no vertex!\n");
          }

        break;
      }

    case 'g':
      {
        /* Group */
        /*  fscanf (fp, "%s", buf); */
        break;
      }

    default:
      break;
    }
    }

  /* Check if informations are valid */
  if ((mdl->has_texCoords && !mdl->num_texCoords) ||
      (mdl->has_normals && !mdl->num_normals))
    {
      fprintf(stderr,"error: contradiction between collected info!\n");
      return 0;
    }

  if (!mdl->num_verts)
    {
      fprintf(stderr,"error: no vertex found!\n");
      return 0;
    }

  printf ("first pass results: found\n");
  printf ("   * %i vertices\n", mdl->num_verts);
  printf ("   * %i texture coords.\n", mdl->num_texCoords);
  printf ("   * %i normal vectors\n", mdl->num_normals);
  printf ("   * %i faces\n", mdl->num_faces);
  printf ("   * has texture coords.: %s\n", mdl->has_texCoords ? "yes" : "no");
  printf ("   * has normals: %s\n", mdl->has_normals ? "yes" : "no");

  return 1;
}

/**
 * Load an OBJ model from file -- first pass.
 * This time, read model data and feed buffers.
 */
int
SecondPass (FILE *fp, struct obj_model_t *mdl)
{
  struct obj_vertex_t *pvert = mdl->vertices;
  struct obj_texCoord_t *puvw = mdl->texCoords;
  struct obj_normal_t *pnorm = mdl->normals;
  struct obj_face_t *pface = mdl->faces;
  char buf[128], *pbuf;
  int i;

  while (!feof (fp))
    {
      /* Read whole line */
      fgets (buf, sizeof (buf), fp);

      switch (buf[0])
    {
    case 'v':
      {
        if (buf[1] == ' ')
          {
        /* Vertex */
        if (sscanf (buf + 2, "%f %f %f %f",
                &pvert->xyzw[0], &pvert->xyzw[1],
                &pvert->xyzw[2], &pvert->xyzw[3]) != 4)
          {
            if (sscanf (buf + 2, "%f %f %f", &pvert->xyzw[0],
                &pvert->xyzw[1], &pvert->xyzw[2] ) != 3)
              {
            fprintf(stderr,"Error reading vertex data!\n");
            return 0;
              }
            else
              {
            pvert->xyzw[3] = 1.0;
              }
          }

        pvert++;
          }
        else if (buf[1] == 't')
          {
        /* Texture coords. */
        if (sscanf (buf + 2, "%f %f %f", &puvw->uvw[0],
                &puvw->uvw[1], &puvw->uvw[2]) != 3)
          {
            if (sscanf (buf + 2, "%f %f", &puvw->uvw[0],
                &puvw->uvw[1]) != 2)
              {
            if (sscanf (buf + 2, "%f", &puvw->uvw[0]) != 1)
              {
                fprintf(stderr,"Error reading texture coordinates!\n");
                return 0;
              }
            else
              {
                puvw->uvw[1] = 0.0;
                puvw->uvw[2] = 0.0;
              }
              }
            else
              {
            puvw->uvw[2] = 0.0;
              }
          }

        puvw++;
          }
        else if (buf[1] == 'n')
          {
        /* Normal vector */
        if (sscanf (buf + 2, "%f %f %f", &pnorm->ijk[0],
                &pnorm->ijk[1], &pnorm->ijk[2]) != 3)
          {
            fprintf(stderr,"Error reading normal vectors!\n");
            return 0;
          }

        pnorm++;
          }

        break;
      }

    case 'f':
      {
        pbuf = buf;
        pface->num_elems = 0;

        /* Count number of vertices for this face */
        while (*pbuf)
          {
        if (*pbuf == ' ')
          pface->num_elems++;

        pbuf++;
          }

        /* Select primitive type */
        if (pface->num_elems < 3)
          {
        fprintf(stderr,"Error: a face must have at least 3 vertices!\n");
        return 0;
          }
        else if (pface->num_elems == 3)
          {
        pface->type = GL_TRIANGLES;
          }
        else if (pface->num_elems == 4)
          {
        pface->type = GL_QUADS;
          }
        else
          {
        pface->type = GL_POLYGON;
          }

        /* Memory allocation for vertices */
        pface->vert_indices = (int *)malloc (sizeof (int) * pface->num_elems);

        if (mdl->has_texCoords)
          pface->uvw_indices = (int *)malloc (sizeof (int) * pface->num_elems);

        if (mdl->has_normals)
          pface->norm_indices = (int *)malloc (sizeof (int) * pface->num_elems);

        /* Read face data */
        pbuf = buf;
        i = 0;

        for (i = 0; i < pface->num_elems; ++i)
          {
        pbuf = strchr (pbuf, ' ');
        pbuf++; /* Skip space */

        /* Try reading vertices */
        if (sscanf (pbuf, "%d/%d/%d",
                &pface->vert_indices[i],
                &pface->uvw_indices[i],
                &pface->norm_indices[i]) != 3)
          {
            if (sscanf (pbuf, "%d//%d", &pface->vert_indices[i],
                &pface->norm_indices[i]) != 2)
              {
            if (sscanf (pbuf, "%d/%d", &pface->vert_indices[i],
                    &pface->uvw_indices[i]) != 2)
              {
                sscanf (pbuf, "%d", &pface->vert_indices[i]);
              }
              }
          }

        /* Indices must start at 0 */
        pface->vert_indices[i]--;

        if (mdl->has_texCoords)
          pface->uvw_indices[i]--;

        if (mdl->has_normals)
          pface->norm_indices[i]--;
          }

        pface++;
        break;
      }
    }
    }

  printf ("second pass results: read\n");
  printf ("   * %li vertices\n", pvert - mdl->vertices);
  printf ("   * %li texture coords.\n", puvw - mdl->texCoords);
  printf ("   * %li normal vectors\n", pnorm - mdl->normals);
  printf ("   * %li faces\n", pface - mdl->faces);

  return 1;
}

/**
 * Load an OBJ model from file, in two passes.
 */
int
ReadOBJModel (const char *filename, struct obj_model_t *mdl)
{
  FILE *fp;

  fp = fopen (filename, "r");
  if (!fp)
    {
      fprintf(stderr,"Error: couldn't open \"%s\"!\n", filename);
      return 0;
    }

  /* reset model data */
  memset (mdl, 0, sizeof (struct obj_model_t));

  /* first pass: read model info */
  if (!FirstPass (fp, mdl))
    {
      fclose (fp);
      return 0;
    }

  rewind (fp);

  /* memory allocation */
  if (!MallocModel (mdl))
    {
      fclose (fp);
      FreeModel (mdl);
      return 0;
    }

  /* second pass: read model data */
  if (!SecondPass (fp, mdl))
    {
      fclose (fp);
      FreeModel (mdl);
      return 0;
    }

  fclose (fp);
  return 1;
}

/**
 * Draw the OBJ model.
 */
void
RenderOBJModel (struct obj_model_t *mdl)
{
  int i, j;

  for (i = 0; i < mdl->num_faces; ++i)
    {
      glBegin (mdl->faces[i].type);
    for (j = 0; j < mdl->faces[i].num_elems; ++j)
      {
        if (mdl->has_texCoords) {
          GLfloat *v = mdl->texCoords[mdl->faces[i].uvw_indices[j]].uvw;
          glTexCoord4f (v[0], v[1], v[2], 1);
        }

        if (mdl->has_normals)
          glNormal3fv (mdl->normals[mdl->faces[i].norm_indices[j]].ijk);

        GLfloat *v = mdl->vertices [mdl->faces[i].vert_indices[j]].xyzw;

        glVertex4f (v[0], v[1], v[2], v[3]);
      }
    glEnd();
    }
}

void
init (const char *filename)
{
  GLfloat lightpos[] = { 5.0f, 10.0f, 0.0f, 1.0f };

  /* Initialize OpenGL context */
  glClearColor (0.5f, 0.5f, 0.5f, 1.0f);
  glShadeModel (GL_SMOOTH);

  glEnable (GL_DEPTH_TEST);
  glEnable (GL_LIGHTING);
  glEnable (GL_LIGHT0);

  glLightfv (GL_LIGHT0, GL_POSITION, lightpos);

  /* Load OBJ model file */
  if (!ReadOBJModel (filename, &objfile))
    exit (EXIT_FAILURE);
}

void
cleanup ()
{
  FreeModel (&objfile);
}

void
reshape (int w, int h)
{
  if (h == 0)
    h = 1;

  glViewport (0, 0, (GLsizei)w, (GLsizei)h);

  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();
  gluPerspective (45.0, w/(GLdouble)h, 0.1, 1000.0);

  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  //glutPostRedisplay ();
}

void
showmodel_update (void)
{
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  glLoadIdentity ();

  glTranslatef (0.0f, 0.0f, -15.0f);

  /* Draw the model */
  RenderOBJModel (&objfile);

  //glutSwapBuffers ();
}

void
showmodel_init (int w, int h, void *cbuf, char *filename)
{
    frameBuffer = ZB_open(w, h, ZB_MODE_5R6G5B, 0, NULL, NULL, cbuf);
    // initialize GL:
    glInit(frameBuffer);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glViewport(0, 0, w, h);
    init(filename);
}
barbiani commented 4 years ago

This is also my first opengl attempt.

Looks like setting the camera is in gluPerspective (45.0, w/(GLdouble)h, 0.1, 1000.0). There is also a camera setting in the model file.

TinyGL is an opengl subset, so the latter documentation can be used.

https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml

Your post has: / Initialize OpenGL context / glClearColor (0.5f, 0.5f, 0.5f, 1.0f);

Tried myselft to get a grey background but this rgb at .5 turned out yellow. Something was not right. This is probably the color you are seeing.

kisvegabor commented 4 years ago

I've found the root of the color issue. There was a bug in RGB_TO_PIXEL macro (zbuffer.h). Here is the corrected version:

/* 16 bit mode */
#define RGB_TO_PIXEL(r,g,b) \
  (((r) & 0xF800) | (((g >> 5)) & 0x07E0) | ((b) >> 11))

@embeddedt That's great that you find this example! I couldn't figure out which version of OpenGL TinyGL is compatible with.
I've tried your code but it crashed for me. The problem is that it finds 7 normals, but still says "has normal: no" therefore the array of normals is not allocated and NULL is referenced.

first pass results: found
   * 17 vertices
   * 3 texture coords.
   * 7 normal vectors
   * 12 faces
   * has texture coords.: no
   * has normals: no

I've created the lv_lib_tinygl repo for easier code sharing. @barbiani, I've granted write access to you. @embeddedt, could you upload your code there?

barbiani commented 4 years ago

I've found the root of the color issue. There was a bug in 'RGB_TO_PIXEL' macro (zbuffer.h). Here is the corrected version:

I tried editing initScene() to make red, green and blue colors pure. The array format seems to be RGBA. Do that and you will see the color errors I was talking about.

void initScene() { static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; static GLfloat red[4] = { 1.0, 0.0, 0.0, 1.0 }; static GLfloat green[4] = { 0.0, 1.0, 0.0, 1.0 }; static GLfloat blue[4] = { 0.0, 0.0, 1.0, 1.0 }; ... }

Correct look: image

kisvegabor commented 4 years ago

I see the issue. However, if I set glClearColor(0.0, 0.0, 1.0, 1.0); or glClearColor(0.0, 1.0, 0.0, 1.0); in gear_init I got the correct colors in the bacground. Probably It's an other bug in the renderer.

I'll take a look.

kisvegabor commented 4 years ago

I've found it. It was really a bug deep in the renderer. Actually it was a critical thing: GLParam is an union with many types. An op_list (an array of GLParam) is built from it where opcodes and values are stored. However, at some point, the array was converted to float *. I suppose not float is the largest member of the union so indexing the array this way made the parameters corrupted. It was easy to fix, but I wonder how many of similar issues could be there.

Now it works for me with 16 bit color depth.

I uploaded my current version to lv_lib_tinygl.

barbiani commented 4 years ago

You are fast! I did not know it was a bug there because I managed to get the right gear colors, but not the grey background by changing the RGB_TO_PIXEL macro and the gear color definitions.

The original tinygl package has more files than I had in my project.

https://github.com/ska80/tinygl

One of them is LIMITATIONS:

` Here are listed the functions that TinyGL understands with the known limitations. The non mentionned functions are not implemented and must not be used.

**** glEnable / glDisable

GL_CULL_FACE, GL_LIGHTING, GL_COLOR_MATERIAL, GL_TEXTURE_2D, GL_NORMALIZE, GL_LIGHTx, GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_POINT, GL_POLYGON_OFFSET_LINE

**** glShadeModel

OK.

**** glCullFace

OK.

**** glPolygonMode

OK.

**** glBegin

No tests are performed to prevent some functions of being executed between glBegin/glEnd.

**** glEnd

OK.

**** glVertex

Some prototypes are not implemented.

**** glColor

Some prototypes are not implemented.

**** glNormal

Some prototypes are not implemented.

**** glTexCoord

**** glEdgeFlag

OK. The edge handling has to be tested, although it is not much useful in TinyGL.

**** glMatrixMode / glLoadMatrixf / glLoadIdentity / glMultMatrixf / glPushMatrix / glPopMatrix / glRotatef / glTranslatef / glScalef / glFrustum

**** glViewport

GlViewport calls a function pointers to tell glx (or another display system) to resize the Z buffer and the ximage. Made optional in version 0.2.

**** glGenLists / glIsList / glNewList / glEndList / glCallList

OK.

**** glClear / glClearColor / glClearDepth

The whole zbuffer and the colors are cleared in any case. The clear color can be redefined, by not the initial z value.

**** glRenderMode

Only the modes GL_RENDER and GL_SELECT are implemented.

**** glSelectBuffer / glInitNames / glPushName / glPopName / glLoadName

OK.

**** glGenTextures / glDeleteTextures / glBindTexture

OK. These functions should be used to get the maximum performance with TinyGL.

**** glTexImage2D

The function accepts only RGB UNSIGNED_BYTES bitmaps. They are internally resized to 256x256 so you'd better use that size. No mipmapping is implemented although it will come if asked. No borders are implemented.

**** glTexEnvi

The only supported mode is GL_DECAL, although others are planned if asked.

**** glTexParameteri

The other prototypes are not implemented. Only the follwing mode are implemented:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

**** glPixelStorei

The pixels are alware byte aligned.

**** glMaterialfv / glMaterialf / glColorMaterial

OK.

**** glLightfv / glLightf / glLightModeli / glLightModelfv

OK. The OpenGL lightening is implemented but not optimized.

**** glFlush

Ignored.

**** glHint

Ignored.

**** glGetIntegerv

**** glGetIntegerv

**** glPolygonOffset

**** glEnableClientState, glDisableClientState,

**** glVertexPointer, glNormalPointer, glColorPointer, glTexureCoordPointer


TinyGL GLX emulation:

**** glXQueryExtension

Returns always True

**** glXChooseVisual

Only 8 bit Pseudocolor or 16 bit Truecolor Visual are accepted. The attribute list is ignored.

**** glXCreateContext

The sharing is not implemented although the code could handle it.

**** glXDestroyContext

OK.

**** glXMakeCurrent

Not all the syntax is supported yet, in particular with the 'NULL' or 'None' parameters.

**** glXSwapBuffers

OK.

**** glXWaitGL / glXWaitX

Ignored.

See README.BEOS for BeOS limitations. `

barbiani commented 4 years ago

For the 3d model rendering I believe that we should parse the obj file, removing comments, including the mtl and changing any texture bitmap to the supported format and writing to a const byte array.

kisvegabor commented 4 years ago

Let's wait until @embeddedt will have time to upload his code to lv_lib_tinygl.

barbiani commented 4 years ago

Further research found this. Might give good results with lvgl.

https://gitlab.com/drummyfish/small3dlib

Discussion about it: https://forum.freegamedev.net/viewtopic.php?f=22&t=11747

Single header library. All it needs is a setpixel function.. compatible with the canvas object.

embeddedt commented 4 years ago

Looks nice! It definitely appears to have been optimized for memory-constrained environments.

We could probably even get it to render directly through LittlevGL's rendering system instead of needing a separate buffer+canvas.

kisvegabor commented 4 years ago

Really an interesting option, although I'm concerned about the rendering quality if small3dlib due to integer arithmetics.

IMO if the user needs 3D he can afford the use of float for better quality. What do you think?

embeddedt commented 4 years ago

I played with small3dlib a bit today and it would definitely be a good fit for someone trying to recreate a retro game on a microcontroller. I'm not sure how useful it would be for rendering "modern" 3D models, but for simple games it might suffice.

Performance may be an issue - I ran it rendering directly to the framebuffer (i.e. without LittlevGL) and my STM32F746 was only able to get 1-2 FPS at 480x272 resolution. I did not have the CPU cache on, however. That probably would have given much better results.

Going back to TinyGL, my code appears to be in objtest.c. It does look like some modifications have been made to it though. In particular, ReadOBJModel should not be commented out here.

embeddedt commented 4 years ago

If the user needs 3D he can afford the use of float for better quality. What do you think?

I agree. The author of small3dlib actually writes here that calculations with HW floating-point operations would be faster than fixed-point integer operations in some cases.

embeddedt commented 4 years ago

I'm also wondering whether full-on 3D rendering capabilities are necessary. Consider the 3D transformation features available in CSS nowadays. If we had the ability to draw things on the canvas and rotate them in 3D space, the plane information interface linked above could be recreated without the need to render any 3D models.

plane demo image

kisvegabor commented 4 years ago

Performance may be an issue - I ran it rendering directly to the framebuffer (i.e. without LittlevGL) and my STM32F746 was only able to get 1-2 FPS at 480x272 resolution. I did not have the CPU cache on, however. That probably would have given much better results.

Do I remember well that you have seen a good FPS with TinyGL?

Consider the 3D transformation features available in CSS nowadays.

I'm learning texture mapping and other basics of 3D rendering to see how to realize a "simple" perspective effect on a canvas. Something like rotate-y in CSS.

Instead of a 3D globe model, a series of 2D images could be used, or a flat 2D map could be used.

What about the plane itself? It also could be a 3D model which is rotated. I've seen car dashboards where the model of the car was rotated, moved, zoomed and the doors opened and closed.

Perhaps the compass underneath the plane could rotate instead of the plane itself. Then the plane could be a static 2D image.

With rotate and perspective effect it really could be a normal image.


I'll try the updated code again. I'm still busy with dev-7.0 and probably will have time for it only at the end of the week.

embeddedt commented 4 years ago

you have seen a good FPS with TinyGL?

Yes. It was much smoother.

kisvegabor commented 4 years ago

Then it seems like a clear decision here. If TinyGL seems faster and has better quality then we should go with it.

kisvegabor commented 4 years ago

@embeddedt I've added a lv_tinygl_test.c which uses the mentioned model but it still crashes for me due to the same inconsistency:

   * 17 vertices
   * 3 texture coords.
   * 7 normal vectors
   * 12 faces
   * has texture coords.: no   #How? There are 3 as stated above
   * has normals: no           #How? There are 7 as stated above

Could you take a look is it already worked for you? Only lv_tinygl_test() needs to be called.


Maybe I missed it but where the MTL file is loaded?

embeddedt commented 4 years ago

Could you take a look is it already worked for you?

Sure; I'll take a look.

Maybe I missed it but where the MTL file is loaded?

It's referenced inside the OBJ file.

embeddedt commented 4 years ago

@kisvegabor I think I've fixed that issue now, but I am still unable to get anything to appear on the screen besides the gray background.

kisvegabor commented 4 years ago

Thank you for the fix. It works better but I also see only the gray background. I've tried to understand what's going on inside TinyGL but find nothing so far. It's new territory for me so there are a lot of unclear parts.

stale[bot] commented 4 years ago

This issue or pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

kisvegabor commented 4 years ago

I didn't have time to figure out why we can't see any output and now I'm working with full capacity on v7. :disappointed:

I still belive the 3D extension would be very useful, but I have no time deal with it now.

stale[bot] commented 4 years ago

This issue or pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

kisvegabor commented 4 years ago

I close this issue in lack of activity :frowning_face: Feel free to comment here if you are interested in working on it.

Satnet commented 3 months ago

I close this issue in lack of activity ☹️ Feel free to comment here if you are interested in working on it.

I lack the knowledge to push this forward. But there really should be 3D support in LVGL. It would be a great addition!