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

    if (!A) {
        SDL_InvalidParamError("A");
        return SDL_FALSE;
    }

    if (!B) {
        SDL_InvalidParamError("B");
        return SDL_FALSE;
    }

    if (!result) {
        SDL_InvalidParamError("result");
        return SDL_FALSE;
    }

    /* Special cases for empty rects */
    if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
        result->w = 0;
        result->h = 0;
        return SDL_FALSE;
    }

    /* 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;

    if (!A || !B || !result) {
        return;
    }

    /* Special cases for empty Rects */
    if (SDL_RectEmpty(A)) {
      if (SDL_RectEmpty(B)) {
       /* A and B empty */
       return;
      } else {
       /* A empty, B not empty */
       *result = *B;
       return;
      }
    } else {      
      if (SDL_RectEmpty(B)) {
       /* A not empty, B empty */
       *result = *A;
       return;
      } 
    }
    
    /* 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 union */
    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;
}
示例#3
0
static int
D3D_UpdateClipRect(SDL_Renderer * renderer)
{
    const SDL_Rect *rect = &renderer->clip_rect;
    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
    RECT r;
    HRESULT result;

    if (!SDL_RectEmpty(rect)) {
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
        r.left = rect->x;
        r.top = rect->y;
        r.right = rect->w + rect->w;
        r.bottom = rect->y + rect->h;

        result = IDirect3DDevice9_SetScissorRect(data->device, &r);
        if (result != D3D_OK) {
            D3D_SetError("SetScissor()", result);
            return -1;
        }
    } else {
        IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
    }
    return 0;
}
SDL_bool
SDL_HasIntersection(const SDL_Rect * A, const SDL_Rect * B)
{
    int Amin, Amax, Bmin, Bmax;

    if (!A) {
        SDL_InvalidParamError("A");
        return SDL_FALSE;
    }

    if (!B) {
        SDL_InvalidParamError("B");
        return SDL_FALSE;
    }

    /* Special cases for empty rects */
    if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
        return SDL_FALSE;
    }

    /* 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;
}
示例#5
0
Rectangle::Rectangle(SDL_Rect rect) {
	if (!SDL_RectEmpty(&rect)) {
		x = rect.x;
		y = rect.y;
		w = rect.w;
		h = rect.h;
	}
}
示例#6
0
/*
 * SDL.rectEmpty(rect)
 *
 * Arguments:
 *	rect the rectangle
 *
 * Returns:
 *	True if empty
 */
static int
l_rectEmpty(lua_State *L)
{
	SDL_Rect rect;

	videoGetRect(L, 1, &rect);

	return commonPush(L, "b", SDL_RectEmpty(&rect));
}
示例#7
0
Tile* Tile_create(const int type, TextureCache* tc, const char* colorPrefix) {
	Tile* this = malloc(sizeof(Tile));
	this->type = type;
	this->blocks = true;
	SDL_RectEmpty(&this->physics.bounds);
	if (!Tile_initByType(this, tc, colorPrefix)) {
		free(this);
		return NULL;
	}
	return this;
}
SDL_bool
SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result)
{
    int Amin, Amax, Bmin, Bmax;

    if (!A || !B || !result) {
        // TODO error message
        return SDL_FALSE;
    }

    /* Special cases for empty rects */
    if (SDL_RectEmpty(A) || SDL_RectEmpty(B)) {
        return SDL_FALSE;
    }
    
    /* 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);
}
示例#9
0
static int
SW_UpdateClipRect(SDL_Renderer * renderer)
{
    SW_RenderData *data = (SW_RenderData *) renderer->driverdata;
    SDL_Surface *surface = data->surface;
    const SDL_Rect *rect = &renderer->clip_rect;

    if (surface) {
        if (!SDL_RectEmpty(rect)) {
            SDL_SetClipRect(surface, rect);
        } else {
            SDL_SetClipRect(surface, NULL);
        }
    }
    return 0;
}
示例#10
0
static int
GLES_UpdateClipRect(SDL_Renderer * renderer)
{
    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
    const SDL_Rect *rect = &renderer->clip_rect;

    if (SDL_CurrentContext != data->context) {
        /* We'll update the clip rect after we rebind the context */
        return 0;
    }

    if (!SDL_RectEmpty(rect)) {
        data->glEnable(GL_SCISSOR_TEST);
        data->glScissor(rect->x, renderer->viewport.h - rect->y - rect->h, rect->w, rect->h);
    } else {
        data->glDisable(GL_SCISSOR_TEST);
    }
    return 0;
}
示例#11
0
static int
DirectFB_UpdateClipRect(SDL_Renderer * renderer)
{
    const SDL_Rect *rect = &renderer->clip_rect;
    DirectFB_RenderData *data = (DirectFB_RenderData *) renderer->driverdata;
    IDirectFBSurface *destsurf = get_dfb_surface(data->window);
    DFBRegion region;

    if (!SDL_RectEmpty(rect)) {
        region.x1 = rect->x;
        region.x2 = rect->x + rect->w;
        region.y1 = rect->y;
        region.y2 = rect->y + rect->h;
        SDL_DFB_CHECKERR(destsurf->SetClip(destsurf, &region));
    } else {
        SDL_DFB_CHECKERR(destsurf->SetClip(destsurf, NULL));
    }
    return 0;
  error:
    return -1;
}
示例#12
0
 bool Rect::isEmpty() const {
     SDL_Rect r;
     return SDL_RectEmpty(this->copyInto(&r)) == SDL_TRUE;
 }
