21

Agh, holy shit. devRant, I need some love.

I have successfully double-buffered the Windows console (cmd.exe) but all hell breaks loose when you resize the fucking window. The currently active buffer will receive the change in dimensions while the inactive buffer will not, resulting in the window quickly oscillating between the two sizes as the buffers change size.

That got me stuck for about a day. Today, I got it sort of working but it wasn't satisfying at all. I can get it to resize LARGER, but if you resize the window SMALLER, the actual buffer inside the window doesn't change size, so scrollbars appear and I have NO IDEA HOW TO FIX THAT. I somehow need to calculate, or use the API to find, the perfect dimensions (In rows and columns) for the console buffer INSIDE the window buffer for them to not have scrollbars.

And I just - -

I cannot gather the energy to do so right now.

I spent hours finding the solution to this bullshit and ONLY SOLVED HALF MY PROBLEM.

And stack overflow isn't exactly helpful. My problem is so specific that nobody even writes comments on the question.

I guess I need to calculate the amount of characters the screen can hold given the font size and the window size, but fuck, that's a lot of work to do just for something that probably won't even work anyways.

Well, off to the code editor again. Time to inevitably waste my time doing something that won't work.

Yay, programming.

Comments
  • 5
    Do you have a git repo I could test out? Not sure if I can help you fix the issue but I may be able to test it.

    I wrote a ton of C++ cmd.exe console applications in my early days of programming so I'll help in what way I can.
  • 1
    @starrynights89 I have 100% torn this shit up trying to get it to work to any degree... I will get a git repo up soon enough, and let you know
  • 2
    @AlgoRythm It's good to get in the habit of doing source control. It'll save your ass in situations like this.
  • 1
    @starrynights89 I only see it saving my ass if it worked in the first place.
  • 1
    Lol. Bug fixing is always the hardest part. Especially when you've wasted a day with it.

    What's the app supposed to do and what language did you use?
  • 1
    @starrynights89 Its a library for Windows terminal graphics, sort of in the spirit of Processing, but not taking any inspiration from it. Above just rendering graphics, it also handles events like key presses.
  • 5
    How about reinitializing the double buffer on resize?
  • 0
    @WhAtEvErYoUmEaN
    yeah.. I suppose you write the buffers line by line. When you just keep adjusting the width and height that you write the the buffer, read from the buffer and "render", then your buffer should resize with your window. You may also have to reallocate the buffer when increasing the size obviously.
  • 1
    @WhAtEvErYoUmEaN I'll give it a shot, doesn't seem like the most elegant solution, but if it works, who gives a fuck at this point.
  • 0
    @AlgoRythm that is what is always happening when you increase the size of an array. when the place it is stored at cant hold the new size, it has to be copied to another location that has enough space.
  • 0
    @simulate Yeah but then any pointers (or, since its Win32, "Handles") to the buffer would be invalid... which I would like to avoid.
  • 0
    @AlgoRythm
    yeah that is what I hate about pointers. they are like the fast lane to segfaults. I suggest that you dont copy the pointer and only keep it at one location and access it through functions. if you need to store a location in the buffer somewhere use integers(indices/offsets). they wont get invalidated.
  • 0
    @AlgoRythm
    thats definitely something I would tell anyone to do. dont pass around pointers, pass indices. they dont get invalidated. the drawback with pure indices is of course that there is no type safety and sometimes it is hard to remember what an index is for. also you need the pointer to access the data that the index is pointing to.
    At least in C++ though (and probably in any language with classes and generics) you can easily wrap an index in a class that stores a reference to the array itself/a pointer to the array pointer and if you have generics, you can dynamically make that work for any type of array (otherwise you could just store the sizeof an element of the array and access it that way) and you have typesafe, uninvalidatable references to elements of an array. indices on steroids, fundamentally. The only thing you still have to watch is that your array doesnt shrink and you try to access it behind it, so for that use an assertion in the class' access function.
  • 0
    @simulate Is that truly less complicated than pointers
  • 0
    @AlgoRythm
    no, but it cant get invalidated πŸ˜„
    and it isnt much more complicated than pointers
  • 0
    @AlgoRythm
    I was running out of space in the previous comment πŸ˜‹ it is just that instead of saying:
    char* item = &items[x];
    // ...
    foo(*item);

    you do:

    unsigned int itemIndex = x;
    // ...
    foo(items[itemIndex]);

    wrap that in a class and you can say, without generics:

    ID item(x, &items, sizeof(char));
    // ...
    foo(*item);
    // overloaded * operator accesses array pointer and returns item at x

    with generics:
    using ItemID = ID<char, items>;
    ItemID item(x);
    // ...
    foo(*item);

    Anyhow, I will stop harassing you with my coding practices now. You dont need this exactly. It is just a wrapper for pointers to make it possible to distribute references to items in a dynamic array. It is basically the blood cycle of my main project by now πŸ˜‚ i only use that wrapper. fuck pointers or even smart pointers. this solution is way simpler and efficient.
  • 1
    @simulate If the user of the library wanted to grab the actual handle of the screen buffer for whatever reason, recreating the buffer on resize would invalidate the handle to their buffer. This is undesirable behavior. But I understand what you're going at, and that's actually how my library works under the hood.

    I have some internal functions:

    Buffer* activeBuffer();

    Buffer* inactiveBuffer();

    (Buffer is a class that wraps the WinAPI HANDLE datatype)

    they work like this:

    Buffer* activeBuffer(){

    return buffers[activeBufferIndex];

    }

    Buffer* inactiveBuffer(){

    return buffers[!activeBufferIndex];

    }

    And is used like this:

    activeBuffer()->clear();

    Or more than one operation:

    Buffer* aBuffer = activeBuffer();

    aBuffer->clear();

    aBuffer->print("Hello world");

    // etc...

    But yeah. Destroying and recreating a new buffer on resize is not my ideal solution.
  • 0
    @AlgoRythm
    Ah okay I see. Luckily you can use classes 😊
    But you have to reallocate the array that the pointers in your buffer class are pointing to. that is what dynamic arrays have to do. no way around it. you dont have to reinitialize both your Buffer objects, because they only store the pointer to the block of data your are resizing (and that pointer is just an ordinary int or long(depending on 32 or 64 bit system)). So it should just be something like:
    void Buffer::resize(uint w, uint h)
    {
    uint newSize = w * h;
    if (newSize > m_size) {
    void* new_ptr = malloc(newSize);
    memcpy(m_ptr, new_ptr, m_size);
    free(m_ptr);
    m_ptr = new_ptr;
    }
    m_width = w;
    m_height = h;
    m_size = newSize;
    }
  • 0
    I dont know the winapi, though i dont think it matters. when writing to the console the winapi will most likely also take a const char*, maybe a const w_char*
  • 0
    @simulate You are mistaken, the buffers are actual screen buffers

    https://docs.microsoft.com/en-us/...

    And I'd prefer to use new and delete if we're talking c++ ;) the syntax is a bit cleaner imo. Anyways, point is, there's no actual allocation on my end. If I resize the ConsoleScreenBuffer, the handle points to the same location. If I create a new ConsoleScreenBuffer, the old handle points to a invalid location.
  • 0
    Please don't kill me over this, but what about multi-level pointers? You could update your pointers to the buffers and only make your pointers available in your API.
  • 0
    @AlgoRythm
    That is why people are so wrong when they say you shouldnt "reinvent the wheel" πŸ˜‚ ok then, learn a framework and find out that it has its problems and doesnt fit your problem perfectly and there is nothing you can do about bugs or missing features except skimming through docs and ending up with hacky workarounds.

    Rendering to the console can easily be done using standard C++ IO functions and it is a lot cleaner than "createConsoleScreenBuffer" imo, but maybe that is because i am more of a low level guy and like to work close to the language.
  • 0
    @simulate You can't control the size of the buffer with std libs. There's 9000 rows of unused buffer and an ugly scrollbars. That's why I'm using the windows API.

    You also can't control attributes with std libs. No colors.

    There's a lot of reasons I'm actually using the windows API
  • 1
    @AlgoRythm
    well, you could use colors, they are just escaped codes at least on linux.

    Yeah, there is no point of debating something I have no clue about. Good luck with your project and hopefully you get that resizing right. It seems to me it is a matter of finding the right api procedure to make that work the way you want.
  • 1
    @simulate afaik cmd.exe isn't ANSI. I'm sure I'll get through it. Always do.
  • 1
    @simulate I fixed the issue to a reasonable degree. Seemingly at random, rarely, the window will stop responding to resizing (Like the actual window itself just doesn't fucking do anything) but I really don't see how my program could cause that.

    Anyways, here's the code, plus the neato test program I wrote up:

    https://github.com/AlgoRythm-Dylan/...
  • 0
Add Comment