view src/video/SDL_rect.c @ 3485:e77a69aae239

Mason Wheeler to sdl I updated SDL, and suddenly my SDL frames stopped working. They'd "initialize" full of gibberish, and I couldn't render anything to them. After a bit of digging, I found a problem: the renderer initialization routine in my SDL frame code wasn't getting called anymore. procedure TSdlFrame.Paint; begin if SDL_SelectRenderer(FWindowID) = -1 then CreateRenderer; SDL_RenderPresent; end; function TSdlFrame.CreateRenderer: boolean; const pf: tagPIXELFORMATDESCRIPTOR = (nSize: sizeof(pf); nVersion: 1; dwFlags: PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; iPixelType: PFD_TYPE_RGBA; cColorBits: 24; cAlphaBits: 8; iLayerType: PFD_MAIN_PLANE); RENDERERS: array[TRendererType] of AnsiString = ('software', 'gdi', 'opengl', 'd3d'); var pFormat: integer; begin if (SDL_SelectRenderer(FWindowID) = 0) then begin result := true; Exit; end; if FRendererType = rtOpenGL then begin pFormat := ChoosePixelFormat(canvas.Handle, @pf); if not SetPixelFormat(canvas.Handle, pFormat, @pf) then outputDebugString(PChar(SysErrorMessage(GetLastError))); if wglCreateContext(canvas.Handle) = 0 then outputDebugString(PChar(SysErrorMessage(GetLastError))); end; if (SDL_CreateRenderer(FWindowID, SDL_RendererIndex(RENDERERS[FRendererType]), [sdlrPresentFlip3, sdlrAccelerated]) = 0) then begin SDL_ShowWindow(FWindowID); assert(SDL_SetRenderDrawColor(0, 0, 0, 255) = 0); FFlags := SDL_GetWindowFlags(FWindowID); if assigned(FOnAvailable) then FOnAvailable(self); end else outputDebugString(pChar(format('SDL_CreateRenderer failed: %s', [sdl_GetError]))); result := SDL_SelectRenderer(FWindowID) = 0; end; This is a critical issue. The Paint method gets called when the control receives a WM_PAINT message from Windows. I can't create the renderer before then, or it will fail and cause trouble. And when I do create it, it needs to be created with certain parameters. So imagine my surprise when I started debugging into the DLL and found that SDL_SelectRenderer was trying to be "helpful" by creating the renderer for me if it didn't already exist! Now not only does my initialization code not get called, I end up with the wrong renderer and so things don't render as expected when I try to use the window.
author Sam Lantinga <slouken@libsdl.org>
date Tue, 24 Nov 2009 04:48:12 +0000
parents 47965eacde88
children 0267b8b1595c
line wrap: on
line source

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997-2009 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

    Sam Lantinga
    slouken@libsdl.org
*/
#include "SDL_config.h"

#include "SDL_video.h"
#include "SDL_rect_c.h"

SDL_bool
SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
{
    int Amin, Amax, Bmin, Bmax;

    /* Horizontal intersection */
    Amin = A->x;
    Amax = Amin + A->w;
    Bmin = B->x;
    Bmax = Bmin + B->w;
    if (Bmin > Amin)
        Amin = Bmin;
    if (Bmax < Amax)
        Amax = Bmax;
    if (Amax <= Amin)
        return SDL_FALSE;

    /* Vertical intersection */
    Amin = A->y;
    Amax = Amin + A->h;
    Bmin = B->y;
    Bmax = Bmin + B->h;
    if (Bmin > Amin)
        Amin = Bmin;
    if (Bmax < Amax)
        Amax = Bmax;
    if (Amax <= Amin)
        return SDL_FALSE;

    return SDL_TRUE;
}

