示例#1
0
void osint_render(void){
	int v;

    SDL_FillRect(screen, NULL, 0);

	for(v = 0; v < vector_draw_cnt; v++){
		Uint8 c = vectors_draw[v].color * 256 / VECTREX_COLORS;
        if (rotatexy)
		    aalineRGBA(screen,
				    (Sint16)(screenx - offx - vectors_draw[v].y0 / scl_factor),
				    (Sint16)(offy + vectors_draw[v].x0 / scl_factor),
				    (Sint16)(screenx - offx - vectors_draw[v].y1 / scl_factor),
				    (Sint16)(offy + vectors_draw[v].x1 / scl_factor),
				    c, c, c, 0xff);
        else
		    aalineRGBA(screen,
				    (Sint16)(offx + vectors_draw[v].x0 / scl_factor),
				    (Sint16)(offy + vectors_draw[v].y0 / scl_factor),
				    (Sint16)(offx + vectors_draw[v].x1 / scl_factor),
				    (Sint16)(offy + vectors_draw[v].y1 / scl_factor),
				    c, c, c, 0xff);
	}

    // Draw overlay image
    if (overlay != NULL)
    {
        SDL_Rect src, dst;
        dst.x = src.x = 0;  dst.y = src.y = 0;
        dst.w = src.w = (Uint16)screenx;  dst.h = src.h = (Uint16)screeny;
        SDL_BlitSurface(overlay, &src, screen, &dst);
    }

	SDL_Flip(screen);
}
示例#2
0
void Draw_Building(way* w, char* role, RGBA* color, char* type)
{
	Sint16 *vx, *vy;
	RGBA rgba;
	node_t* node = NULL;
	double longitude, latitude, minlat, maxlat, minlon, maxlon;
	int i, j, k, index, compteur, value_tag;
	static int policy = 0;
	
	maxlat = pBound->maxlat;
	minlat = pBound->minlat;
	maxlon = pBound->maxlon;
	minlon = pBound->minlon;
	
	vx = malloc(w->size_ref * sizeof(*vx));
	vy = malloc(w->size_ref * sizeof(*vy));
	compteur = 0;

	for(i = 0; i < w->size_ref; i++)
	{
		index = search_node_dicho(w->ref[i]);
	
		if(index == FAILURE)
			continue;
		
		node = pRoot->arrayNodes[index];
		
		longitude = node->longitude;
		latitude = node->latitude;

		vx[i] = (Sint16)(long_to_pix(longitude) * pMap->width * pMap->zoom);
		vy[i] = (Sint16)(lat_to_pix(latitude) * pMap->height * pMap->zoom);

		compteur++;
	}
	
	if(type != NULL && !strcmp(type, "barrier"))
	{
		for(i = 0; i < compteur - 1; i++)
     	 	aalineRGBA(pRenderer, vx[i], vy[i], vx[i+1], vy[i+1], color->r, color->g, color->b, color->a);
	}
	else
	{
		filledPolygonRGBA(pRenderer, vx, vy, compteur, color->r, color->g, color->b, color->a);
	
		if(role == NULL)
		{
			rgba = colorConverter(BARRIER_COLOR);
			for(i = 0; i < compteur - 1; i++)
		 	 	aalineRGBA(pRenderer, vx[i], vy[i], vx[i+1], vy[i+1], rgba.r, rgba.g, rgba.b, rgba.a);
		}
    }	 	
	free(vx);
	free(vy);
}
示例#3
0
文件: draw.c 项目: Eckankar/MosGame
// ML type: surface -> point -> point -> color -> bool -> unit
// Draws a line from wStart to wEnd of wColor on wScreen.
// If wAntialias is true, then the line will be antialiased.
EXTERNML value draw_draw_line(value wScreen, value wStart, value wEnd,
                                             value wColor, value wAntiAlias) {
    SDL_Surface *screen = (SDL_Surface *)Addr_val(wScreen);

    int startx = Long_val(Field(wStart, 0)),
        starty = Long_val(Field(wStart, 1)),
        endx   = Long_val(Field(wEnd, 0)),
        endy   = Long_val(Field(wEnd, 1)),
        colorr = Long_val(Field(wColor, 0)),
        colorg = Long_val(Field(wColor, 1)),
        colorb = Long_val(Field(wColor, 2)),
        colora = Tag_val(wColor) == RGBA ? Long_val(Field(wColor, 3)) : 255;

    if (colorr < 0 || colorr > 255 ||
        colorg < 0 || colorg > 255 ||
        colorb < 0 || colorb > 255 ||
        colora < 0 || colora > 255) {
        invalid_argument("Invalid color value given - each value must be between 0 and 255.");
    }

    if (Bool_val(wAntiAlias)) {
        aalineRGBA(screen, startx, starty, endx, endy, colorr, colorg, colorb, 255);
    } else {
        lineRGBA(screen, startx, starty, endx, endy, colorr, colorg, colorb, 255);
    }

    return Val_unit;
}
示例#4
0
void ConfigurationMenu::RenderMenu( SDL_Surface *surface )
{
	if ( visibility )
	{
		boxRGBA( surface, 800 / 2 - 250, 480 / 2 - 150, 800 / 2 + 250, 480 / 2 + 150, 0, 0, 0, 255 );
		rectangleRGBA( surface, 800 / 2 - 250, 480 / 2 - 150, 800 / 2 + 250, 480 / 2 + 150, 255, 255, 255, 255 );
		rectangleRGBA( surface, 800 / 2 - 250 + 1, 480 / 2 - 150 + 1, 800 / 2 + 250 - 1, 480 / 2 + 150 - 1, 255, 255, 255, 255 );
		aalineRGBA( surface, 800 / 2 - 225, 480 / 2 - 100, 800 / 2 + 225, 480 / 2 - 100, 255, 255, 255, 200 );
		dialogTitleLabel.Render( surface );
		traceLinesLabel.Render( surface );
		traceLineBodyLabel.Render( surface );
		traceLineSledLabel.Render( surface );
		traceLineHatLabel.Render( surface );
		traceLineHeadLabel.Render( surface );
		traceLineArmLabel.Render( surface );
		traceLineLegLabel.Render( surface );

		traceLineBodyRadio.Render( surface );
		traceLineSledRadio.Render( surface );
		traceLineHatRadio.Render( surface );
		traceLineHeadRadio.Render( surface );
		traceLineArmRadio.Render( surface );
		traceLineLegRadio.Render( surface );

		lineSnapLabel.Render( surface );
		lineSnapRadio.Render( surface );
	}
}
示例#5
0
void Bullet::Render()
{
	double strength = timeLeft/timeMax;
	int r = 255;
	int g = 255*strength;
	int b = 0;
	int a = 255*strength;
	aalineRGBA(Surface::Display, startX, startY, endX, endY, r, g, b, a);
};
static void drawDIPS(SDL_Surface* surf, state* s, unsigned char r, unsigned char g, unsigned char b, unsigned char a, double ratioPixels) {

    double distance = (fabs(s->xPosition2 - s->xPosition1) * ratioPixels) - 14;
    double inter = (distance) / (double)NB_SPRING;
    unsigned int i = 1;
    int sign = 1;

    double x1 = (screenWidth / 4.0) + (s->xPosition1 * ratioPixels);
    double y1 = screenHeight / 2.0;
    double x2 = x1 - (ratioPixels * sin(M_PIl - s->angularPosition1) * 2.0 * parameters[2]);
    double y2 = y1 + (ratioPixels * cos(M_PIl - s->angularPosition1) * 2.0 * parameters[2]);

    aalineRGBA(surf, x1, y1, x2, y2, r, g, b, a);
    filledCircleRGBA(surf, x1, y1, 5, r, g, b, a);
    filledCircleRGBA(surf, x2, y2, 5, r, g, b, a);
    rectangleRGBA(surf, x1 - 7, y1 - 7, x1 + 7, y1 + 7, r, g, b, a);

    x1 = (screenWidth / 4.0) + (s->xPosition2 * ratioPixels);
    y1 = (screenHeight / 2.0);
    x2 = x1 - (ratioPixels * sin(M_PIl - s->angularPosition2) * 2.0 * parameters[3]);
    y2 = y1 + (ratioPixels * cos(M_PIl - s->angularPosition2) * 2.0 * parameters[3]);

    aalineRGBA(surf, x1, y1, x2, y2, r, g, b, a);
    filledCircleRGBA(surf, x1, y1, 5, r, g, b, a);
    filledCircleRGBA(surf, x2, y2, 5, r, g, b, a);
    rectangleRGBA(surf, x1 - 7, y1 - 7, x1 + 7, y1 + 7, r, g, b, a);

    x1 = (screenWidth / 4.0) + (s->xPosition1 * ratioPixels) + 7;
    y1 = (screenHeight / 2.0);
    for(; i <= NB_SPRING; i++) {
        if(sign > 0)
            sign = -7;
        else
            sign = 7;
        aalineRGBA(surf, x1+((i-1)*inter), y1+sign, x1+(i*inter), y1-sign, r, g, b, a);
    }

}
示例#7
0
CAMLprim value ml_aalineRGBA(value dst,value p1,value p2, value col,value alpha)
{
  SDL_Surface *sur= SDL_SURFACE(dst);
  SDL_Rect rect1,rect2;
  SDL_Color c;
  int r;

  SDLRect_of_value(&rect1,p1);
  SDLRect_of_value(&rect2,p2);
  SDLColor_of_value(&c,col);
  r=aalineRGBA(sur,rect1.x,rect1.y,rect2.x,rect2.y,c.r,c.g,c.b, Int_val(alpha));

  return Val_bool(r);
}
void sequential_soo_drawingProcedure(SDL_Surface* screen, int screenWidth, int screenHeight,  void* instance) {

    #if NUMBER_OF_DIMENSIONS_OF_ACTION == 1
    sequential_soo_instance* theInstance = (sequential_soo_instance*)instance;
    if(instance != NULL) {
        unsigned int H = theInstance->H;
        unsigned int i = 0;

        unsigned int heightShift = (H == 1) ? 0 : (screenHeight-20)/(H-1);

        for(; i < H; i++) {
            soo* sooInstance = theInstance->instances[i];
            depth* crtDepth = sooInstance->list;
            while(crtDepth != NULL) {
                leaf* crtLeaf = crtDepth->list;
                /*double shift = (1.0/(2.0*pow(3.0,crtDepth->depth))) * (WIDTH_TREE - 20);*/
                double y = 10 + (i * heightShift);
                aalineRGBA(screen, (screenWidth / 2.0) + 10, y, screenWidth - 10, y, 0, 0, 0, 255);
                while(crtLeaf != NULL) {
                    double x = (screenWidth / 2.0) + 10 + (crtLeaf->centerPosition[0]*((screenWidth / 2.0) - 20));
                    aalineRGBA(screen, x, y + 2, x, y - 2, 0, 0, 0, 255);
                    /*aalineRGBA(screen, x - shift, y - 4, x - shift, y + 4, 0, 0, 0, 255);
                    aalineRGBA(screen, x + shift, y - 4, x + shift, y + 4, 0, 0, 0, 255);*/
                    crtLeaf = crtLeaf->next;
                }
                crtDepth = crtDepth->next;
            }
        }
    }
    #else
    (void)screen;
    (void)screenWidth;
    (void)screenHeight;
    (void)instance;
    #endif

}
示例#9
0
void Draw_Natural(way* w, char* role, RGBA* color, char* type)
{
	Sint16 *vx, *vy;
	node_t* node = NULL;
	double longitude, latitude, minlat, maxlat, minlon, maxlon;
	int i, index, compteur = 0;
	
	maxlat = pBound->maxlat;
	minlat = pBound->minlat;
	maxlon = pBound->maxlon;
	minlon = pBound->minlon;
	
	vx = malloc(w->size_ref * sizeof(*vx));
	vy = malloc(w->size_ref * sizeof(*vy));

	for(i = 0; i < w->size_ref; i++)
	{
		index = search_node_dicho(w->ref[i]);
	
		if(index == FAILURE)
			continue;
		
		node = pRoot->arrayNodes[index];
		
		longitude = node->longitude;
		latitude = node->latitude;

		vx[i] = (Sint16)(long_to_pix(longitude) * pMap->width * pMap->zoom);
		vy[i] = (Sint16)(lat_to_pix(latitude) * pMap->height * pMap->zoom);

		compteur++;
	}

	if(type != NULL)
		if(!strcmp(type, "cliff"))
			for(i = 0; i < compteur - 1; i++)
				thickLineRGBA(pRenderer, vx[i], vy[i], vx[i + 1], vy[i + 1], CLIFF_LENGTH, color->r, color->g, color->b, color->a);
		else
			if(!strcmp(type, "coastline"))
				for(i = 0; i < compteur - 1; i++)
					aalineRGBA(pRenderer, vx[i], vy[i], vx[i + 1], vy[i + 1], color->r, color->g, color->b, color->a);
	else
		filledPolygonRGBA(pRenderer, vx, vy, compteur, color->r, color->g, color->b, color->a);
		
	free(vx);
	free(vy);
}
示例#10
0
void osint_render(void){
	SDL_FillRect(screen, NULL, 0);

	int v;
	for(v = 0; v < vector_draw_cnt; v++){
		Uint8 c = vectors_draw[v].color * 256 / VECTREX_COLORS;
		aalineRGBA(screen,
				offx + vectors_draw[v].x0 / scl_factor,
				offy + vectors_draw[v].y0 / scl_factor,
				offx + vectors_draw[v].x1 / scl_factor,
				offy + vectors_draw[v].y1 / scl_factor,
				c, c, c, 0xff);
	}
	if(overlay){
		SDL_Rect dest_rect = {offx, offy, 0, 0};
		SDL_BlitSurface(overlay, NULL, screen, &dest_rect);
	}
	SDL_Flip(screen);
}
static void drawPendulum(state* s, unsigned char r, unsigned char g, unsigned char b, unsigned char a, double ratioPixels) {
	
	double x1 = (screenWidth / 4.0) + (s->xPosition * ratioPixels);
	
	double y1 = screenHeight / 2.0;
	
	double x2 = x1 - (ratioPixels * sin(M_PIl - s->angularPosition) * 2.0 * parameters[2]);
	
	double y2 = y1 + (ratioPixels * cos(M_PIl - s->angularPosition) * 2.0 * parameters[2]);
	
	aalineRGBA(screen, x1, y1, x2, y2, r, g, b, a);
	
	filledCircleRGBA(screen, x1, y1, 3, r, g, b, a);
	
	x2 = x1 - (int)(ratioPixels * sin(M_PIl - s->angularPosition) * ((2.0 * parameters[2]) + (3.0/ratioPixels)));
	
	y2 = y1 + (int)(ratioPixels * cos(M_PIl - s->angularPosition) * ((2.0 * parameters[2]) + (3.0/ratioPixels)));
	
	filledCircleRGBA(screen, x2, y2, 3, r, g, b, a);
	
	rectangleRGBA(screen, x1 - 10, y1 - 5, x1 + 10, y1 + 5, r, g, b, a);

}
示例#12
0
void Renderer::Line(Point p, Point p2, Uint8 rr, Uint8 gg, Uint8 bb, Uint8 aa){
    aalineRGBA(_renderer, p.x(), p.y(), p2.x(), p2.y(), rr, gg, bb, aa);
}
示例#13
0
/* Calls to commands created via [sdl.surface] are implemented by this
 * C command. */
