V FAQ (DRAWING STUFF)

  • Fast way to display bitmaps?
  • More on displaying images fast
  • Coordinate Translation and Scaling
  • About colors and color maps
  • When to set attributes for a vCanvasPane
  • Too many Redraw messages to keep up with

  • Fast way to display bitmaps?

    Q:
    I'm using V to display bitmaps. My app is rendering a complex image so I would like to display the result every few seconds. I tried drawing my bitmap with DrawIcon, but it takes too long and the second call to the function displays the same bitmap even if the data of the vIcon changed. I tried using a pen and drawing points one by one but that is way too slow.

    So, is there any easy and fast way to display 24-bit bitmaps using V?

    A:

    This may be one of the weaker parts of V. I've spent a good deal of time with this issue, and can't get stuff real fast. In theory, writing to a vMemDC should be the fastest way to write pixels, which you can do a row at a time with DrawColorPoints, then transferring to the screen with CopyFromMemDC. This technique get you about as close to the native drawing stuff as can be done portably, but it is still faster to draw directly to the screen using DrawColorPoints. It isn't real fast.

    The native tool kits let you work directly with the bitmap/pixmap in memory, but do it quite differently on Windows and X. Perhaps someday I'll figure out a way to give portable access to the underlying model.

    An alternative, and not a terrible one, is to get the handle to the actual X or Windows window used for the canvas. This is HWND vCanvas::DrawingWindow() for Windows, and Widget vCanvas::DrawingWindow() -OR- Drawable vCanvas::GetXDrawable() for X. You can then use the HWND or Widget/Drawable as to draw to directly using the native drawing toolkits. These are usually much easier to use and figure out than all the control stuff for dialogs and menus.


    More on displaying images fast

    Q:
    I'm thinking of using V for a project I'm about to start. I need to be able to display images (8, 16, 24, and maybe 32 bit) to a window and I need to do it very fast.

    A:

    Actually, in its current state, V can't really do what you need. The vMemoryDC already uses BitBlt to in the CopyFromMemoryDC method, but it is still too slow - it takes too long to fill the image, no matter what mode you use.

    The ultimate solution is to provide access directly to the screen memory via a pointer. This is something like Microsoft's game API. However, I haven't had the time to do it portably, although I think it can be done.

    The alternative is to drop down to real Windows or X code. The vCanvas provides the necessary hooks to get the Window, Drawable, or Widget as needed. This solution is not portable.


    Coordinate Translation and Scaling

    Q:
    When using a canvas with scaling and translation, it's not clear whether coordinates are first translated and then scaled, or vice versa.

    A:

      ScreenX = (((PassedInX + XTranslate) * ScaleMult) / ScaleDiv);
    

    About colors and color maps

    Q:
    I assume that V tries to allocate read/write color cells when under X, so that it can (possibly) change colors. If the color map is full, does it just take what it can get?

    A:

    Presently, V tries to hide what is going on with the color map. This led to some problems on the X version in earlier releases. With V Version 1.07 and later, V tries to allow efficient use of the colormap while still hiding most of the details.

    The main way to use and generate colors is with vColor objects. There are 16 predefined vColors, and you can declare other vColors, either with no color specified (which defaults to black), or your own colors. Ideally, it wouldn't matter how many colors you used, or how many vColors you declared, or how many times you changed the color value of vColor objects.

    In reality, some color systems do allow unlimited colors, but most existing systems run with a palette or color map of 256 colors. So mostly, at any given time, a program can have only 256 active colors. As better color hardware gets more widely used, this situation will change, but count on only 256 for now.

    The question then becomes which 256 colors are available to the program. Both X and Windows provide default system color maps that provide the current 256 colors, and V uses the default system color maps. The way the system color maps work are somewhat different for X and Windows, however.

    The situation for X is currently somewhat better than Windows. The default system color map is allocated partly ReadOnly, and partly ReadWrite. Usually, four to eight colors are allocated ReadOnly, and correspond to black, white, and the basic colors used by the screen manager. The rest of the entries are available for program use. When you create a new color, either by declaring a vColor object with a new color, or you use vColor::Set to set an existing object to a new color, a new cell of the system color map is allocated and used. If you continue to generate more new colors, the map eventually fills up, and you don't get what you had hoped for.

    With V Version 1.07 and later, a new method called vColor::ResetColor was added to help solve this problem. If you will be generating lots of new colors, you can only use about 245 or so of them at a time. If you use vColor::Set to change the colors, the color map fills up. If, on the other hand, you reuse and existing vColor object by calling vColor::ResetColor, then the original entry in the X system color map is reused. Thus, as long as you don't use more than the number of available entries in the color map, you won't have problems displaying just what you want at any given time. You can use vColor::BitsOfColor to determine the color resolution of the system you are running on.

    The situation on Windows is different. There, you still usually have 256 colors, but the default system color map (called a palette in Windows jargon) is fixed. Each time you use a color, Windows uses the closest match, and this is sometimes a dithered color. Thus, while you will never run out of palette entries, you also don't always get the color you wanted.

    Since Windows systems more commonly have more colors, and since you don't run out of color map entries, I don't plan to change this soon. Changing would mean adding a color map or pallete V object, with all the portability problems that introduces. For now, vColor::Set and vColor::Reset have identical behavior on Windows, but quite different behavior on X.


    When to set attributes for a vCanvasPane

    Q:
    When *exactly* is the right time to set such attributes as Background color etc. to a vCanvasPane? The attached DC is not available at constructor call, so I tricked around using static variables and Redraw(), but there has to be a cleaner way, no?

    A:

    Actually, you got it. Redraw is called when the window is first displayed, before you have any chance to call any of your code. So, you really do need something like:

      void myCanvas::Redraw(int x, int y, int h, int w)
      {
        static int first = 1;
    
        // Redraw is called when the canvas is first displayed,
        // before your code can do any real work. The vDC is
        // available at this point. Any special initialization
        // needs to be done here because the vDC is not
        // available at constructor time.
        if (first)
          {
            first = 0;
    
            // Set colors, whatever now...
    
            // And call your parent class's Redraw
            vParentPane::Redraw(x,y,h,w);
            return;
          }
        // Normal Redraw code goes here
        ....
      }
    

    Too many Redraw messages to keep up with

    Q:
    My V application takes quite a bit of time to redraw its image. When I drag another window across the V app's window, the app gets behind trying to keep up with all the Redraw messages sent by this action. Is there a way around this problem?

    A:

    This problem doesn't occur on all platforms. (e.g., Windows draws an outline of the top window, avoiding these multiple calls to Redraw. X and NT do generate multiple calls.) No matter how fast V drawing ever gets, this situation will no doubt continue to exist. There is a rather simple solution that works for the V Icon editor that limits the total number of redraws to 2. Consider the following code fragment adapted from the V Icon Editor code:

    //===================>>> myCanvasPane::Redraw <<<=================
      void myCanvasPane::Redraw(int x, int y, int w, int h)
      {
        // Cheap way to handle multiple calls to Redraw that
        // doesn't use the passed coordinates.
    
        static int nest = 0;  // Track multiple calls to Redraw
    
        if (++nest > 1)   // ignore multiple calls
            return;
    
        DrawImage();      // draw image - may take a while
    
        if (nest > 1)     // had nested calls, so need to redraw again
          {
            DrawImage();  // draw image
          }
       nest = 0;          // Really done
      }