SDL_bool
SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
{
    int Amin, Amax, Bmin, Bmax;

    /* Horizontal intersection */
    Amin = A->x;
    Amax = Amin + A->w;
    Bmin = B->x;
    Bmax = Bmin + B->w;
    if (Bmin > Amin)
        Amin = Bmin;
    result->x = Amin;
    if (Bmax < Amax)
        Amax = Bmax;
    result->w = Amax - Amin;

    /* Vertical intersection */
    Amin = A->y;
    Amax = Amin + A->h;
    Bmin = B->y;
    Bmax = Bmin + B->h;
    if (Bmin > Amin)
        Amin = Bmin;
    result->y = Amin;
    if (Bmax < Amax)
        Amax = Bmax;
    result->h = Amax - Amin;

    return !SDL_RectEmpty(result);
}

void
SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
{
    int Amin, Amax, Bmin, Bmax;

    /* Horizontal union */
    Amin = A->x;
    Amax = Amin + A->w;
    Bmin = B->x;
    Bmax = Bmin + B->w;
    if (Bmin < Amin)
        Amin = Bmin;
    result->x = Amin;
    if (Bmax > Amax)
        Amax = Bmax;
    result->w = Amax - Amin;

    /* Vertical intersection */
    Amin = A->y;
    Amax = Amin + A->h;
    Bmin = B->y;
    Bmax = Bmin + B->h;
    if (Bmin < Amin)
        Amin = Bmin;
    result->y = Amin;
    if (Bmax > Amax)
        Amax = Bmax;
    result->h = Amax - Amin;
}

SDL_bool
SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2,
                         int *Y2)
{
    int x1, y1;
    int x2, y2;
    int rectx1;
    int recty1;
    int rectx2;
    int recty2;

    if (!rect || !X1 || !Y1 || !X2 || !Y2) {
        return SDL_FALSE;
    }

    x1 = *X1;
    y1 = *Y1;
    x2 = *X2;
    y2 = *Y2;
    rectx1 = rect->x;
    recty1 = rect->y;
    rectx2 = rect->x + rect->w - 1;
    recty2 = rect->y + rect->h - 1;

    /* Check to see if entire line is inside rect */
    if (x1 >= rectx1 && x1 <= rectx2 && x2 >= rectx1 && x2 <= rectx2 &&
        y1 >= recty1 && y1 <= recty2 && y2 >= recty1 && y2 <= recty2) {
        return SDL_TRUE;
    }

    /* Check to see if entire line is to one side of rect */
    if ((x1 < rectx1 && x2 < rectx1) || (x1 > rectx2 && x2 > rectx2) ||
        (y1 < recty1 && y2 < recty1) || (y1 > recty2 && y2 > recty2)) {
        return SDL_FALSE;
    }

    if (y1 == y2) {
        /* Horizontal line, easy to clip */
        if (x1 < rectx1) {
            *X1 = rectx1;
        } else if (x1 > rectx2) {
            *X1 = rectx2;
        }
        if (x2 < rectx1) {
            *X2 = rectx1;
        } else if (x2 > rectx2) {
            *X2 = rectx2;
        }
        return SDL_TRUE;
    }

    if (x1 == x2) {
        /* Vertical line, easy to clip */
        if (y1 < recty1) {
            *Y1 = recty1;
        } else if (y1 > recty2) {
            *Y1 = recty2;
        }
        if (y2 < recty1) {
            *Y2 = recty1;
        } else if (y2 > recty2) {
            *Y2 = recty2;
        }
        return SDL_TRUE;
    }

    else {
        /* The task of clipping a line with finite slope ratios in a fixed-
         * precision coordinate space is not as immediately simple as it is
         * with coordinates of arbitrary precision. If the ratio of slopes
         * between the input line segment and the result line segment is not
         * a whole number, you have in fact *moved* the line segment a bit,
         * and there can be no avoiding it without more precision
         */
        int *x_result_[] = { X1, X2, NULL }, **x_result = x_result_;
        int *y_result_[] = { Y1, Y2, NULL }, **y_result = y_result_;
        SDL_bool intersection = SDL_FALSE;
        double b, m, left, right, bottom, top;
        int xl, xh, yl, yh;

        /* solve mx+b line formula */
        m = (double) (y1 - y2) / (double) (x1 - x2);
        b = y2 - m * (double) x2;

        /* find some linear intersections */
        left = (m * (double) rectx1) + b;
        right = (m * (double) rectx2) + b;
        top = (recty1 - b) / m;
        bottom = (recty2 - b) / m;

        /* sort end-points' x and y components individually */
        if (x1 < x2) {
            xl = x1;
            xh = x2;
        } else {
            xl = x2;
            xh = x1;
        }
        if (y1 < y2) {
            yl = y1;
            yh = y2;
        } else {
            yl = y2;
            yh = y1;
        }

#define RISING(a, b, c) (((a)<=(b))&&((b)<=(c)))

        /* check for a point that's entirely inside the rect */
        if (RISING(rectx1, x1, rectx2) && RISING(recty1, y1, recty2)) {
            x_result++;
            y_result++;
            intersection = SDL_TRUE;
        } else
            /* it was determined earlier that *both* end-points are not contained */
        if (RISING(rectx1, x2, rectx2) && RISING(recty1, y2, recty2)) {
            **(x_result++) = x2;
            **(y_result++) = y2;
            intersection = SDL_TRUE;
        }

        if (RISING(recty1, left, recty2) && RISING(xl, rectx1, xh)) {
            **(x_result++) = rectx1;
            **(y_result++) = (int) left;
            intersection = SDL_TRUE;
        }

        if (*x_result == NULL)
            return intersection;
        if (RISING(recty1, right, recty2) && RISING(xl, rectx2, xh)) {
            **(x_result++) = rectx2;
            **(y_result++) = (int) right;
            intersection = SDL_TRUE;
        }

        if (*x_result == NULL)
            return intersection;
        if (RISING(rectx1, top, rectx2) && RISING(yl, recty1, yh)) {
            **(x_result++) = (int) top;
            **(y_result++) = recty1;
            intersection = SDL_TRUE;
        }

        if (*x_result == NULL)
            return intersection;
        if (RISING(rectx1, bottom, rectx2) && RISING(yl, recty2, yh)) {
            **(x_result++) = (int) bottom;
            **(y_result++) = recty2;
            intersection = SDL_TRUE;
        }

        return intersection;
    }

    return SDL_FALSE;
}

