Issue
I have the following code which creates a pixel grid layout with a spanCount
parameter:
class MyCanvasView(context: Context, val spanCount: Double) : View(context) {
lateinit var extraCanvas: Canvas
private lateinit var extraBitmap: Bitmap
val rectangles = mutableListOf<RectF>()
private lateinit var caller: CanvasFragmentListener
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
caller = context as CanvasFragmentListener
if (::extraBitmap.isInitialized) extraBitmap.recycle()
extraBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
extraCanvas = Canvas(extraBitmap)
val scale = (w / spanCount)
for (i in 0 until spanCount.toInt()) {
for (i_2 in 0 until spanCount.toInt()) {
val left = (i * scale).toFloat()
val top = (i_2 * scale).toFloat()
val rect = RectF(
left,
top,
left + scale.toFloat(),
top + scale.toFloat()
)
Log.d("MY_LOG", "LEFT: ${((i * scale).toFloat())} TOP: ${((i_2 * scale).toFloat())} ")
rectangles.add(rect)
extraCanvas.drawRect(
rect,
Paint().apply {
style = Paint.Style.FILL
color = Color.WHITE
})
}
}
}
private fun drawRectAt(x: Float, y: Float) {
for (rect in rectangles) {
if (rect.contains(x, y)) {
caller.onPixelTapped(this, rect)
invalidate()
}
}
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val x = event.x
val y = event.y
when (event.actionMasked) {
MotionEvent.ACTION_MOVE -> {
drawRectAt(x, y)
}
MotionEvent.ACTION_DOWN -> {
drawRectAt(x, y)
}
}
return true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(extraBitmap, 0f, 0f, null)
}
}
This canvas can detect swipe/touch events of the user, which means if the user drags their finger from top to bottom at a slow speed they will see the following:
(On the left, I did a very slow bottom-to-top swipe, and on the very right, I did a very fast bottom-to-top swipe. The swipes gradually get faster as you go along.)
As you may tell, the far right example looks very bad! There are many holes in between these pixels. It seems as though the dispatchTouchEvent
isn't handling fast gestures so well.
If I open up any conventional pixel art editor and do the same as what I did in my app, there is no difference between how each line is rendered:
Even drawing a line in MS Paint with a very fast speed will yield a perfect result:
If anyone knows how I can achieve this on a Canvas please reply to this - the solution may be easy or it may be obvious - I'm new to Android Canvas so I don't really know. But for my pixel art app I want the user to be able to swipe fast and have it all rendered nicely, but I have a feeling this is going to be hard to implement and will require a lot of low level code, this guy even said you need to move to OpenGL ES to achieve this but Idk if this is true.
Edit:
Thanks to someone in the comments, the following code improves it by around 60-70%:
val historySize = event.historySize
val pointerCount = event.pointerCount
for (h in 0 until historySize) {
for (p in 0 until pointerCount) {
drawRectAt(event.getHistoricalX(p, h), event.getHistoricalY(p, h))
}
for (p in 0 until pointerCount) {
drawRectAt(event.getX(p), event.getY(p))
}
}
Really fast swipes look like the following without that block of code:
With the block of code added the situation significantly improved (and so have slower swipes):
I'm still looking for a solution which will make it 100% perfect, but I'm wondering if this is the furthest I'm going to get using event.historySize
and event.pointerCount
.
Drawing a line in between pixels gets me very close to the result:
The only problem is that the line is not pixelized in relation to the spanCount
value.
In order to rasterize the line so it appears as though the user has drawn it, we could use Bresenham's line algorithm as someone had recommended in the comments which would look similar to the following:
This is probably how most pixel art editors handle faster swipes, although there absolutely no tutorials or resources as to how you would implement Bresenham's line algorithm in an Android app, so if anyone can supply me with some easy-to-learn resources that would be appreciated.
I am offering 150 reputation immediately to anyone who can somehow assist in the implementation this feature that I want.
Solution
Late reply: this was fixed by simply drawing a line in between points using Bresenham's line algorithm.
Answered By - thebluepandabear
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.