For @HumanTorch re discussion about minimising overhead - this only tries to draw the tiles that will be displayed, as opposed to drawing the whole world and clipping at a low level. I get 19 - 20 FPS instead of 7. Another optimisation that could be made is not redraw if the tile already drawn on screen happens to be the same. Would require adding a screen tile cache. It might make sense to have separate world X and Y limits rather than a square world.
To simplify the arithmetic I set the bottom left as 0,0 both for virtual world tile coordinates and for virtual window pixel coordinates. The -240,-180 offset for the screen center is applied only at the point of drawing, and also a -4,-4 offset for the center of the 8x8 sprites is added there too. So the code sees sprites as if the origin is in the bottom left. Finally I added an arbitrary scale coordinate that can be changed at runtime. Smaller scales are very slow however.