void
SDL_AddDirtyRect(SDL_DirtyRectList * list, const SDL_Rect * rect)
{
    SDL_DirtyRect *dirty;

    /* FIXME: At what point is this optimization too expensive? */
    for (dirty = list->list; dirty; dirty = dirty->next) {
        if (SDL_HasIntersection(&dirty->rect, rect)) {
            SDL_UnionRect(&dirty->rect, rect, &dirty->rect);
            return;
        }
    }

    if (list->free) {
        dirty = list->free;
        list->free = dirty->next;
    } else {
        dirty = (SDL_DirtyRect *) SDL_malloc(sizeof(*dirty));
        if (!dirty) {
            return;
        }
    }
    dirty->rect = *rect;
    dirty->next = list->list;
    list->list = dirty;
}

void
SDL_ClearDirtyRects(SDL_DirtyRectList * list)
{
    SDL_DirtyRect *prev, *curr;

    /* Skip to the end of the free list */
    prev = NULL;
    for (curr = list->free; curr; curr = curr->next) {
        prev = curr;
    }

    /* Add the list entries to the end */
    if (prev) {
        prev->next = list->list;
    } else {
        list->free = list->list;
    }
    list->list = NULL;
}

void
SDL_FreeDirtyRects(SDL_DirtyRectList * list)
{
    while (list->list) {
        SDL_DirtyRect *elem = list->list;
        list->list = elem->next;
        SDL_free(elem);
    }
    while (list->free) {
        SDL_DirtyRect *elem = list->free;
        list->free = elem->next;
        SDL_free(elem);
    }
}

/* vi: set ts=4 sw=4 expandtab: */