notcurses icon indicating copy to clipboard operation
notcurses copied to clipboard

Erroneous colors inside a tmux session

Open saccharineboi opened this issue 2 years ago • 2 comments

I'm writing a rasterizer and I've noticed that colors differ between the xfce terminal and from inside of a tmux session. So, here's the version running without tmux on xfce terminal (version 0.8.10) where LANG=en_US.UTF-8, TERM=xfce, and LC_CTYPE="", notcurses version 3.0.7 on Linux 5.17.1-zen1-1-zen (distro is Arch Linux):

https://user-images.githubusercontent.com/95090318/160998630-a4bcfb8e-4571-4769-a380-06572035d32e.mp4

Here's the same code running inside tmux session will all the same parameters except TERM=tmux-256color:

https://user-images.githubusercontent.com/95090318/160998907-c76a8bd9-36f0-48ac-a1e1-298ad2536184.mp4

I tested this again in tmux with TERM=xfce and it produced the same result.

How can I debug this? I'd like to find the source of the problem but I don't even know where to look.

Also sometimes the terminal gets corrupted after I exit from the rasterizer inside tmux, but it never happens outside the tmux session.

saccharineboi avatar Mar 31 '22 07:03 saccharineboi

tmux definitely introduces a layer between us and the true terminal that leads to complexity, but as far as i'm aware, we're able to work around most of it. i can't look into this right now, but i'll load up tmux this weekend and get to the bottom of it. is it possible for you to post your test code, ideally minimized to show the problem?

dankamongmen avatar Mar 31 '22 08:03 dankamongmen

This is pretty much the gist of what's happening:

/// We go inside the render loop
while (true) {
    
        struct ncvisual_options options = {
            .n          = renderPlane,
            .scaling    = NCSCALE_NONE,
            .leny       = (unsigned)framebufferHeight,
            .lenx       = (unsigned)framebufferWidth,
            .blitter    = NCBLIT_1x1
        };

        int cnt = 0;
        for (int i = 0; i < framebufferHeight; ++i) {
            for (int j = 0; j < framebufferWidth; ++j) {

                /// This is the pixel structure used by the rasterizer
                /// It contains things like color and depth value,
                /// but at this point the final color is determined and
                /// ready to be displayed
                TXpixel_t* currentPixel = txGetPixelFromFrontFramebuffer(i, j);

                /// Since the colors are stored as floating point values 0.0f <= X <= 1.0f
                /// we turn them into their integer equivalents  0 <= I <= 255
                uint32_t u_r = (uint32_t)(currentPixel->color[0] * 255.0f);
                uint32_t u_g = (uint32_t)(currentPixel->color[1] * 255.0f);
                uint32_t u_b = (uint32_t)(currentPixel->color[2] * 255.0f);

                /// Store the color as a 32-bit unsigned integer
                raw_framebuffer[cnt++] = (((uint32_t)255 << 24) |
                                                    (u_b << 16) |
                                                    (u_g << 8)  |
                                                    (u_r << 0));
            }
        }

        /// Blit our color buffer onto a plane
        ncblit_rgba(raw_framebuffer,
                    txGetFramebufferWidth() * (int)(sizeof(uint32_t)),
                    &options);

        /// Display it on the terminal
        notcurses_render(txGetContext());
}

saccharineboi avatar Mar 31 '22 13:03 saccharineboi