C-Chads / tinygl

The penultimate portable graphics library
Other
453 stars 53 forks source link

Unable to load GL_RGBA textures #18

Closed bztsrc closed 1 year ago

bztsrc commented 2 years ago

Hi!

Pretty awesome additions you have made to TinyGL! I really like it! My only issue is, I procedurally generate textures with uint32_t pixels and I cannot load that. So I've added this little patch to support GL_RGBA textures (it does not do anything with the alpha channel, it just allows to load pixel buffers with uint32_t pixels).

Basically it adds a components parameter to the image_util.c functions and uses that instead of the hardcoded 3:

diff --git a/src/image_util.c b/src/image_util.c
index 53d9d54..8f3fe46 100644
--- a/src/image_util.c
+++ b/src/image_util.c
@@ -4,7 +4,7 @@
  * image conversion
  */

-void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint ysize) {
+void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint ysize, GLint components) {
    GLint i, n;
    GLubyte* p;

@@ -12,7 +12,7 @@ void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint
    n = xsize * ysize;
    for (i = 0; i < n; i++) {
        pixmap[i] = ((p[0] & 0xF8) << 8) | ((p[1] & 0xFC) << 3) | ((p[2] & 0xF8) >> 3);
-       p += 3;
+       p += components;
    }
 }

@@ -20,15 +20,15 @@ void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint
  This actually converts to ARGB!!!
  This is the format of the entire engine!!!
 */
