My current program draw a rotated bitmap (64x64) and tile it on the screen by drawing it again but adding an offset based on the computed position of the bitmap top right corner (after rotation), it works fine but i experience some jerkiness of the grid in motion.
The jerkiness doesn't appear if i do the same thing with canvas transforms.
Here is an example which compare both : https://editor.p5js.org/onirom/sketches/A5D-0nxBp
Move mouse to the left part of the canvas for the custom rotation algorithm and to the right part for the canvas one.
It seems that some tile are misplaced by a single pixel which result in the grid jerkiness.
Is there a way to remove the grid jerkiness without doing it as a single pass and keeping the same interpolation scheme ?
Is it a sub pixels correctness issue ?
Here is some code :
let tileImage = null
function preload() {
tileImage = loadImage('data:image/png;base64,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W2sfpw9AhrpK3QAHh8BokbLXPd4d6uzt3zOt/n4Aru1yvz0Dqp8AAA0aaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3LmdpbXAub3JnL3htcC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1wTU06RG9jdW1lbnRJRD0iZ2ltcDpkb2NpZDpnaW1wOjNlYzk5MTljLWI0OTUtNGExMC1hNTQyLWI1NjQ4ZDc1YzcwYSIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpmMDczODg5NS1mZDBmLTRjMGUtOTRjOS0yZjA4YjZiYjVjYjEiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDoxNjkwYmU3NS02NzE1LTQwMDEtYTdkZS0xMjBjODQ3MjU3MzgiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICBHSU1QOkFQST0iMi4wIgogICBHSU1QOlBsYXRmb3JtPSJMaW51eCIKICAgR0lNUDpUaW1lU3RhbXA9IjE2NzA1Mzk0OTE3Nzc3MTUiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zMCIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDplMGQ2NWZlOS1lMDQ1LTRhOGItYWZmZS0xZGRjMWI0M2Q3MTciCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoTGludXgpIgogICAgICBzdEV2dDp3aGVuPSIyMDIyLTEyLTA4VDIzOjQ0OjUxKzAxOjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PnF4ZZ8AAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfmDAgWLDOSx0KrAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAABDVJREFUeNrtmzFrFVEQhSeSwiIEIhJFEUUMQVERBFNYCGKhiJWllVjbCPojLGysLS2tREghgoVFBEFEEIkERRQNYiCksNPGr3jHPW/uJi8iZqZZdt/eve/tnDlzZu59YzevXvgZHbay+iNabGpye0RE7J2eiIiIew9fDXx++/qZiIh48vzjup6vdvTQzs55rl06HhERn5bXho5n3oU3nyMiYltscRs7dmS2EwFzh/cMHfjh62pERHz5PvyN794xMXC+f9fkwHjOQRIe4lzt5eJy07ytVghwCNgsU0T0tVF5vhDw28bxCG+W2NcYdRygsZ3dxzwOCfocxl88fbDzflifLOSygOOOQoDLs8rCsDOfc3Q2e2Cq8/qd+y8GPHF+btCzeBIjX6un3f1nT+3rnJfrb9+vDOiIQoDmfY0hzcuv330bmqcx7sMun5uJiIgTM9MRETG/sNb5fOZXpTi/sNSJGMcJTk+ABDioEOA0vfO044ZMyRF7LsadlgeZ3AcSVKm2KkkMJBYCsiqv1dPu3LF1Vq05HaHX0Q2uusyuFwLIxyurkwOeUmWVxVhrDDp90LfK5HNVlhki4KLqBygH8EbUk6r4WmMZ7Q3bqgfUHj1b2lC1p+O0puB3qD6pfkBrP0Crxv/FigNcp0bZta/nWzs/60XUqBBZCKC6gt2zPK324PHiQBbR5/XVAZotYG2eXxywWRyA4tNqLEMGdT4eylZ8XJWZKUytCltjP+OKQkCm3UGEeo5xIEC1PJ7CAyhC7TtoreFMkTaqLFEI0BjkDbu1QVcjZHmeHqAa84AAagjV9HSTN6o7CgEOAcq2rabr/qzgaHfW1flZTLeyfbbi5DihEKA9N2Lb6QHNCjqeul5Z3/X2Rm0OMaUDNtoP+Fds1H2J4gB9o8qi2tPD3CqsVnPUENoL5DpZhBUfTKvKP5Vo914jOEznhbt0nkKA++DGlZOdnuNNav5Xw3Pc56pKkIRnFIHaxdWdHtzv1iKZj6OOLwQQO7wRF/PZvoGs7ueco8aqruyoQnV7fPT7qgLlHKShVGuHCAjgDbdWU+oJ2DpbhVWk4BnXaXI1hH5PN2/WX6gsAAJgZ1iY/OqMmOM+5wHtEjtEaJbRvK77F521erwQoAhQdndVmyo/p/R4HrEKZ7idpGSFTNu7DhRsrr1H17fQjlNVg1oNZtnA7eXN6m+39vi3q7/igKwabN2bM6q6Xp+70f8TuPHVEXIIoOpz9XxmsL7T6tr3Vx2QrT26bKP/GtNaQles1G7dfVoIiIgYd3W9ru+rh/AE+oCjruBo/gYBenRdaIcE17niedqHqCzQtyOkHnHr+lpvOzbXzk4rtzhE6P8PtSZRhPG9VdEWAvr+h1fvdxodJKgn3W7y7HsoAlSBuue68YWAjAP6GiytypI3rzHZ17SnqL29iOkmTlH9sOUR8AvuXvZlpzhIWwAAAABJRU5ErkJggg==')
}
function setup() {
createCanvas(512, 512)
frameRate(14)
tileImage.loadPixels()
}
function computeRotatedPoint(c, s, x, y) {
return { x: x * c - y * s, y: x * s + y * c }
}
currentTileWidth = 0
currentTileHeight = 0
// draw a rotated bitmap at screen position ox, oy
function drawRotatedBitmap(c, s, ox, oy) {
let dcu = s
let dcv = c
let dru = dcv
let drv = -dcu
let su = (tileImage.width / 2.0) - (currentTileWidth_d2 * dcv + currentTileHeight_d2 * dcu)
let sv = (tileImage.height / 2.0) - (currentTileWidth_d2 * drv + currentTileHeight_d2 * dru)
let ru = su
let rv = sv
for (let y = 0; y < currentTileHeight; y += 1) {
let u = ru
let v = rv
for (let x = 0; x < currentTileWidth; x += 1) {
let ui = u
let vi = v
if (ui >= 0 && ui < tileImage.width) {
let index1 = (floor(ui) + floor(vi) * tileImage.width) * 4
let index2 = (x + ox + (y + oy) * width) * 4
pixels[index2 + 0] = tileImage.pixels[index1 + 0]
pixels[index2 + 1] = tileImage.pixels[index1 + 1]
pixels[index2 + 2] = tileImage.pixels[index1 + 2]
}
u += dru
v += drv
}
ru += dcu
rv += dcv
}
}
let angle = 0
function draw() {
background(0)
const s = sin(angle / 256 * PI * 2)
const c = cos(angle / 256 * PI * 2)
// compute rotated tile width / height
let tw = tileImage.width
let th = tileImage.height
if (angle % 128 < 64) {
currentTileWidth = abs(tw * c + th * s)
currentTileHeight = abs(tw * s + th * c)
} else {
currentTileWidth = abs(tw * c - th * s)
currentTileHeight = abs(tw * s - th * c)
}
currentTileWidth_d2 = (currentTileWidth / 2.0)
currentTileHeight_d2 = (currentTileHeight / 2.0)
// compute rotated point
const rp = computeRotatedPoint(c, s, tw, 0)
// draw tiles
loadPixels()
for (let i = -3; i <= 3; i += 1) {
// compute center
const cx = width / 2 - currentTileWidth_d2
const cy = height / 2 - currentTileHeight_d2
// compute tile position
const ox = rp.x * i
const oy = rp.y * i
drawRotatedBitmap(c, s, round(cx + ox), round(cy + oy))
}
updatePixels()
angle += 0.5
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
</body>
</html>