示例#13
0
void
SDLTest_CommonEvent(SDLTest_CommonState * state, SDL_Event * event, int *done)
{
    int i;
    static SDL_MouseMotionEvent lastEvent;

    if (state->verbose & VERBOSE_EVENT) {
        SDLTest_PrintEvent(event);
    }

    switch (event->type) {
    case SDL_WINDOWEVENT:
        switch (event->window.event) {
        case SDL_WINDOWEVENT_CLOSE:
            {
                SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
                if (window) {
                    SDL_DestroyWindow(window);
                }
            }
            break;
        }
        break;
    case SDL_KEYDOWN:
        switch (event->key.keysym.sym) {
            /* Add hotkeys here */
        case SDLK_PRINTSCREEN: {
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    for (i = 0; i < state->num_windows; ++i) {
                        if (window == state->windows[i]) {
                            SDLTest_ScreenShot(state->renderers[i]);
                        }
                    }
                }
            }
            break;
        case SDLK_EQUALS:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-+ double the size of the window */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    int w, h;
                    SDL_GetWindowSize(window, &w, &h);
                    SDL_SetWindowSize(window, w*2, h*2);
                }
            }
            break;
        case SDLK_MINUS:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-- half the size of the window */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    int w, h;
                    SDL_GetWindowSize(window, &w, &h);
                    SDL_SetWindowSize(window, w/2, h/2);
                }
            }
            break;
        case SDLK_c:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-C copy awesome text! */
                SDL_SetClipboardText("SDL rocks!\nYou know it!");
                printf("Copied text to clipboard\n");
            }
            if (event->key.keysym.mod & KMOD_ALT) {
                /* Alt-C toggle a render clip rectangle */
                for (i = 0; i < state->num_windows; ++i) {
                    int w, h;
                    if (state->renderers[i]) {
                        SDL_Rect clip;
                        SDL_GetWindowSize(state->windows[i], &w, &h);
                        SDL_RenderGetClipRect(state->renderers[i], &clip);
                        if (SDL_RectEmpty(&clip)) {
                            clip.x = w/4;
                            clip.y = h/4;
                            clip.w = w/2;
                            clip.h = h/2;
                            SDL_RenderSetClipRect(state->renderers[i], &clip);
                        } else {
                            SDL_RenderSetClipRect(state->renderers[i], NULL);
                        }
                    }
                }
            }
            break;
        case SDLK_v:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-V paste awesome text! */
                char *text = SDL_GetClipboardText();
                if (*text) {
                    printf("Clipboard: %s\n", text);
                } else {
                    printf("Clipboard is empty\n");
                }
                SDL_free(text);
            }
            break;
        case SDLK_g:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-G toggle grab */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    SDL_SetWindowGrab(window, !SDL_GetWindowGrab(window) ? SDL_TRUE : SDL_FALSE);
                }
            }
            break;
        case SDLK_m:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-M maximize */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    Uint32 flags = SDL_GetWindowFlags(window);
                    if (flags & SDL_WINDOW_MAXIMIZED) {
                        SDL_RestoreWindow(window);
                    } else {
                        SDL_MaximizeWindow(window);
                    }
                }
            }
            break;
        case SDLK_r:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-R toggle mouse relative mode */
                SDL_SetRelativeMouseMode(!SDL_GetRelativeMouseMode() ? SDL_TRUE : SDL_FALSE);
            }
            break;
        case SDLK_z:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-Z minimize */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    SDL_MinimizeWindow(window);
                }
            }
            break;
        case SDLK_RETURN:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-Enter toggle fullscreen */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    Uint32 flags = SDL_GetWindowFlags(window);
                    if (flags & SDL_WINDOW_FULLSCREEN) {
                        SDL_SetWindowFullscreen(window, SDL_FALSE);
                    } else {
                        SDL_SetWindowFullscreen(window, SDL_TRUE);
                    }
                }
            } else if (event->key.keysym.mod & KMOD_ALT) {
                /* Alt-Enter toggle fullscreen desktop */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    Uint32 flags = SDL_GetWindowFlags(window);
                    if (flags & SDL_WINDOW_FULLSCREEN) {
                        SDL_SetWindowFullscreen(window, SDL_FALSE);
                    } else {
                        SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
                    }
                }
            }
            break;
        case SDLK_b:
            if (event->key.keysym.mod & KMOD_CTRL) {
                /* Ctrl-B toggle window border */
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                if (window) {
                    const Uint32 flags = SDL_GetWindowFlags(window);
                    const SDL_bool b = ((flags & SDL_WINDOW_BORDERLESS) != 0) ? SDL_TRUE : SDL_FALSE;
                    SDL_SetWindowBordered(window, b);
                }
            }
            break;
        case SDLK_0:
            if (event->key.keysym.mod & KMOD_CTRL) {
                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
                SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Test Message", "You're awesome!", window);
            }
            break;
        case SDLK_1:
            if (event->key.keysym.mod & KMOD_CTRL) {
                FullscreenTo(0, event->key.windowID);
            }
            break;
        case SDLK_2:
            if (event->key.keysym.mod & KMOD_CTRL) {
                FullscreenTo(1, event->key.windowID);
            }
            break;
        case SDLK_ESCAPE:
            *done = 1;
            break;
        case SDLK_SPACE:
        {
            char message[256];
            SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);

            SDL_snprintf(message, sizeof(message), "(%i, %i), rel (%i, %i)\n", lastEvent.x, lastEvent.y, lastEvent.xrel, lastEvent.yrel);
            SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Last mouse position", message, window);
            break;
        }
        default:
            break;
        }
        break;
    case SDL_QUIT:
        *done = 1;
        break;
    case SDL_MOUSEMOTION:
        lastEvent = event->motion;
        break;
    }
}
示例#14
0
文件: SDL_blit.c 项目: 0-wiz-0/mame
/* The general purpose software blit routine */
static int
SDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
             SDL_Surface * dst, SDL_Rect * dstrect)
{
    int okay;
    int src_locked;
    int dst_locked;

    /* Everything is okay at the beginning...  */
    okay = 1;

    /* Lock the destination if it's in hardware */
    dst_locked = 0;
    if (SDL_MUSTLOCK(dst)) {
        if (SDL_LockSurface(dst) < 0) {
            okay = 0;
        } else {
            dst_locked = 1;
        }
    }
    /* Lock the source if it's in hardware */
    src_locked = 0;
    if (SDL_MUSTLOCK(src)) {
        if (SDL_LockSurface(src) < 0) {
            okay = 0;
        } else {
            src_locked = 1;
        }
    }

    /* Set up source and destination buffer pointers, and BLIT! */
    if (okay && !SDL_RectEmpty(srcrect)) {
        SDL_BlitFunc RunBlit;
        SDL_BlitInfo *info = &src->map->info;

        /* Set up the blit information */
        info->src = (Uint8 *) src->pixels +
            (Uint16) srcrect->y * src->pitch +
            (Uint16) srcrect->x * info->src_fmt->BytesPerPixel;
        info->src_w = srcrect->w;
        info->src_h = srcrect->h;
        info->src_pitch = src->pitch;
        info->src_skip =
            info->src_pitch - info->src_w * info->src_fmt->BytesPerPixel;
        info->dst =
            (Uint8 *) dst->pixels + (Uint16) dstrect->y * dst->pitch +
            (Uint16) dstrect->x * info->dst_fmt->BytesPerPixel;
        info->dst_w = dstrect->w;
        info->dst_h = dstrect->h;
        info->dst_pitch = dst->pitch;
        info->dst_skip =
            info->dst_pitch - info->dst_w * info->dst_fmt->BytesPerPixel;
        RunBlit = (SDL_BlitFunc) src->map->data;

        /* Run the actual software blit */
        RunBlit(info);
    }

    /* We need to unlock the surfaces if they're locked */
    if (dst_locked) {
        SDL_UnlockSurface(dst);
    }
    if (src_locked) {
        SDL_UnlockSurface(src);
    }
    /* Blit is done! */
    return (okay ? 0 : -1);
}
示例#15
0
文件: render.c 项目: nikarul/splatgl
int Splat_Render(Splat_Canvas *canvas) {
  if (!canvas) {
    Splat_SetError("Splat_Render:  Invalid argument.");
    return -1;
  }

  int winwidth, winheight;
  SDL_Rect scaledRect;

  SDL_GetWindowSize(window, &winwidth, &winheight);

  /* Render to our framebuffer */
  glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); ERRCHECK();
  glViewport(0, 0, viewportWidth, viewportHeight); ERRCHECK();

  // Change to the projection matrix and set up our ortho view
  glMatrixMode(GL_PROJECTION); ERRCHECK();
  glLoadIdentity(); ERRCHECK();
  gluOrtho2D(0, viewportWidth, 0, viewportHeight); ERRCHECK();

  // Set up modelview for 2D integer coordinates
  glMatrixMode(GL_MODELVIEW); ERRCHECK();
  glLoadIdentity(); ERRCHECK();
  glTranslatef(0.375f, viewportHeight + 0.375f, 0.0f); ERRCHECK();
  glScalef(1.0f, -1.0f, 0.001f); ERRCHECK(); // Make the positive Z-axis point "out" from the view (e.g images at depth 4 will be higher than those at depth 0), and swap the Y axis

  // Clear the color and depth buffers.
  glClear(GL_COLOR_BUFFER_BIT); ERRCHECK();

  // Enable textures and blending
  glEnable(GL_TEXTURE_2D); ERRCHECK();
  glEnable(GL_BLEND); ERRCHECK();
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ERRCHECK();

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ERRCHECK();
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ERRCHECK();

  // Save the current matrix
  glPushMatrix(); ERRCHECK();

  // Scale as necessary
  glScalef(canvas->scale[0], canvas->scale[1], 1.0f); ERRCHECK();
  bool scaledCanvas = !(canvas->scale[0] == 1.0f && canvas->scale[1] == 1.0f);

  // Specify vertex and tex coord buffers
  glVertexPointer(3, GL_FLOAT, 0, vertex_buffer); ERRCHECK();
  glEnableClientState(GL_VERTEX_ARRAY); ERRCHECK();
  glTexCoordPointer(2, GL_FLOAT, 0, texcoord_buffer); ERRCHECK();
  glEnableClientState(GL_TEXTURE_COORD_ARRAY); ERRCHECK();

  SDL_Rect viewRect;
  viewRect.x = canvas->origin.x;
  viewRect.y = canvas->origin.y;
  viewRect.w = viewportWidth;
  viewRect.h = viewportHeight;

  float depth = 0.0f;
  for (Splat_Layer *layer = canvas->layers; layer != NULL; layer = layer->next) {
    for (Splat_Instance *instance = layer->instances; instance != NULL; instance = instance->next) {
      //TODO do this once per texture
      // Bind our texture
      glBindTexture(GL_TEXTURE_2D, instance->texture); ERRCHECK();

      if ((instance->flags & SPLAT_RELATIVE) != 0 && !SDL_HasIntersection(&instance->rect, &viewRect)) {
        continue;
      }

      // Save the current matrix
      glPushMatrix(); ERRCHECK();

      // If relative, translate to the active canvas' current location
      if (instance->flags & SPLAT_RELATIVE) {
        glTranslatef(-canvas->origin.x, -canvas->origin.y, 0.0f); ERRCHECK();
      }

      // Translate to the images current location
      glTranslatef(instance->rect.x, instance->rect.y, 0.0f); ERRCHECK();

      // Set color for rendering
      glColor4ub(instance->color.r, instance->color.g, instance->color.b, instance->color.a); ERRCHECK();

      // Scale the render rect
      scaledRect.x = instance->rect.x;
      scaledRect.y = instance->rect.y;
      scaledRect.w = instance->rect.w * instance->scale[0];
      scaledRect.h = instance->rect.h * instance->scale[1];

      // Handle rotation
      if (instance->flags & MASK_IMAGEMOD) {
        const float w2 = ((float) scaledRect.w) / 2.0f;
        const float h2 = ((float) scaledRect.h) / 2.0f;

        glTranslatef(w2, h2, 0.0f); ERRCHECK();

        if (instance->flags & SPLAT_MIRROR_DIAG) {
          glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); ERRCHECK();
          if ((instance->flags & SPLAT_MIRROR_X)) {
            glScalef(1.0f, -1.0f, 1.0f); ERRCHECK();
          }
          if ((instance->flags & SPLAT_MIRROR_Y) == 0) {
            glScalef(-1.0f, 1.0f, 1.0f); ERRCHECK();
          }
        } else {
          if (instance->flags & SPLAT_MIRROR_X) {
            glScalef(-1.0f, 1.0f, 1.0f); ERRCHECK();
          }
          if (instance->flags & SPLAT_MIRROR_Y) {
             glScalef(1.0f, -1.0f, 1.0f); ERRCHECK();
          }
        }
        if (instance->flags & SPLAT_ROTATE) {
          glRotatef(instance->angle, 0.0f, 0.0f, 1.0f); ERRCHECK();
        }

        glTranslatef(-w2, -h2, 0.0f); ERRCHECK();
      }

      // Handle scissoring
      if (!SDL_RectEmpty(&instance->clip)) {
        // Enable scissoring
        glEnable(GL_SCISSOR_TEST); ERRCHECK();

        // Snip, snip, snip...
        if (scaledCanvas) {
          glScissor(instance->clip.x * canvas->scale[0], winheight - ((instance->clip.y + instance->clip.h) * canvas->scale[1]), instance->clip.w * canvas->scale[0], instance->clip.h * canvas->scale[1]); ERRCHECK();
        } else {
          glScissor(instance->clip.x, winheight - (instance->clip.y + instance->clip.h), instance->clip.w, instance->clip.h); ERRCHECK();
        }
      } else {
        // Disable scissoring
        glDisable(GL_SCISSOR_TEST); ERRCHECK();
      }

      // Prepare to render triangles

      // First triangle
      //glTexCoord2f(instance->s1, instance->t2);
      texcoord_buffer[0] = instance->s1;
      texcoord_buffer[1] = instance->t2;
      //glVertex3f(0.0f, scaled_rect.h, depth);
      vertex_buffer[0] = 0.0f;
      vertex_buffer[1] = scaledRect.h;
      vertex_buffer[2] = depth;

      //glTexCoord2f(instance->s1, instance->t1);
      texcoord_buffer[2] = instance->s1;
      texcoord_buffer[3] = instance->t1;
      //glVertex3f(0.0f, 0.0f, depth);
      vertex_buffer[3] = 0.0f;
      vertex_buffer[4] = 0.0f;
      vertex_buffer[5] = depth;

      //glTexCoord2f(instance->s2, instance->t1);
      texcoord_buffer[4] = instance->s2;
      texcoord_buffer[5] = instance->t1;
      //glVertex3f(scaled_rect.w, 0.0f, depth);
      vertex_buffer[6] = scaledRect.w;
      vertex_buffer[7] = 0.0f;
      vertex_buffer[8] = depth;

      // Second triangle
      //glTexCoord2f(instance->s2, instance->t2);
      texcoord_buffer[6] = instance->s2;
      texcoord_buffer[7] = instance->t2;
      //glVertex3f(scaled_rect.w, scaled_rect.h, depth);
      vertex_buffer[9] = scaledRect.w;
      vertex_buffer[10] = scaledRect.h;
      vertex_buffer[11] = depth;

      //glTexCoord2f(instance->s1, instance->t2);
      texcoord_buffer[8] = instance->s1;
      texcoord_buffer[9] = instance->t2;
      //glVertex3f(0.0f, scaled_rect.h, depth);
      vertex_buffer[12] = 0.0f;
      vertex_buffer[13] = scaledRect.h;
      vertex_buffer[14] = depth;

      //glTexCoord2f(instance->s2, instance->t1);
      texcoord_buffer[10] = instance->s2;
      texcoord_buffer[11] = instance->t1;
      //glVertex3f(scaled_rect.w, 0.0f, depth);
      vertex_buffer[15] = scaledRect.w;
      vertex_buffer[16] = 0.0f;
      vertex_buffer[17] = depth;

      // Finished with our triangles
      glDrawArrays(GL_TRIANGLES, 0, 6); ERRCHECK();

      // Finished with our triangles
      glPopMatrix(); ERRCHECK();
    }

    depth += 1.0f;
  }

  // Disable scissoring
  glDisable(GL_SCISSOR_TEST); ERRCHECK();

  uint32_t time = SDL_GetTicks();

  // Draw rects
  if (canvas->rects) {
    glDisable(GL_TEXTURE_2D); ERRCHECK();
    glEnableClientState(GL_VERTEX_ARRAY); ERRCHECK();
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); ERRCHECK();
    glVertexPointer(2, GL_FLOAT, 0, &vertex_buffer); ERRCHECK();

    for (Splat_Rect *prev = NULL, *curr = canvas->rects; curr != NULL; /**/) {
      glColor4ub(curr->color.r, curr->color.g, curr->color.b, curr->color.a); ERRCHECK();

      // Save the current matrix
      glPushMatrix(); ERRCHECK();

      if (!curr->relative) {
        // Translate to the active canvas's current location
        glTranslatef(-canvas->origin.x, -canvas->origin.y, 0.0f); ERRCHECK();
      }

      glLineWidth(curr->width); ERRCHECK();

      // Prepare to render rects
      if (curr->fill) {
        // First triangle
        vertex_buffer[0] = curr->x1;
        vertex_buffer[1] = curr->y1;

        vertex_buffer[2] = curr->x2;
        vertex_buffer[3] = curr->y1;

        vertex_buffer[4] = curr->x1;
        vertex_buffer[5] = curr->y2;

        // Second triangle
        vertex_buffer[6] = curr->x2;
        vertex_buffer[7] = curr->y2;

        vertex_buffer[8] = curr->y1;
        vertex_buffer[9] = curr->y2;

        vertex_buffer[10] = curr->x2;
        vertex_buffer[11] = curr->x1;

        // Finished with our triangles
        glDrawArrays(GL_TRIANGLES, 0, 6); ERRCHECK();
      } else {
        vertex_buffer[0] = curr->x1;
        vertex_buffer[1] = curr->y1;

        vertex_buffer[2] = curr->x2;
        vertex_buffer[3] = curr->y1;

        vertex_buffer[4] = curr->x2;
        vertex_buffer[5] = curr->y2;

        vertex_buffer[6] = curr->x1;
        vertex_buffer[7] = curr->y2;

        // Finished with our lines
        glDrawArrays(GL_LINE_LOOP, 0, 4); ERRCHECK();
      }

      // Restore the old matrix
      glPopMatrix(); ERRCHECK();

      // Expire old rects
      if (time >= curr->ttl) {
        if (prev) {
          prev->next = curr->next;
        } else {
          canvas->rects = curr->next;
        }
        
        Splat_Rect *old = curr;
        curr = curr->next;
        free(old);
      } else {
        prev = curr;
        curr = curr->next;
      }
    }
  }

  if (canvas->lines) {
    glDisable(GL_TEXTURE_2D); ERRCHECK();
    glEnableClientState(GL_VERTEX_ARRAY); ERRCHECK();
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); ERRCHECK();
    for (Splat_Line *prev = NULL, *curr = canvas->lines; curr != NULL; /**/) {
      glColor4ub(curr->color.r, curr->color.g, curr->color.b, curr->color.a); ERRCHECK();

      if (!curr->relative) {
        // Translate to the active canvas's current location
        glTranslatef(-canvas->origin.x, -canvas->origin.y, 0.0f); ERRCHECK();
      }

      glLineWidth(curr->width); ERRCHECK();

      glVertexPointer(2, GL_FLOAT, 0, &curr->start.x); ERRCHECK();

      // Finished with our triangles
      glDrawArrays(GL_LINES, 0, 2); ERRCHECK();

      // Expire old lines
      if (time >= curr->ttl) {
        if (prev) {
          prev->next = curr->next;
        } else {
          canvas->lines = curr->next;
        }

        Splat_Line *old = curr;
        curr = curr->next;
        free(old);
      } else {
        prev = curr;
        curr = curr->next;
      }
    }
  }

  // Restore original, non-scaled matrix
  glPopMatrix(); ERRCHECK();

  // Render to the screen
  glBindFramebuffer(GL_FRAMEBUFFER, 0); ERRCHECK();
  glViewport(0, 0, winwidth, winheight); ERRCHECK(); // Render on the whole framebuffer, complete from the lower left corner to the upper right

  glDisable(GL_BLEND); ERRCHECK();
  glEnable(GL_TEXTURE_2D); ERRCHECK();

  // Specify vertex and tex coord buffers
  glVertexPointer(3, GL_FLOAT, 0, vertex_buffer); ERRCHECK();
  glEnableClientState(GL_VERTEX_ARRAY); ERRCHECK();
  glTexCoordPointer(2, GL_FLOAT, 0, texcoord_buffer); ERRCHECK();
  glEnableClientState(GL_TEXTURE_COORD_ARRAY); ERRCHECK();

  // Change to the projection matrix and set up our ortho view
  glMatrixMode(GL_PROJECTION); ERRCHECK();
  glLoadIdentity(); ERRCHECK();
  gluOrtho2D(0, winwidth, 0, winheight); ERRCHECK();

  // Set up modelview for 2D integer coordinates
  glMatrixMode(GL_MODELVIEW); ERRCHECK();
  glLoadIdentity(); ERRCHECK();
  glTranslatef(0.375f, winheight + 0.375f, 0.0f); ERRCHECK();
  glScalef(1.0f, -1.0f, 0.001f); ERRCHECK(); // Make the positive Z-axis point "out" from the view (e.g images at depth 4 will be higher than those at depth 0), and swap the Y axis

  glBindTexture(GL_TEXTURE_2D, frameTexture); ERRCHECK();
  glColor4ub(255, 255, 255, 255); ERRCHECK();