-void gl_convertRGB_to_8A8R8G8B(GLuint* pixmap, GLubyte* rgb, GLint xsize, GLint ysize) {
+void gl_convertRGB_to_8A8R8G8B(GLuint* pixmap, GLubyte* rgb, GLint xsize, GLint ysize, GLint components) {
    GLint i, n;
    GLubyte* p;

    p = rgb;
    n = xsize * ysize;
    for (i = 0; i < n; i++) {
-       pixmap[i] = (((GLuint)p[0]) << 16) | (((GLuint)p[1]) << 8) | (((GLuint)p[2]));
-       p += 3;
+       pixmap[i] = (components == 4 ? ((GLuint)p[3]) << 24 : 255) | (((GLuint)p[0]) << 16) | (((GLuint)p[1]) << 8) | (((GLuint)p[2]));
+       p += components;
    }
 }

@@ -47,7 +47,7 @@ static GLint GLinterpolate_imutil(GLint v00, GLint v01, GLint v10, GLint xf, GLi
  * TODO: more accurate resampling
  */

-void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src) {
+void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src, GLint components) {
    GLubyte *pix, *pix_src;
    GLfloat x1, y1, x1inc, y1inc;
    GLint xi, yi, j, xf, yf, x, y;
@@ -68,20 +68,22 @@ void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte*
            yf = (GLint)((y1 - floor(y1)) * INTERP_NORM);

            if ((xf + yf) <= INTERP_NORM) {
-               for (j = 0; j < 3; j++) {
-                   pix[j] = GLinterpolate_imutil(pix_src[(yi * xsize_src + xi) * 3 + j], pix_src[(yi * xsize_src + xi + 1) * 3 + j],
-                                                 pix_src[((yi + 1) * xsize_src + xi) * 3 + j], xf, yf);
+               for (j = 0; j < components; j++) {
+                   pix[j] = GLinterpolate_imutil(pix_src[(yi * xsize_src + xi) * components + j],
+                                                 pix_src[(yi * xsize_src + xi + 1) * components + j],
+                                                 pix_src[((yi + 1) * xsize_src + xi) * components + j], xf, yf);
                }
            } else {
                xf = INTERP_NORM - xf;
                yf = INTERP_NORM - yf;
-               for (j = 0; j < 3; j++) {
-                   pix[j] = GLinterpolate_imutil(pix_src[((yi + 1) * xsize_src + xi + 1) * 3 + j], pix_src[((yi + 1) * xsize_src + xi) * 3 + j],
-                                                 pix_src[(yi * xsize_src + xi + 1) * 3 + j], xf, yf);
+               for (j = 0; j < components; j++) {
+                   pix[j] = GLinterpolate_imutil(pix_src[((yi + 1) * xsize_src + xi + 1) * components + j],
+                                                 pix_src[((yi + 1) * xsize_src + xi) * components + j],
+                                                 pix_src[(yi * xsize_src + xi + 1) * components + j], xf, yf);
                }
            }

-           pix += 3;
+           pix += components;
            x1 += x1inc;
        }
        y1 += y1inc;
@@ -93,7 +95,7 @@ void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte*

 /* resizing with no GLinterlating nor nearest pixel */

-void gl_resizeImageNoInterpolate(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src) {
+void gl_resizeImageNoInterpolate(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src, GLint components) {
    GLubyte *pix, *pix_src, *pix1;
    GLint x1, y1, x1inc, y1inc;
    GLint xi, yi, x, y;
@@ -115,8 +117,10 @@ void gl_resizeImageNoInterpolate(GLubyte* dest, GLint xsize_dest, GLint ysize_de
            pix[0] = pix1[0];
            pix[1] = pix1[1];
            pix[2] = pix1[2];
+           if(components == 4)
+               pix[3] = pix1[3];

-           pix += 3;
+           pix += components;
            x1 += x1inc;
        }
        y1 += y1inc;
diff --git a/src/texture.c b/src/texture.c
index c2e5364..f332e8b 100644
--- a/src/texture.c
+++ b/src/texture.c
@@ -263,20 +263,18 @@ void glopTexImage1D(GLParam* p) {
    GLint do_free=0;
    GLContext* c = gl_get_context();
    {
+       if (!(c->current_texture != NULL && target == GL_TEXTURE_1D && level == 0 && type == GL_UNSIGNED_BYTE && border == 0 &&
+            ((format == GL_RGB && components == 3) || (format == GL_RGBA && components == 4))))
 #if TGL_FEATURE_ERROR_CHECK == 1
-       if (!(c->current_texture != NULL && target == GL_TEXTURE_1D && level == 0 && components == 3 && border == 0 && format == GL_RGB &&
-             type == GL_UNSIGNED_BYTE))
 #define ERROR_FLAG GL_INVALID_ENUM
 #include "error_check.h"

 #else
-       if (!(c->current_texture != NULL && target == GL_TEXTURE_1D && level == 0 && components == 3 && border == 0 && format == GL_RGB &&
-             type == GL_UNSIGNED_BYTE))
            gl_fatal_error("glTexImage2D: combination of parameters not handled!!");
 #endif
    }
    if (width != TGL_FEATURE_TEXTURE_DIM || height != TGL_FEATURE_TEXTURE_DIM) {
-       pixels1 = gl_malloc(TGL_FEATURE_TEXTURE_DIM * TGL_FEATURE_TEXTURE_DIM * 3); /* GUARDED*/
+       pixels1 = gl_malloc(TGL_FEATURE_TEXTURE_DIM * TGL_FEATURE_TEXTURE_DIM * components); /* GUARDED*/
        if (pixels1 == NULL) {
 #if TGL_FEATURE_ERROR_CHECK == 1
 #define ERROR_FLAG GL_OUT_OF_MEMORY
@@ -287,7 +285,7 @@ void glopTexImage1D(GLParam* p) {
        }
        /* no GLinterpolation is done here to respect the original image aliasing ! */

-       gl_resizeImageNoInterpolate(pixels1, TGL_FEATURE_TEXTURE_DIM, TGL_FEATURE_TEXTURE_DIM, pixels, width, height);
+       gl_resizeImageNoInterpolate(pixels1, TGL_FEATURE_TEXTURE_DIM, TGL_FEATURE_TEXTURE_DIM, pixels, width, height, components);
        do_free = 1;
        width = TGL_FEATURE_TEXTURE_DIM;
        height = TGL_FEATURE_TEXTURE_DIM; 
@@ -299,9 +297,9 @@ void glopTexImage1D(GLParam* p) {
    im->xsize = width;
    im->ysize = height;
 #if TGL_FEATURE_RENDER_BITS == 32
-   gl_convertRGB_to_8A8R8G8B(im->pixmap, pixels1, width, height);
+   gl_convertRGB_to_8A8R8G8B(im->pixmap, pixels1, width, height, components);
 #elif TGL_FEATURE_RENDER_BITS == 16
-   gl_convertRGB_to_5R6G5B(im->pixmap, pixels1, width, height);
+   gl_convertRGB_to_5R6G5B(im->pixmap, pixels1, width, height, components);
 #else
 #error bad TGL_FEATURE_RENDER_BITS
 #endif
@@ -323,20 +321,18 @@ void glopTexImage2D(GLParam* p) {
    GLint do_free=0;
    GLContext* c = gl_get_context();
    {
+       if (!(c->current_texture != NULL && target == GL_TEXTURE_2D && level == 0 && type == GL_UNSIGNED_BYTE && border == 0 &&
+            ((format == GL_RGB && components == 3) || (format == GL_RGBA && components == 4))))
 #if TGL_FEATURE_ERROR_CHECK == 1
-       if (!(c->current_texture != NULL && target == GL_TEXTURE_2D && level == 0 && components == 3 && border == 0 && format == GL_RGB &&
-             type == GL_UNSIGNED_BYTE))
 #define ERROR_FLAG GL_INVALID_ENUM
 #include "error_check.h"

 #else
-       if (!(c->current_texture != NULL && target == GL_TEXTURE_2D && level == 0 && components == 3 && border == 0 && format == GL_RGB &&
-             type == GL_UNSIGNED_BYTE))
            gl_fatal_error("glTexImage2D: combination of parameters not handled!!");
 #endif
    }
    if (width != TGL_FEATURE_TEXTURE_DIM || height != TGL_FEATURE_TEXTURE_DIM) {
-       pixels1 = gl_malloc(TGL_FEATURE_TEXTURE_DIM * TGL_FEATURE_TEXTURE_DIM * 3); /* GUARDED*/
+       pixels1 = gl_malloc(TGL_FEATURE_TEXTURE_DIM * TGL_FEATURE_TEXTURE_DIM * components); /* GUARDED*/
        if (pixels1 == NULL) {
 #if TGL_FEATURE_ERROR_CHECK == 1
 #define ERROR_FLAG GL_OUT_OF_MEMORY
@@ -347,7 +343,7 @@ void glopTexImage2D(GLParam* p) {
        }
        /* no GLinterpolation is done here to respect the original image aliasing ! */

-       gl_resizeImageNoInterpolate(pixels1, TGL_FEATURE_TEXTURE_DIM, TGL_FEATURE_TEXTURE_DIM, pixels, width, height);
+       gl_resizeImageNoInterpolate(pixels1, TGL_FEATURE_TEXTURE_DIM, TGL_FEATURE_TEXTURE_DIM, pixels, width, height, components);
        do_free = 1;
        width = TGL_FEATURE_TEXTURE_DIM;
        height = TGL_FEATURE_TEXTURE_DIM;
@@ -359,9 +355,9 @@ void glopTexImage2D(GLParam* p) {
    im->xsize = width;
    im->ysize = height;
 #if TGL_FEATURE_RENDER_BITS == 32
-   gl_convertRGB_to_8A8R8G8B(im->pixmap, pixels1, width, height);
+   gl_convertRGB_to_8A8R8G8B(im->pixmap, pixels1, width, height, components);
 #elif TGL_FEATURE_RENDER_BITS == 16
-   gl_convertRGB_to_5R6G5B(im->pixmap, pixels1, width, height);
+   gl_convertRGB_to_5R6G5B(im->pixmap, pixels1, width, height, components);
 #else
 #error Bad TGL_FEATURE_RENDER_BITS
 #endif
diff --git a/src/zgl.h b/src/zgl.h
index 77cc70a..9ad5405 100644
--- a/src/zgl.h
+++ b/src/zgl.h
@@ -432,10 +432,10 @@ void glEndTextures();
 GLTexture* alloc_texture(GLint h);

 /* image_util.c */
-void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint ysize);
-void gl_convertRGB_to_8A8R8G8B(GLuint* pixmap, GLubyte* rgb, GLint xsize, GLint ysize);
-void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src);
-void gl_resizeImageNoInterpolate(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src);
+void gl_convertRGB_to_5R6G5B(GLushort* pixmap, GLubyte* rgb, GLint xsize, GLint ysize, GLint components);
+void gl_convertRGB_to_8A8R8G8B(GLuint* pixmap, GLubyte* rgb, GLint xsize, GLint ysize, GLint components);
+void gl_resizeImage(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src, GLint components);
+void gl_resizeImageNoInterpolate(GLubyte* dest, GLint xsize_dest, GLint ysize_dest, GLubyte* src, GLint xsize_src, GLint ysize_src, GLint components);

Cheers, bzt

bztsrc commented 1 year ago

Okay! Let me know if you need anything. This is a very simple change, does not provide alpha transparency on textures or anything, it just allows the format to be loaded.

Cheers, bzt

bztsrc commented 1 year ago

Thank you very much. It's very likely I'll accept it.

You're welcome! I guess I can close this issue now, but I'll keep looking at it should you have some questions.

I need to get around to it. I've been doing other things and not focusing on programming recently.

No need to hurry! Take your time.

have you tested the commits for yourself and made sure it doesn't adversely affect the demos?

Yes. BTW the version I'm actively using in production is here. It has some other modifications and cleanup as well (see the readme on the link, most notably that version compiles as ANSI C without warnings), and of course includes this components parameter patch too. If you want, you can backport some of my other modifications as well.

Cheers, bzt

williehwc commented 1 year ago

I think gl_resizeImageNoInterpolate (image_util.c) should also be changed as follows, in keeping with the pattern of changing 3 to components.

From: pix1 = pix_src + (yi * xsize_src + xi) * 3; To: pix1 = pix_src + (yi * xsize_src + xi) * components;

Other than that, this is a really helpful addition to TinyGL, thanks!

Edit: Just noticed the repo you linked has the change, which is not in the diff above.

bztsrc commented 1 year ago

I think gl_resizeImageNoInterpolate (image_util.c) should also be changed as follows, in keeping with the pattern of changing 3 to components.

Absolutely. There's also a pix += components; line.

Just noticed the repo you linked has the change, which is not in the diff above.

Ah, I'm terribly sorry. I had to manually construct the diff because I've changed so many things (for example made it ANSI C89), so gitdiff was huge, and included unnecessary things not related to this. Indeed I forget to include gl_resizeImageNoInterpolate in the diff, mea culpa.

Other than that, this is a really helpful addition to TinyGL, thanks!

You're welcome! And I should be the one saying thanks for this TinyGL fork!

Cheers, bzt

williehwc commented 1 year ago

Oh, I'm not a contributer, just someone interested in using this fork and some of your changes in an upcoming project.

Just wanted to make sure: the GPL 3 license of your project does not apply to your modifications to TinyGL, right?

On Mon, Nov 28, 2022, 11:13 AM Zoltan Baldaszti @.***> wrote:

I think gl_resizeImageNoInterpolate (image_util.c) should also be changed as follows, in keeping with the pattern of changing 3 to components.

Absolutely. There's also a pix += components; line.

Just noticed the repo you linked has the change, which is not in the diff above.

Ah, I'm terribly sorry. I had to manually construct the diff because I've changed so many things (for example made it ANSI C89), so gitdiff was huge, and included unnecessary things not related to this. Indeed I forget to include gl_resizeImageNoInterpolate in the diff, mea culpa.

Other than that, this is a really helpful addition to TinyGL, thanks!

You're welcome! And I should be the one saying thanks for this TinyGL fork!

Cheers, bzt

— Reply to this email directly, view it on GitHub https://github.com/C-Chads/tinygl/issues/18#issuecomment-1329455349, or unsubscribe https://github.com/notifications/unsubscribe-auth/AATC57S74SVRAD6U4GTMKD3WKTR2HANCNFSM5LVX3F6A . You are receiving this because you commented.Message ID: @.***>

bztsrc commented 1 year ago

@williehwc:

Just wanted to make sure: the GPL 3 license of your project does not apply to your modifications to TinyGL, right?

I'm afraid they do (see GPL section 5c). That's why I've uploaded the diff here directly instead of just linking my GPL'd repo. To be clear, the patch in this issue is licensed under the same license as TinyGL's.

So as a rock-solid workaround, I've attached my entire TinyGL directory here (as soon as distributed separately, the GPL restrictions won't apply any more, this tarball is licensed as the original TinyGL, you're in the clear using this).

TinyGL.tgz (60k)

Cheers, bzt

williehwc commented 1 year ago

Thank you, this is really useful!

bztsrc commented 1 year ago

it looks like you didn't make a PR, you just posted the issue?

Ah yes, sorry about that. git push doesn't work for me on github lately (I have absolutely no issues with other sites, just with github, and it used to work here too. I haven't changed anything, but I'm upgrading my system regularly).

Cheers, bzt

bztsrc commented 1 year ago

Unrelated to this topic:

I would actually like to re-write TinyGL myself (Not using any of Bellard's code) so that I can make it CC0.

You have my permission to use my modifications to the TinyGL source as CC0, should you have use any of that with the rewrite.

However I'm not focused on other projects (Primarily related to CPU and system emulation and assemblers) so I probably don't have time for it.

Cool! Here's a Universal Disassember if you're interested. You provide the instruction set of an architecture in a text file and the script outputs a single header, MIT licensed C library, which in turn then can disassemble binaries for that architecture with a single function call.

Cheers, bzt

bztsrc commented 1 year ago

Github has been fussy about needing SSH keys to do everything. If you switch to SSH keys from https, it should work.

It's not like that, I know how to use SSH keys. For example, last week I was locked out entirely from the site, as github said verification code sent in email, but the email never arrived... only a week later. And things like that, there's always something not working for me on github. I've simply given up with its git interface, because there are much better alternatives.

I have already written a disassembler, debugger, macro assembler, a system library, and an operating system in for the instruction set I am working on. It's all public domain

Yes, I've seen that, pretty cool!

Cheers, bzt