static int JimSdlHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    JimSdlSurface *jss = Jim_CmdPrivData(interp);
    int option;
    static const char * const options[] = {
        "free", "flip", "pixel", "rectangle", "box", "line", "aaline",
        "circle", "aacircle", "fcircle", NULL
    };
    enum
    { OPT_FREE, OPT_FLIP, OPT_PIXEL, OPT_RECTANGLE, OPT_BOX, OPT_LINE,
        OPT_AALINE, OPT_CIRCLE, OPT_AACIRCLE, OPT_FCIRCLE
    };

    if (argc < 2) {
        Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
        return JIM_ERR;
    }
    if (Jim_GetEnum(interp, argv[1], options, &option, "SDL surface method", JIM_ERRMSG) != JIM_OK)
        return JIM_ERR;
    if (option == OPT_PIXEL) {
        /* PIXEL */
        long x, y, red, green, blue, alpha = 255;

        if (argc != 7 && argc != 8) {
            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
            return JIM_ERR;
        }
        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
            Jim_GetLong(interp, argv[4], &red) != JIM_OK ||
            Jim_GetLong(interp, argv[5], &green) != JIM_OK ||
            Jim_GetLong(interp, argv[6], &blue) != JIM_OK) {
            return JIM_ERR;
        }
        if (argc == 8 && Jim_GetLong(interp, argv[7], &alpha) != JIM_OK)
            return JIM_ERR;
        pixelRGBA(jss->screen, x, y, red, green, blue, alpha);
        return JIM_OK;
    }
    else if (option == OPT_RECTANGLE || option == OPT_BOX ||
        option == OPT_LINE || option == OPT_AALINE) {
        /* RECTANGLE, BOX, LINE, AALINE */
        long x1, y1, x2, y2, red, green, blue, alpha = 255;

        if (argc != 9 && argc != 10) {
            Jim_WrongNumArgs(interp, 2, argv, "x y red green blue ?alpha?");
            return JIM_ERR;
        }
        if (Jim_GetLong(interp, argv[2], &x1) != JIM_OK ||
            Jim_GetLong(interp, argv[3], &y1) != JIM_OK ||
            Jim_GetLong(interp, argv[4], &x2) != JIM_OK ||
            Jim_GetLong(interp, argv[5], &y2) != JIM_OK ||
            Jim_GetLong(interp, argv[6], &red) != JIM_OK ||
            Jim_GetLong(interp, argv[7], &green) != JIM_OK ||
            Jim_GetLong(interp, argv[8], &blue) != JIM_OK) {
            return JIM_ERR;
        }
        if (argc == 10 && Jim_GetLong(interp, argv[9], &alpha) != JIM_OK)
            return JIM_ERR;
        switch (option) {
            case OPT_RECTANGLE:
                rectangleRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
                break;
            case OPT_BOX:
                boxRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
                break;
            case OPT_LINE:
                lineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
                break;
            case OPT_AALINE:
                aalineRGBA(jss->screen, x1, y1, x2, y2, red, green, blue, alpha);
                break;
        }
        return JIM_OK;
    }
    else if (option == OPT_CIRCLE || option == OPT_AACIRCLE || option == OPT_FCIRCLE) {
        /* CIRCLE, AACIRCLE, FCIRCLE */
        long x, y, radius, red, green, blue, alpha = 255;

        if (argc != 8 && argc != 9) {
            Jim_WrongNumArgs(interp, 2, argv, "x y radius red green blue ?alpha?");
            return JIM_ERR;
        }
        if (Jim_GetLong(interp, argv[2], &x) != JIM_OK ||
            Jim_GetLong(interp, argv[3], &y) != JIM_OK ||
            Jim_GetLong(interp, argv[4], &radius) != JIM_OK ||
            Jim_GetLong(interp, argv[5], &red) != JIM_OK ||
            Jim_GetLong(interp, argv[6], &green) != JIM_OK ||
            Jim_GetLong(interp, argv[7], &blue) != JIM_OK) {
            return JIM_ERR;
        }
        if (argc == 9 && Jim_GetLong(interp, argv[8], &alpha) != JIM_OK)
            return JIM_ERR;
        switch (option) {
            case OPT_CIRCLE:
                circleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
                break;
            case OPT_AACIRCLE:
                aacircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
                break;
            case OPT_FCIRCLE:
                filledCircleRGBA(jss->screen, x, y, radius, red, green, blue, alpha);
                break;
        }
        return JIM_OK;
    }
    else if (option == OPT_FREE) {
        /* FREE */
        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        Jim_DeleteCommand(interp, Jim_String(argv[0]));
        return JIM_OK;
    }
    else if (option == OPT_FLIP) {
        /* FLIP */
        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        SDL_Flip(jss->screen);
        return JIM_OK;
    }
    return JIM_OK;
}
示例#14
0
void start_freehand_drawing(void)
{
    FreehandGeometry geometry;

    int oldmouse_x, oldmouse_y;
    int offsetx = cxoff + canvas->get_absxpos();
    int offsety = cyoff + canvas->get_absypos();
    //SDL_Surface *sur = canvas->get_image(canvas->get_active_image_n());

    SDL_Surface *behind = SDLGui::createSurface(screen->w, screen->h);
    blit(screen, behind, 0, 0, 0, 0, screen->w, screen->h);
                
    SDL_Event event;
    oldmouse_x = mouse.x;
    oldmouse_y = mouse.y;
    
    unsigned processed = 0;
    StlStroke& stroke = *(geometry.currStroke);


    while(mouse.b == SDL_BUTTON_LEFT)
    {
        // Update the screen with the last round of geometry read from the 
        // event queue.
        SDL_PumpEvents();
        for (unsigned i = processed; i < stroke.size(); i++)
        {
            if (i == 0)
            {
                //putpixel(screen, stroke[i].x + offsetx,
                //        stroke[i].y + offsety, BLACK);
                continue;
            }

            aalineRGBA(screen, (int) stroke[i - 1].x + offsetx,
                    (int) stroke[i - 1].y + offsety, 
                    (int) stroke[i].x + offsetx,
                    (int) stroke[i].y + offsety, 0, 0, 0, 128);
            processed++;
        }
        SDL_PumpEvents();
        SDL_Flip(screen);

        // Wait for a new event.
        SDL_WaitEvent(&event);
        // Process all events in the queue.
        do
        {
            switch (event.type)
            {
                case SDL_MOUSEMOTION:
                    mouse.x = event.motion.x;
                    mouse.y = event.motion.y;
                    if ((oldmouse_x != mouse.x) || (oldmouse_y != mouse.y))
                    {
                        geometry.addPoint(mouse.x - offsetx, mouse.y - offsety);
                        oldmouse_x = mouse.x;
                        oldmouse_y = mouse.y;
                    }
                    break;
                case SDL_MOUSEBUTTONUP:
                    mouse.b = 0;
                    break;
                case SDL_QUIT:
                    mouse.kill_sig = 1;
                    break;
                default:
                    break;
            }
        }
        while ((mouse.b != 0) && SDL_PollEvent(&event));
    }

    //qDebug("Points: %d", (int) points.size());
    SDL_FastBlit(behind, screen, 0, 0, 0, 0, screen->w, screen->h);
    SDL_FreeSurface(behind);
   
    if (lastFreehand == NULL)
    {
        strokeTimerID = SDL_AddTimer(strokeTimeout, freehand_timer_callback, 
                NULL);
        
        lastFreehand = new Freehand(geometry);
        // Visibility graph stuff:
        visalgo->obj_add(lastFreehand);

        //QT canvas_deselect_shapes();
    }
    else
    {
        SDL_RemoveTimer(strokeTimerID);
        strokeTimerID = SDL_AddTimer(strokeTimeout, freehand_timer_callback, 
                NULL);
        lastFreehand->addStroke(geometry);
        visalgo->obj_resize(lastFreehand);
    }
#if defined(__APPLE__)
    // After using carbon for mouse input, we need to resync the sdl mouse.
    GUI_DummyMouseEvent();
    while(SDL_PollEvent(&event));
        // noop;
    reset_mouse();
    mouse.bstate = mouse.b = 0;
#endif
    repaint_canvas();
}
示例#15
0
void Viewer::mainloop() {
    Timer timer;
    Timer total;

    if (m_print_perf)
        fmt::print("Rendering frame {}\n", m_frame);
    m_scene_changed = false;
    m_frame++;

    int current_time = SDL_GetTicks();
    double dt = (current_time - m_last_frame_time) / 1000.0;
    m_last_frame_time = current_time;
    auto fps = 1. / dt;

    // Input
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
        if (e.type == SDL_QUIT) {
            shutdown();
        }

        if (e.type == SDL_KEYDOWN) {
            if (e.key.keysym.sym == SDLK_ESCAPE) {
                shutdown();
            }
            if (e.key.keysym.sym == SDLK_b) {
                m_debug = !m_debug;
            }
            if (e.key.keysym.sym == SDLK_n) {
                m_print_perf = !m_print_perf;
            }
            if (e.key.keysym.sym == SDLK_1) {
                m_stride_x = 1;
                m_stride_y = 1;
                m_scene_changed = true;
            }
            if (e.key.keysym.sym == SDLK_2) {
                m_stride_x = 2;
                m_stride_y = 2;
                m_scene_changed = true;
            }
            if (e.key.keysym.sym == SDLK_3) {
                m_stride_x = 4;
                m_stride_y = 4;
                m_scene_changed = true;
            }
        }

        if (e.type == SDL_MOUSEBUTTONDOWN) {
            if (e.button.button == SDL_BUTTON_RIGHT) {
                if (m_look_mode) {
                    m_look_mode = false;
                    SDL_SetRelativeMouseMode(SDL_FALSE);
                } else if (!m_look_mode) {
                    m_look_mode = true;
                    SDL_SetRelativeMouseMode(SDL_TRUE);
                }
            }
        }
    }

    float cam_speed = .8f * dt;

    // Left/right
    const uint8_t *keystates = SDL_GetKeyboardState(0);
    if (keystates[SDL_SCANCODE_A]) {
        m_scene_changed = true;
        Camera::set_pos(m_camera, Camera::pos(m_camera) - Camera::right(m_camera) * cam_speed);
    } else if (keystates[SDL_SCANCODE_D]) {
        Camera::set_pos(m_camera, Camera::pos(m_camera) + Camera::right(m_camera) * cam_speed);
        m_scene_changed = true;
    }

    // Up/down
    if (keystates[SDL_SCANCODE_SPACE]) {
        m_scene_changed = true;
        Camera::set_pos(m_camera, Camera::pos(m_camera) + glm::vec3{0, 1, 0} * cam_speed);
    } else if (keystates[SDL_SCANCODE_LCTRL]) {
        m_scene_changed = true;
        Camera::set_pos(m_camera, Camera::pos(m_camera) - glm::vec3{0, 1, 0} * cam_speed);
    }

    // Roll
    if (keystates[SDL_SCANCODE_Q]) {
        m_scene_changed = true;
        Camera::set_world_up(m_camera, glm::rotateZ(Camera::up(m_camera), 0.1f));
    } else if (keystates[SDL_SCANCODE_E]) {
        m_scene_changed = true;
        Camera::set_world_up(m_camera, glm::rotateZ(Camera::up(m_camera), -0.1f));
    }

    // Front/back
    if (keystates[SDL_SCANCODE_W]) {
        m_scene_changed = true;
        Camera::set_pos(m_camera, Camera::pos(m_camera) + Camera::dir(m_camera) * cam_speed);
    } else if (keystates[SDL_SCANCODE_S]) {
        m_scene_changed = true;
        Camera::set_pos(m_camera, Camera::pos(m_camera) - Camera::dir(m_camera) * cam_speed);
    }

    // Rendering here
    int width;
    int height;
    SDL_GetWindowSize(m_window, &width, &height);

    glm::ivec2 mouse_pos;
    if (m_look_mode) {
        // Yaw
        SDL_GetRelativeMouseState(&(mouse_pos.x), &(mouse_pos.y));
        if (mouse_pos.x != 0) {
            m_scene_changed = true;
            Camera::set_dir(m_camera, glm::rotateY(Camera::dir(m_camera), mouse_pos.x * 0.001f));
        }

        // Pitch
        if (mouse_pos.y != 0) {
            m_scene_changed = true;
            Camera::set_dir(m_camera,
                            glm::rotate(Camera::dir(m_camera), mouse_pos.y * 0.001f,
                                        glm::cross(Camera::up(m_camera), Camera::dir(m_camera))));
        }

    } else if (!m_look_mode) {
        SDL_GetMouseState(&(mouse_pos.x), &(mouse_pos.y));
    }

    if (m_scene_changed) {
        m_samples_accumulated = 0;
    }

    if (m_print_perf)
        fmt::print("    {:<15} {:>10.3f} ms\n", "Input handling", timer.elapsed());

    Scene::rebuild(m_scene);

    if (m_print_perf)
        fmt::print("    {:<15} {:=10.3f} ms\n", "Scene rebuild", timer.elapsed());

    const auto luminance = m_renderer->render(m_scene_changed, m_stride_x, m_stride_y);
    if (m_print_perf) {
        m_renderer->print_last_frame_timings();
    }

    m_samples_accumulated += 1;

    timer.reset();