#ifdef SPLAT_SHADERS_EXPERIMENTAL
  glUseProgram(shaderProgram); ERRCHECK();

  if (shaderProgram) {
    float size[2];
    GLint uniform;

    size[0] = viewportWidth;
    size[1] = viewportHeight;
    uniform = glGetUniformLocation(shaderProgram, "rubyInputSize"); ERRCHECK();
    glUniform2fv(uniform, 1, size); ERRCHECK();

    uniform = glGetUniformLocation(shaderProgram, "rubyTextureSize"); ERRCHECK();
    glUniform2fv(uniform, 1, size); ERRCHECK();

    size[0] = winwidth;
    size[1] = winheight;
    uniform = glGetUniformLocation(shaderProgram, "rubyOutputSize"); ERRCHECK();
    glUniform2fv(uniform, 1, size); ERRCHECK();
  }
#endif // SPLAT_SHADERS_EXPERIMENTAL

  // First triangle
  //glTexCoord2f(handle->s1, handle->t2);
  texcoord_buffer[0] = 0.0f;
  texcoord_buffer[1] = 0.0f;
  //glVertex3f(0.0f, scaled_rect.h, handle->depth);
  vertex_buffer[0] = 0.0f;
  vertex_buffer[1] = (float) winheight;
  vertex_buffer[2] = 0.0f;

  //glTexCoord2f(handle->s1, handle->t1);
  texcoord_buffer[2] = 0.0f;
  texcoord_buffer[3] = 1.0f;
  //glVertex3f(0.0f, 0.0f, handle->depth);
  vertex_buffer[3] = 0.0f;
  vertex_buffer[4] = 0.0f;
  vertex_buffer[5] = 0.0f;

  //glTexCoord2f(handle->s2, handle->t1);
  texcoord_buffer[4] = 1.0f;
  texcoord_buffer[5] = 1.0f;
  //glVertex3f(scaled_rect.w, 0.0f, handle->depth);
  vertex_buffer[6] = (float) winwidth;
  vertex_buffer[7] = 0.0f;
  vertex_buffer[8] = 0.0f;

  // Second triangle
  //glTexCoord2f(handle->s2, handle->t2);
  texcoord_buffer[6] = 1.0f;
  texcoord_buffer[7] = 0.0f;
  //glVertex3f(scaled_rect.w, scaled_rect.h, handle->depth);
  vertex_buffer[9] = (float) winwidth;
  vertex_buffer[10] = (float) winheight;
  vertex_buffer[11] = 0.0f;

  //glTexCoord2f(handle->s1, handle->t2);
  texcoord_buffer[8] = 0.0f;
  texcoord_buffer[9] = 0.0f;
  //glVertex3f(0.0f, scaled_rect.h, handle->depth);
  vertex_buffer[12] = 0.0f;
  vertex_buffer[13] = (float) winheight;
  vertex_buffer[14] = 0.0f;

  //glTexCoord2f(handle->s2, handle->t1);
  texcoord_buffer[10] = 1.0f;
  texcoord_buffer[11] = 1.0f;
  //glVertex3f(scaled_rect.w, 0.0f, handle->depth);
  vertex_buffer[15] = (float) winwidth;
  vertex_buffer[16] = 0.0f;
  vertex_buffer[17] = 0.0f;

  // Finished with our triangles
  glDrawArrays(GL_TRIANGLES, 0, 6); ERRCHECK();