// This striding is just for speeding up
// We're basically drawing really big pixels here
#pragma omp parallel for collapse(2) schedule(dynamic, 1024)
    for (auto x = 0; x < width; x += m_stride_x) {
        for (auto y = 0; y < height; y += m_stride_y) {
            glm::vec4 color = luminance[y * width + x] / static_cast<float>(m_samples_accumulated);
            for (auto u = 0; u < m_stride_x; u++) {
                for (auto v = 0; v < m_stride_y; v++) {
                    m_pixels[(y + v) * width + (x + u)] = trac0r::pack_color_argb(color);
                }
            }
        }
    }

    if (m_print_perf)
        fmt::print("    {:<15} {:>10.3f} ms\n", "Pixel transfer", timer.elapsed());

    // std::vector<uint32_t> m_pixels_filtered;
    // m_pixels_filtered.resize(m_screen_width * m_screen_height, 0);
    // trac0r::box_filter(m_pixels, width, height, m_pixels_filtered);
    // m_pixels = m_pixels_filtered;
    //
    // if (m_print_perf)
    //     fmt::print("    {:<15} {:>10.3f} ms\n", "Image filtering", timer.elapsed());

    SDL_RenderClear(m_render);
    SDL_UpdateTexture(m_render_tex, 0, m_pixels.data(), width * sizeof(uint32_t));
    SDL_RenderCopy(m_render, m_render_tex, 0, 0);

    if (m_debug) {
        // Lots of debug info
        glm::vec2 mouse_rel_pos =
            Camera::screenspace_to_camspace(m_camera, mouse_pos.x, mouse_pos.y);
        glm::vec3 mouse_canvas_pos = Camera::camspace_to_worldspace(m_camera, mouse_rel_pos);

        auto fps_debug_info = "FPS: " + std::to_string(int(fps));
        auto scene_changing_info = "Samples : " + std::to_string(m_samples_accumulated);
        scene_changing_info += " Scene Changing: " + std::to_string(m_scene_changed);
        auto cam_look_debug_info = "Cam Look Mode: " + std::to_string(m_look_mode);
        auto cam_pos_debug_info = "Cam Pos: " + glm::to_string(Camera::pos(m_camera));
        auto cam_dir_debug_info = "Cam Dir: " + glm::to_string(Camera::dir(m_camera));
        auto cam_up_debug_info = "Cam Up: " + glm::to_string(Camera::up(m_camera));
        auto cam_fov_debug_info =
            "Cam FOV (H/V): " +
            std::to_string(int(glm::degrees(Camera::horizontal_fov(m_camera)))) + "/";
        cam_fov_debug_info += std::to_string(int(glm::degrees(Camera::vertical_fov(m_camera))));
        auto cam_canvas_center_pos_info =
            "Cam Canvas Center: " + glm::to_string(Camera::canvas_center_pos(m_camera));
        auto mouse_pos_screen_info = "Mouse Pos Screen Space: " + glm::to_string(mouse_pos);
        auto mouse_pos_relative_info = "Mouse Pos Cam Space: " + glm::to_string(mouse_rel_pos);
        auto mouse_pos_canvas_info =
            "Mouse Pos Canvas World Space: " + glm::to_string(mouse_canvas_pos);

        auto fps_debug_tex =
            trac0r::make_text(m_render, m_font, fps_debug_info, {200, 100, 100, 200});
        auto scene_changing_tex =
            trac0r::make_text(m_render, m_font, scene_changing_info, {200, 100, 100, 200});
        auto cam_look_debug_tex =
            trac0r::make_text(m_render, m_font, cam_look_debug_info, {200, 100, 100, 200});
        auto cam_pos_debug_tex =
            trac0r::make_text(m_render, m_font, cam_pos_debug_info, {200, 100, 100, 200});
        auto cam_dir_debug_tex =
            trac0r::make_text(m_render, m_font, cam_dir_debug_info, {200, 100, 100, 200});
        auto cam_up_debug_tex =
            trac0r::make_text(m_render, m_font, cam_up_debug_info, {200, 100, 100, 200});
        auto cam_fov_debug_tex =
            trac0r::make_text(m_render, m_font, cam_fov_debug_info, {200, 100, 100, 200});
        auto cam_canvas_center_pos_tex =
            trac0r::make_text(m_render, m_font, cam_canvas_center_pos_info, {200, 100, 100, 200});
        auto mouse_pos_screen_tex =
            trac0r::make_text(m_render, m_font, mouse_pos_screen_info, {200, 100, 100, 200});
        auto mouse_pos_relative_tex =
            trac0r::make_text(m_render, m_font, mouse_pos_relative_info, {200, 100, 100, 200});
        auto mouse_pos_canvas_tex =
            trac0r::make_text(m_render, m_font, mouse_pos_canvas_info, {200, 100, 100, 200});

        trac0r::render_text(m_render, fps_debug_tex, 10, 10);
        trac0r::render_text(m_render, scene_changing_tex, 10, 25);
        trac0r::render_text(m_render, cam_look_debug_tex, 10, 40);
        trac0r::render_text(m_render, cam_pos_debug_tex, 10, 55);
        trac0r::render_text(m_render, cam_dir_debug_tex, 10, 70);
        trac0r::render_text(m_render, cam_up_debug_tex, 10, 85);
        trac0r::render_text(m_render, cam_fov_debug_tex, 10, 100);
        trac0r::render_text(m_render, cam_canvas_center_pos_tex, 10, 115);
        trac0r::render_text(m_render, mouse_pos_screen_tex, 10, 130);
        trac0r::render_text(m_render, mouse_pos_relative_tex, 10, 145);
        trac0r::render_text(m_render, mouse_pos_canvas_tex, 10, 160);

        // Let's draw some debug to the display (such as AABBs)
        if (m_debug) {
            auto &accel_struct = Scene::accel_struct(m_scene);
            for (auto &shape : FlatStructure::shapes(accel_struct)) {
                auto &aabb = Shape::aabb(shape);
                const auto &verts = AABB::vertices(aabb);
                std::array<glm::i8vec2, 12> pairs;
                pairs[0] = {0, 1};
                pairs[1] = {1, 3};
                pairs[2] = {2, 3};
                pairs[3] = {0, 2};
                pairs[4] = {4, 5};
                pairs[5] = {5, 7};
                pairs[6] = {6, 7};
                pairs[7] = {4, 6};
                pairs[8] = {0, 4};
                pairs[9] = {1, 5};
                pairs[10] = {2, 6};
                pairs[11] = {3, 7};
                for (auto pair : pairs) {
                    auto ws1 = Camera::worldpoint_to_worldspace(m_camera, verts[pair[0]]);
                    auto ss1 = glm::i32vec2(0);
                    if (ws1 != glm::vec3(0)) {
                        auto cs1 = Camera::worldspace_to_camspace(m_camera, ws1);
                        ss1 = Camera::camspace_to_screenspace(m_camera, cs1);
                    }
                    auto ws2 = Camera::worldpoint_to_worldspace(m_camera, verts[pair[1]]);
                    auto ss2 = glm::i32vec2(0);
                    if (ws2 != glm::vec3(0)) {
                        auto cs2 = Camera::worldspace_to_camspace(m_camera, ws2);
                        ss2 = Camera::camspace_to_screenspace(m_camera, cs2);
                    }
                    if (ss1 != glm::i32vec2(0) && ss2 != glm::i32vec2(0)) {
                        aalineRGBA(m_render, ss1.x, ss1.y, ss2.x, ss2.y, 255, 255, 0, 200);
                    }
                }
            }
        }

        SDL_DestroyTexture(fps_debug_tex);
        SDL_DestroyTexture(scene_changing_tex);
        SDL_DestroyTexture(cam_look_debug_tex);
        SDL_DestroyTexture(cam_pos_debug_tex);
        SDL_DestroyTexture(cam_dir_debug_tex);
        SDL_DestroyTexture(cam_up_debug_tex);
        SDL_DestroyTexture(cam_fov_debug_tex);
        SDL_DestroyTexture(cam_canvas_center_pos_tex);
        SDL_DestroyTexture(mouse_pos_screen_tex);
        SDL_DestroyTexture(mouse_pos_relative_tex);
        SDL_DestroyTexture(mouse_pos_canvas_tex);
    }

    SDL_RenderPresent(m_render);

    if (m_print_perf) {
        fmt::print("    {:<15} {:>10.3f} ms\n", "Rendering", timer.elapsed());
        fmt::print("    {:<15} {:>10.3f} ms\n", "=> Budget", 1000.f / 60.f - total.peek());
        fmt::print("    {:<15} {:>10.3f} ms\n\n", "=> Total", total.peek());
    }

    m_frame_total += total.elapsed();
    if (m_benchmark_mode < 0 && m_max_frames != 0 && m_frame > m_max_frames) {
        auto filename = std::string("trac0r-") + std::to_string(m_max_frames) + std::string(".bmp");
        SDL_Surface *sshot = SDL_CreateRGBSurface(0, m_screen_width, m_screen_height, 32,
                                                  0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000);
        SDL_RenderReadPixels(m_render, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch);
        SDL_SaveBMP(sshot, filename.c_str());
        SDL_FreeSurface(sshot);
        shutdown();
    } else if (m_benchmark_mode > 0 && m_max_frames != 0 && m_frame > m_max_frames) {
        fmt::print("Benchmark results:\n");
        fmt::print("    {:<15} {:>10}\n", "Frames rendered", m_max_frames);
        fmt::print("    {:<15} {:>10.3f} ms\n", "Total runtime", m_frame_total);
        fmt::print("    {:<15} {:>10.3f} ms\n", "Avg. frame", m_frame_total / m_max_frames);
        fmt::print("    {:<15} {:>10.3f} FPS\n", "Avg. FPS",
                   1.f / ((m_frame_total / 1000.f) / m_max_frames));
        shutdown();
    }
}