#ifdef SPLAT_SHADERS_EXPERIMENTAL
  glUseProgram(0); ERRCHECK();
#endif // SPLAT_SHADERS_EXPERIMENTAL

  // Finish rendering by swap buffers
  SDL_GL_SwapWindow(window);

#if ENABLE_FPS_LOG
  fps_lastframe = fps_frametime;
  fps_frametime = SDL_GetTicks();
  Uint32 current_fps = 1.0f / (((float) (fps_frametime - fps_lastframe)) / 1000.0f);
  fps_max = current_fps > fps_max ? current_fps : fps_max;
  fps_min = current_fps < fps_min ? current_fps : fps_min;
  fps_times[fps_index] = current_fps;
  fps_index++;
  if (fps_index > MAX_FPS_INDEX) {
    fps_index = 0;
  }

  if (fps_frametime > fps_next_update) {
    Uint32 i, total = 0, fps;
    for (i = 0; i < MAX_FPS_INDEX; i++) {
      total += fps_times[i];
    }
    fps = total / MAX_FPS_INDEX;
    printf("FPS:  %d (%d to %d)\n", fps, fps_min, fps_max);

    // Reset min/max and set next print time
    fps_min = (Uint32) -1;
    fps_max = 0;
    fps_next_update = fps_frametime + 2000;
  }
#endif

  return 0;
}
SDL_bool
SDL_EnclosePoints(const SDL_Point * points, int count, const SDL_Rect * clip,
                  SDL_Rect * result)
{
    int minx = 0;
    int miny = 0;
    int maxx = 0;
    int maxy = 0;
    int x, y, i;

    if (!points) {
        SDL_InvalidParamError("points");
        return SDL_FALSE;
    }

    if (count < 1) {
        SDL_InvalidParamError("count");
        return SDL_FALSE;
    }

    if (clip) {
        SDL_bool added = SDL_FALSE;
        const int clip_minx = clip->x;
        const int clip_miny = clip->y;
        const int clip_maxx = clip->x+clip->w-1;
        const int clip_maxy = clip->y+clip->h-1;

        /* Special case for empty rectangle */
        if (SDL_RectEmpty(clip)) {
            return SDL_FALSE;
        }

        for (i = 0; i < count; ++i) {
            x = points[i].x;
            y = points[i].y;

            if (x < clip_minx || x > clip_maxx ||
                y < clip_miny || y > clip_maxy) {
                continue;
            }
            if (!added) {
                /* Special case: if no result was requested, we are done */
                if (result == NULL) {
                    return SDL_TRUE;
                }

                /* First point added */
                minx = maxx = x;
                miny = maxy = y;
                added = SDL_TRUE;
                continue;
            }
            if (x < minx) {
                minx = x;
            } else if (x > maxx) {
                maxx = x;
            }
            if (y < miny) {
                miny = y;
            } else if (y > maxy) {
                maxy = y;
            }
        }
        if (!added) {
            return SDL_FALSE;
        }
    } else {
        /* Special case: if no result was requested, we are done */
        if (result == NULL) {
            return SDL_TRUE;
        }

        /* No clipping, always add the first point */
        minx = maxx = points[0].x;
        miny = maxy = points[0].y;

        for (i = 1; i < count; ++i) {
            x = points[i].x;
            y = points[i].y;

            if (x < minx) {
                minx = x;
            } else if (x > maxx) {
                maxx = x;
            }
            if (y < miny) {
                miny = y;
            } else if (y > maxy) {
                maxy = y;
            }
        }
    }

    if (result) {
        result->x = minx;
        result->y = miny;
        result->w = (maxx-minx)+1;
        result->h = (maxy-miny)+1;
    }
    return SDL_TRUE;
}
SDL_bool
SDL_IntersectRectAndLine(const SDL_Rect * rect, int *X1, int *Y1, int *X2,
                         int *Y2)
{
    int x = 0;
    int y = 0;
    int x1, y1;
    int x2, y2;
    int rectx1;
    int recty1;
    int rectx2;
    int recty2;
    int outcode1, outcode2;

    if (!rect) {
        SDL_InvalidParamError("rect");
        return SDL_FALSE;
    }

    if (!X1) {
        SDL_InvalidParamError("X1");
        return SDL_FALSE;
    }

    if (!Y1) {
        SDL_InvalidParamError("Y1");
        return SDL_FALSE;
    }

    if (!X2) {
        SDL_InvalidParamError("X2");
        return SDL_FALSE;
    }

    if (!Y2) {
        SDL_InvalidParamError("Y2");
        return SDL_FALSE;
    }

    /* Special case for empty rect */
    if (SDL_RectEmpty(rect)) {
        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;
    }

    /* More complicated Cohen-Sutherland algorithm */
    outcode1 = ComputeOutCode(rect, x1, y1);
    outcode2 = ComputeOutCode(rect, x2, y2);
    while (outcode1 || outcode2) {
        if (outcode1 & outcode2) {
            return SDL_FALSE;
        }

        if (outcode1) {
            if (outcode1 & CODE_TOP) {
                y = recty1;
                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
            } else if (outcode1 & CODE_BOTTOM) {
                y = recty2;
                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
            } else if (outcode1 & CODE_LEFT) {
                x = rectx1;
                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
            } else if (outcode1 & CODE_RIGHT) {
                x = rectx2;
                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
            }
            x1 = x;
            y1 = y;
            outcode1 = ComputeOutCode(rect, x, y);
        } else {
            if (outcode2 & CODE_TOP) {
                y = recty1;
                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
            } else if (outcode2 & CODE_BOTTOM) {
                y = recty2;
                x = x1 + ((x2 - x1) * (y - y1)) / (y2 - y1);
            } else if (outcode2 & CODE_LEFT) {
                x = rectx1;
                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
            } else if (outcode2 & CODE_RIGHT) {
                x = rectx2;
                y = y1 + ((y2 - y1) * (x - x1)) / (x2 - x1);
            }
            x2 = x;
            y2 = y;
            outcode2 = ComputeOutCode(rect, x, y);
        }
    }
    *X1 = x1;
    *Y1 = y1;
    *X2 = x2;
    *Y2 = y2;
    return SDL_TRUE;
}