Clean up some floating point rounding code

This commit is contained in:
Garhoogin 2025-05-28 22:51:30 -05:00 committed by GitHub
parent 89a6b845e5
commit c4c9e1ff33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 169 additions and 168 deletions

View File

@ -21,12 +21,12 @@ extern HICON g_appIcon;
#define FX32_HALF (FX32_ONE/2)
#define FX32_FROM_F32(x) ((int)(((x)<0.0f)?((x)*FX32_ONE+0.5f):((x)*FX32_ONE-0.5f)))
#define RAD_0DEG 0.00000000f
#define RAD_22_5DEG 0.39269908f
#define RAD_45DEG 0.78539816f
#define RAD_90DEG 1.57079633f
#define RAD_180DEG 3.14159265f
#define RAD_360DEG 6.28318531f
#define RAD_0DEG 0.00000000000000000
#define RAD_22_5DEG 0.39269908169872415
#define RAD_45DEG 0.78539816339744831
#define RAD_90DEG 1.57079632679489662
#define RAD_180DEG 3.14159265358979323
#define RAD_360DEG 6.28318530717958648
#define SEXT8(n) (((n)<0x080)?(n):((n)-0x100))
#define SEXT9(n) (((n)<0x100)?(n):((n)-0x200))
@ -95,7 +95,7 @@ static int AnmViewerGetAnimFrame(NANRVIEWERDATA *data, int iSeq, int iFrm, ANIM_
static void AnmViewerPreviewGetScroll(NANRVIEWERDATA *data, int *pScrollX, int *pScrollY);
static int FloatToInt(float x) {
static int FloatToInt(double x) {
return (int) (x + (x < 0.0f ? -0.5f : 0.5f));
}
@ -144,9 +144,9 @@ static void FormatFxToString(WCHAR *buf, int fx) {
static void FormatAngleToString(WCHAR *buf, int fx) {
fx &= 0xFFFF;
float deg = ((float) fx) / 65536.0f * 360.0f;
double deg = ((double) fx) / 65536.0 * 360.0;
int asInt = (int) (deg * 1000.0f + 0.5f);
int asInt = (int) (deg * 1000.0 + 0.5);
buf += wsprintfW(buf, L"%d", asInt / 1000);
*(buf++) = L'.';
@ -189,11 +189,11 @@ static OBJECT_HEADER *AnmViewerGetAssociatedObject(HWND hWnd, int type) {
// ----- transformation calculation routines
static void AnmViewerInvMtx(float *pMtx) {
float mtx[2][2];
static void AnmViewerInvMtx(double *pMtx) {
double mtx[2][2];
memcpy(mtx, pMtx, sizeof(mtx));
float det = mtx[0][0] * mtx[1][1] - mtx[1][0] * mtx[0][1];
double det = mtx[0][0] * mtx[1][1] - mtx[1][0] * mtx[0][1];
if (det == 0.0f) return;
pMtx[0 * 2 + 0] = mtx[1][1] / det;
@ -203,18 +203,18 @@ static void AnmViewerInvMtx(float *pMtx) {
}
static void AnmViewerCalcTransformMatrix(
float centerX, // center point X of transformation
float centerY, // center point Y of transformation
float scaleX, // 1. scale X
float scaleY, // 1. scale Y
float rotZ, // 2. rotation (radians)
float transX, // 3. translation X
float transY, // 3. translation Y
float *pMtx, // -> output transformation matrix
float *pTrans // -> output translation vector
double centerX, // center point X of transformation
double centerY, // center point Y of transformation
double scaleX, // 1. scale X
double scaleY, // 1. scale Y
double rotZ, // 2. rotation (radians)
double transX, // 3. translation X
double transY, // 3. translation Y
double *pMtx, // -> output transformation matrix
double *pTrans // -> output translation vector
) {
float mtx[2][2];
float trans[2];
double mtx[2][2];
double trans[2];
if (rotZ == 0.0f) {
//no rotation
@ -227,8 +227,8 @@ static void AnmViewerCalcTransformMatrix(
trans[1] = centerY * (1.0f - scaleY) + transY;
} else {
//with rotation
float sinR = (float) sin(rotZ);
float cosR = (float) cos(rotZ);
double sinR = sin(rotZ);
double cosR = cos(rotZ);
mtx[0][0] = scaleX * cosR;
mtx[0][1] = -scaleY * sinR;
@ -244,17 +244,17 @@ static void AnmViewerCalcTransformMatrix(
memcpy(pTrans, trans, sizeof(trans));
}
static void AnmViewerApplyScaleTransform(float cx, float cy, float *pTx, float *pTy, float *pSx, float *pSy, float rot, float newSx, float newSy) {
float mtxNew[2][2], transNew[2], mtxOld[2][2], transOld[2];
static void AnmViewerApplyScaleTransform(double cx, double cy, double *pTx, double *pTy, double *pSx, double *pSy, double rot, double newSx, double newSy) {
double mtxNew[2][2], transNew[2], mtxOld[2][2], transOld[2];
AnmViewerCalcTransformMatrix(0.0f, 0.0f, newSx, newSy, rot, *pTx, *pTy, &mtxNew[0][0], &transNew[0]);
AnmViewerCalcTransformMatrix(0.0f, 0.0f, *pSx, *pSy, rot, *pTx, *pTy, &mtxOld[0][0], &transOld[0]);
AnmViewerInvMtx(&mtxOld[0][0]);
//set (tx, ty) such that it transforms the same by the inverses of both new and original.
float cxAdj = cx - transOld[0];
float cyAdj = cy - transOld[1];
float cxAdj2 = (cxAdj * mtxOld[0][0] + cyAdj * mtxOld[0][1]);
float cyAdj2 = (cxAdj * mtxOld[1][0] + cyAdj * mtxOld[1][1]);
double cxAdj = cx - transOld[0];
double cyAdj = cy - transOld[1];
double cxAdj2 = (cxAdj * mtxOld[0][0] + cyAdj * mtxOld[0][1]);
double cyAdj2 = (cxAdj * mtxOld[1][0] + cyAdj * mtxOld[1][1]);
//transform by new matrix
cxAdj = (cxAdj2 * mtxNew[0][0] + cyAdj2 * mtxNew[0][1]) + transNew[0];
@ -266,17 +266,17 @@ static void AnmViewerApplyScaleTransform(float cx, float cy, float *pTx, float *
*pSy = newSy;
}
static void AnmViewerApplyRotateTransform(float cx, float cy, float *pTx, float *pTy, float sx, float sy, float *pRot, float newRot) {
float mtxNew[2][2], transNew[2], mtxOld[2][2], transOld[2];
static void AnmViewerApplyRotateTransform(double cx, double cy, double *pTx, double *pTy, double sx, double sy, double *pRot, double newRot) {
double mtxNew[2][2], transNew[2], mtxOld[2][2], transOld[2];
AnmViewerCalcTransformMatrix(0.0f, 0.0f, sx, sy, newRot, *pTx, *pTy, &mtxNew[0][0], &transNew[0]);
AnmViewerCalcTransformMatrix(0.0f, 0.0f, sx, sy, *pRot, *pTx, *pTy, &mtxOld[0][0], &transOld[0]);
AnmViewerInvMtx(&mtxOld[0][0]);
//set (tx, ty) such that it transforms the same by the inverses of both new and original.
float cxAdj = cx - transOld[0];
float cyAdj = cy - transOld[1];
float cxAdj2 = (cxAdj * mtxOld[0][0] + cyAdj * mtxOld[0][1]);
float cyAdj2 = (cxAdj * mtxOld[1][0] + cyAdj * mtxOld[1][1]);
double cxAdj = cx - transOld[0];
double cyAdj = cy - transOld[1];
double cxAdj2 = (cxAdj * mtxOld[0][0] + cyAdj * mtxOld[0][1]);
double cyAdj2 = (cxAdj * mtxOld[1][0] + cyAdj * mtxOld[1][1]);
//transform by new matrix
cxAdj = (cxAdj2 * mtxNew[0][0] + cyAdj2 * mtxNew[0][1]) + transNew[0];
@ -287,39 +287,36 @@ static void AnmViewerApplyRotateTransform(float cx, float cy, float *pTx, float
*pRot = newRot;
}
static void AnmViewerTransform(int *pX, int *pY, float a, float b, float c, float d) {
float x = (float) *pX;
float y = (float) *pY;
static void AnmViewerTransform(int *pX, int *pY, double a, double b, double c, double d) {
double x = (double) *pX;
double y = (double) *pY;
float x2 = (x * a + y * b);
float y2 = (x * c + y * d);
double x2 = (x * a + y * b);
double y2 = (x * c + y * d);
*pX = (int) (x2 + (x2 >= 0.0f ? 0.5f : -0.5f));
*pY = (int) (y2 + (y2 >= 0.0f ? 0.5f : -0.5f));
*pX = FloatToInt(x2);
*pY = FloatToInt(y2);
}
static void AnmViewerEncodeTransform(ANIM_DATA_SRT *dst, const AnmTransSrt *src) {
dst->px = (int) (src->tx + (src->tx < 0.0f ? -0.5f : 0.5f));
dst->py = (int) (src->ty + (src->ty < 0.0f ? -0.5f : 0.5f));
dst->px = FloatToInt(src->tx);
dst->py = FloatToInt(src->ty);
dst->sx = FloatToInt(src->sx * 4096.0);
dst->sy = FloatToInt(src->sy * 4096.0);
float sx = src->sx * 4096.0f;
float sy = src->sy * 4096.0f;
dst->sx = (int) (sx + (sx < 0.0f ? -0.5f : 0.5f));
dst->sy = (int) (sy + (sy < 0.0f ? -0.5f : 0.5f));
float rot = src->rot * 65536.0f / RAD_360DEG;
dst->rotZ = ((int) (rot + (rot < 0.0f ? -0.5f : 0.5f))) & 0xFFFF;
double rot = src->rot * 65536.0 / RAD_360DEG;
dst->rotZ = FloatToInt(rot) & 0xFFFF;
}
static void AnmViewerDecodeTransform(AnmTransSrt *dst, const ANIM_DATA_SRT *src) {
dst->tx = (float) src->px;
dst->ty = (float) src->py;
dst->sx = src->sx / 4096.0f;
dst->sy = src->sy / 4096.0f;
dst->rot = src->rotZ / 65536.0f * RAD_360DEG;
dst->tx = (double) src->px;
dst->ty = (double) src->py;
dst->sx = src->sx / 4096.0;
dst->sy = src->sy / 4096.0;
dst->rot = src->rotZ / 65536.0 * RAD_360DEG;
}
static void AnmViewerGetCurrentFrameTransform(NANRVIEWERDATA *data, float *pMtx, float *pTrans) {
static void AnmViewerGetCurrentFrameTransform(NANRVIEWERDATA *data, double *pMtx, double *pTrans) {
pMtx[0] = 1.0f;
pMtx[1] = 0.0f;
pMtx[2] = 0.0f;
@ -423,7 +420,7 @@ static void AnmViewerRenderSolidCircle(FrameBuffer *fb, int cx, int cy, int cr,
}
}
static void AnmViewerGetCellBoundCorners(int *ptUL, int *ptUR, int *ptDL, int *ptDR, int x, int y, int w, int h, float a, float b, float c, float d, int tx, int ty) {
static void AnmViewerGetCellBoundCorners(int *ptUL, int *ptUR, int *ptDL, int *ptDR, int x, int y, int w, int h, double a, double b, double c, double d, int tx, int ty) {
//get transformed coordinates
ptUL[0] = x; ptUL[1] = y;
ptUR[0] = x + w; ptUR[1] = y;
@ -437,7 +434,7 @@ static void AnmViewerGetCellBoundCorners(int *ptUL, int *ptUR, int *ptDL, int *p
AnmViewerTransform(&ptDR[0], &ptDR[1], a, b, c, d); ptDR[0] += tx; ptDR[1] += ty;
}
static void AnmViewerDrawBoxRot(FrameBuffer *fb, const COLOR32 *cols, int x, int y, int w, int h, int cx, int cy, float a, float b, float c, float d) {
static void AnmViewerDrawBoxRot(FrameBuffer *fb, const COLOR32 *cols, int x, int y, int w, int h, int cx, int cy, double a, double b, double c, double d) {
//transform
int ptUL[2], ptUR[2], ptDL[2], ptDR[2];
AnmViewerGetCellBoundCorners(&ptUL[0], &ptUR[0], &ptDL[0], &ptDR[0], x, y, w, h, a, b, c, d, cx, cy);
@ -484,19 +481,19 @@ static void AnmViewerGetCellBounds(NCER_CELL *cell, int *pBoundX, int *pBoundY,
// ----- hit testing routines
static float AnmViewerGetPtAngle(NANRVIEWERDATA *data, float rotX, float rotY) {
static double AnmViewerGetPtAngle(NANRVIEWERDATA *data, double rotX, double rotY) {
//rotation point
float rotD = (float) sqrt(rotX * rotX + rotY * rotY);
double rotD = sqrt(rotX * rotX + rotY * rotY);
if (rotD != 0.0f) {
rotX /= rotD;
rotY /= rotD;
}
float newrot;
if (rotY <= 0.0f) {
newrot = (float) -acos(rotX) + RAD_180DEG;
double newrot;
if (rotY <= 0.0) {
newrot = -acos(rotX) + RAD_180DEG;
} else {
newrot = (float) -acos(-rotX);
newrot = -acos(-rotX);
}
newrot -= RAD_90DEG;
return newrot;
@ -554,7 +551,7 @@ static int AnmViewerHitTest(NANRVIEWERDATA *data, int clientX, int clientY) {
AnmViewerGetCellBounds(cell, &cellX, &cellY, &cellW, &cellH);
//get transform
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
//effective rectangle: we'll scale it up to the viewe's size.
@ -569,12 +566,12 @@ static int AnmViewerHitTest(NANRVIEWERDATA *data, int clientX, int clientY) {
cellH += CELL_PADDING_SIZE;
//tranform cursor position by the inverse matrix
float invMtx[2][2];
double invMtx[2][2];
memcpy(invMtx, mtx, sizeof(mtx));
AnmViewerInvMtx(&invMtx[0][0]);
int effectiveX = x - 256 * data->scale - ((int) (trans[0] + (trans[0] < 0.0f ? -0.5f : 0.5f)));
int effectiveY = y - 128 * data->scale - ((int) (trans[1] + (trans[1] < 0.0f ? -0.5f : 0.5f)));
int effectiveX = x - 256 * data->scale - FloatToInt(trans[0]);
int effectiveY = y - 128 * data->scale - FloatToInt(trans[1]);
AnmViewerTransform(&effectiveX, &effectiveY, invMtx[0][0], invMtx[0][1], invMtx[1][0], invMtx[1][1]);
if (effectiveX >= cellX && effectiveY >= cellY && effectiveX < (cellX + cellW) && effectiveY < (cellY + cellH)) {
@ -620,10 +617,10 @@ static int AnmViewerGetEffectiveHit(NANRVIEWERDATA *data) {
return data->mouseDownHit;
}
static HCURSOR AnmViewerGetArrowCursorForAngle(NANRVIEWERDATA *data, float angle) {
static HCURSOR AnmViewerGetArrowCursorForAngle(NANRVIEWERDATA *data, double angle) {
//in rotations, adjusted by 22.5 degrees, scaled up to octants
float adj = (angle / RAD_360DEG) * 8.0f;
int octant = (int) (adj + (adj < 0.0f ? -0.5f : 0.5f));
double adj = (angle / RAD_360DEG) * 8.0;
int octant = FloatToInt(adj);
octant &= 0x7;
switch (octant) {
@ -648,9 +645,9 @@ static HCURSOR AnmViewerHitCursorRotCircle(NANRVIEWERDATA *data) {
AnmViewerPreviewGetScroll(data, &scrollX, &scrollY);
float rotX = (float) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
float rotY = (float) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
float newrot = AnmViewerGetPtAngle(data, rotX, rotY);
double rotX = (double) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
double rotY = (double) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
double newrot = AnmViewerGetPtAngle(data, rotX, rotY);
return AnmViewerGetArrowCursorForAngle(data, newrot + RAD_90DEG);
}
@ -661,11 +658,11 @@ static HCURSOR AnmViewerHitCursorBox(NANRVIEWERDATA *data, int hit) {
if (flag == 0) return LoadCursor(NULL, IDC_SIZEALL);
//get matrix transform to map edge hits to sizing cursors
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
float upX = mtx[0][1], upY = mtx[1][1];
float upMag = (float) sqrt(upX * upX + upY * upY);
double upX = mtx[0][1], upY = mtx[1][1];
double upMag = sqrt(upX * upX + upY * upY);
if (upMag > 0.0f) {
upX /= upMag;
upY /= upMag;
@ -676,26 +673,26 @@ static HCURSOR AnmViewerHitCursorBox(NANRVIEWERDATA *data, int hit) {
upY = -upY;
}
float baseAngle = (float) acos(-upY);
double baseAngle = acos(-upY);
baseAngle = baseAngle / RAD_360DEG; // to rotations
//hit edges
switch (flag) {
case ANM_HIT_U:
case ANM_HIT_D:
baseAngle += 0.000f;
baseAngle += 0.000;
break;
case ANM_HIT_L:
case ANM_HIT_R:
baseAngle += 0.250f;
baseAngle += 0.250;
break;
case ANM_HIT_U | ANM_HIT_L:
case ANM_HIT_D | ANM_HIT_R:
baseAngle += 0.375f;
baseAngle += 0.375;
break;
case ANM_HIT_U | ANM_HIT_R:
case ANM_HIT_D | ANM_HIT_L:
baseAngle += 0.125f;
baseAngle += 0.125;
break;
}
@ -813,15 +810,15 @@ static void AnmViewerRenderGlyphListImage(NANRVIEWERDATA *data, int i) {
//render
memset(data->cellRender, 0, sizeof(data->cellRender));
if (cell != NULL) {
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
float sx = frm.sx / 4096.0f;
float sy = frm.sy / 4096.0f;
float rot = (frm.rotZ / 65536.0f) * RAD_360DEG;
double sx = frm.sx / 4096.0;
double sy = frm.sy / 4096.0;
double rot = (frm.rotZ / 65536.0) * RAD_360DEG;
AnmViewerCalcTransformMatrix(0.0f, 0.0f, sx, sy, rot, (float) frm.px, (float) frm.py, &mtx[0][0], trans);
AnmViewerCalcTransformMatrix(0.0f, 0.0f, sx, sy, rot, (double) frm.px, (double) frm.py, &mtx[0][0], trans);
CellViewerRenderCell(data->cellRender, NULL, ncer, ncgr, nclr, frm.index, cell,
(int) trans[0], (int) trans[1],
FloatToInt(trans[0]), FloatToInt(trans[1]),
mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1]);
}
@ -862,13 +859,13 @@ static void AnmViewerSetRotationPoint(NANRVIEWERDATA *data) {
int xMin, yMin, w, h;
AnmViewerGetCellBounds(cell, &xMin, &yMin, &w, &h);
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
//get the bounding coordinates
int ptUL[2], ptUR[2], ptDL[2], ptDR[2];
AnmViewerGetCellBoundCorners(&ptUL[0], &ptUR[0], &ptDL[0], &ptDR[0], xMin, yMin, w, h,
mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1], (int) trans[0], (int) trans[1]);
mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1], FloatToInt(trans[0]), FloatToInt(trans[1]));
int cx = data->anchorX, cy = data->anchorY;
int d2UL = (ptUL[0] - cx) * (ptUL[0] - cx) + (ptUL[1] - cy) * (ptUL[1] - cy);
@ -881,14 +878,14 @@ static void AnmViewerSetRotationPoint(NANRVIEWERDATA *data) {
if (d2UR > maxD2) maxD2 = d2UR;
if (d2DL > maxD2) maxD2 = d2DL;
if (d2DR > maxD2) maxD2 = d2DR;
float maxD = (float) sqrt((float) maxD2);
double maxD = sqrt((double) maxD2);
//rotate and add displacement
float rot = frame.rotZ / 65536.0f * RAD_360DEG;
float rotX = (float) cos(rot - RAD_90DEG) * maxD + (float) cx;
float rotY = (float) sin(rot - RAD_90DEG) * maxD + (float) cy;
data->rotPtX = (int) rotX;
data->rotPtY = (int) rotY;
double rot = frame.rotZ / 65536.0 * RAD_360DEG;
double rotX = cos(rot - RAD_90DEG) * maxD + (double) cx;
double rotY = sin(rot - RAD_90DEG) * maxD + (double) cy;
data->rotPtX = FloatToInt(rotX);
data->rotPtY = FloatToInt(rotY);
}
static void AnmViewerSetAnchor(NANRVIEWERDATA *data, int x, int y) {
@ -915,7 +912,7 @@ static void AnmViewerSetDefaultAnchor(NANRVIEWERDATA *data) {
int xMin, yMin, w, h;
AnmViewerGetCellBounds(cell, &xMin, &yMin, &w, &h);
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
int anchorX = xMin + w / 2;
@ -923,8 +920,8 @@ static void AnmViewerSetDefaultAnchor(NANRVIEWERDATA *data) {
AnmViewerTransform(&anchorX, &anchorY, mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1]);
//set anchor
anchorX += (int) (trans[0] + (trans[0] < 0.0f ? -0.5f : 0.5f));
anchorY += (int) (trans[1] + (trans[1] < 0.0f ? -0.5f : 0.5f));
anchorX += FloatToInt(trans[0]);
anchorY += FloatToInt(trans[1]);
AnmViewerSetAnchor(data, anchorX, anchorY);
}
@ -1600,16 +1597,16 @@ static void AnmViewerPreviewOnPaint(NANRVIEWERDATA *data) {
}
//render
float mtx[2][2] = { { 1.0f, 0.0f }, { 0.0f, 1.0f } }, trans[2] = { 0 };
double mtx[2][2] = { { 1.0f, 0.0f }, { 0.0f, 1.0f } }, trans[2] = { 0 };
memset(data->cellRender, 0, sizeof(data->cellRender));
if (cell != NULL) {
float sx = frm.sx / 4096.0f;
float sy = frm.sy / 4096.0f;
float rot = (frm.rotZ / 65536.0f) * RAD_360DEG;
double sx = frm.sx / 4096.0;
double sy = frm.sy / 4096.0;
double rot = (frm.rotZ / 65536.0) * RAD_360DEG;
AnmViewerCalcTransformMatrix(0.0f, 0.0f, sx, sy, rot, (float) frm.px, (float) frm.py, &mtx[0][0], trans);
AnmViewerCalcTransformMatrix(0.0, 0.0, sx, sy, rot, (double) frm.px, (double) frm.py, &mtx[0][0], trans);
CellViewerRenderCell(data->cellRender, NULL, ncer, ncgr, nclr, frm.index, cell,
(int) trans[0], (int) trans[1],
FloatToInt(trans[0]), FloatToInt(trans[1]),
mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1]);
}
@ -1662,8 +1659,8 @@ static void AnmViewerPreviewOnPaint(NANRVIEWERDATA *data) {
int boxX, boxY, boxW, boxH;
AnmViewerGetCellBounds(cell, &boxX, &boxY, &boxW, &boxH);
int cx = (int) (trans[0] + (trans[0] < 0.0f ? -0.5f : 0.5f));
int cy = (int) (trans[1] + (trans[1] < 0.0f ? -0.5f : 0.5f));
int cx = FloatToInt(trans[0]);
int cy = FloatToInt(trans[1]);
COLOR32 lineCols[] = { 0x00FFFF, 0x00FFFF, 0x00FFFF, 0x00FFFF }; // up down left right
int hit = AnmViewerGetEffectiveHit(data);
@ -1774,9 +1771,9 @@ static void AnmViewerPreviewOnLButtonDown(NANRVIEWERDATA *data) {
if (hitType == ANM_HIT_ROT_CIRCLE) {
//start rotation on circle, calculate rotation offset
float rotX = (float) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
float rotY = (float) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
float mouseRot = AnmViewerGetPtAngle(data, rotX, rotY);
double rotX = (double) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
double rotY = (double) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
double mouseRot = AnmViewerGetPtAngle(data, rotX, rotY);
data->rotAngleOffset = data->transStart.rot - mouseRot;
}
@ -1823,28 +1820,28 @@ static void AnmViewerPreviewOnMouseMove(NANRVIEWERDATA *data) {
int dx = (ptCursor.x - data->mouseDownX) / data->scale;
int dy = (ptCursor.y - data->mouseDownY) / data->scale;
srt.tx += (float) dx;
srt.ty += (float) dy;
srt.tx += (double) dx;
srt.ty += (double) dy;
//move anchor
AnmViewerSetAnchor(data, data->mouseDownAnchorX + dx, data->mouseDownAnchorY + dy);
} else {
//scale
float centeredX1 = (float) (data->mouseDownX + scrollX - 256 * data->scale - data->anchorX * data->scale);
float centeredY1 = (float) (data->mouseDownY + scrollY - 128 * data->scale - data->anchorY * data->scale);
float centeredX2 = (float) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
float centeredY2 = (float) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
double centeredX1 = (double) (data->mouseDownX + scrollX - 256 * data->scale - data->anchorX * data->scale);
double centeredY1 = (double) (data->mouseDownY + scrollY - 128 * data->scale - data->anchorY * data->scale);
double centeredX2 = (double) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
double centeredY2 = (double) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
AnmViewerInvMtx(&mtx[0][0]);
float vecUX = mtx[1][0];
float vecUY = mtx[1][1];
float vecRX = mtx[0][0];
float vecRY = mtx[0][1];
double vecUX = mtx[1][0];
double vecUY = mtx[1][1];
double vecRX = mtx[0][0];
double vecRY = mtx[0][1];
float gx = 1.0f, gy = 1.0f; // growth factors
double gx = 1.0f, gy = 1.0f; // growth factors
if (flg & (ANM_HIT_R | ANM_HIT_L)) {
gx = (centeredX2 * vecRX + centeredY2 * vecRY) / (centeredX1 * vecRX + centeredY1 * vecRY);
}
@ -1852,35 +1849,35 @@ static void AnmViewerPreviewOnMouseMove(NANRVIEWERDATA *data) {
gy = (centeredX2 * vecUX + centeredY2 * vecUY) / (centeredX1 * vecUX + centeredY1 * vecUY);
}
float sx2 = srt.sx * gx;
float sy2 = srt.sy * gy;
double sx2 = srt.sx * gx;
double sy2 = srt.sy * gy;
//shift pressed, round to integer scales
if (shiftState) {
//X scale
if (sx2 >= 1.0f || sx2 <= -1.0f) {
//round scale to integer
sx2 = (float) (int) (sx2 + (sx2 < 0.0f ? -0.5f : 0.5f));
sx2 = (double) FloatToInt(sx2);
} else if (sx2 != 0.0f) {
//round inverse scale to integer
sx2 = 1.0f / sx2;
sx2 = (float) (int) (sx2 + (sx2 < 0.0f ? -0.5f : 0.5f));
sx2 = (double) FloatToInt(sx2);
sx2 = 1.0f / sx2;
}
//Y scale
if (sy2 >= 1.0f || sy2 <= -1.0f) {
//round scale to integer
sy2 = (float) (int) (sy2 + (sy2 < 0.0f ? -0.5f : 0.5f));
sy2 = (double) FloatToInt(sy2);
} else if (sy2 != 0.0f) {
//round inverse scale to integer
sy2 = 1.0f / sy2;
sy2 = (float) (int) (sy2 + (sy2 < 0.0f ? -0.5f : 0.5f));
sy2 = (double) FloatToInt(sy2);
sy2 = 1.0f / sy2;
}
}
AnmViewerApplyScaleTransform((float) data->anchorX, (float) data->anchorY, &srt.tx, &srt.ty, &srt.sx, &srt.sy, srt.rot, sx2, sy2);
AnmViewerApplyScaleTransform((double) data->anchorX, (double) data->anchorY, &srt.tx, &srt.ty, &srt.sx, &srt.sy, srt.rot, sx2, sy2);
}
//put
@ -1914,7 +1911,7 @@ static void AnmViewerPreviewOnMouseMove(NANRVIEWERDATA *data) {
if (AnmViewerGetCurrentAnimFrame(data, &frm, NULL) && ncer != NULL && frm.index >= 0 && frm.index < ncer->nCells) {
NCER_CELL *cell = &ncer->cells[frm.index];
float mtx[2][2], trans[2];
double mtx[2][2], trans[2];
AnmViewerGetCurrentFrameTransform(data, &mtx[0][0], &trans[0]);
int cellX, cellY, cellW, cellH;
@ -1927,8 +1924,8 @@ static void AnmViewerPreviewOnMouseMove(NANRVIEWERDATA *data) {
&clampCoords[9][0], // 9: bottom-right
cellX, cellY, cellW, cellH,
mtx[0][0], mtx[0][1], mtx[1][0], mtx[1][1],
(int) (trans[0] + (trans[0] < 0.0f ? -0.5f : 0.5f)),
(int) (trans[1] + (trans[1] < 0.0f ? -0.5f : 0.5f)));
FloatToInt(trans[0]),
FloatToInt(trans[1]));
//interpolate edge points
AvgPoint(&clampCoords[2][0], &clampCoords[1][0], &clampCoords[3][0]);
@ -1968,21 +1965,21 @@ static void AnmViewerPreviewOnMouseMove(NANRVIEWERDATA *data) {
memcpy(&srt, &data->transStart, sizeof(AnmTransSrt));
//rotation point
float rotX = (float) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
float rotY = (float) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
float newrot = AnmViewerGetPtAngle(data, rotX, rotY);
double rotX = (double) (ptCursor.x + scrollX - 256 * data->scale - data->anchorX * data->scale);
double rotY = (double) (ptCursor.y + scrollY - 128 * data->scale - data->anchorY * data->scale);
double newrot = AnmViewerGetPtAngle(data, rotX, rotY);
newrot += data->rotAngleOffset;
//if shift pressed, round to 1/8 rotations
if (shiftState) {
newrot /= RAD_360DEG;
newrot *= 8.0f;
newrot = (float) (int) (newrot + (newrot < 0.0f ? -0.5f : 0.5f));
newrot = (double) FloatToInt(newrot);
newrot /= 8.0f;
newrot *= RAD_360DEG;
}
AnmViewerApplyRotateTransform((float) data->anchorX, (float) data->anchorY,
AnmViewerApplyRotateTransform((double) data->anchorX, (double) data->anchorY,
&srt.tx, &srt.ty, srt.sx, srt.sy, &srt.rot, newrot);
ANIM_DATA_SRT frm;
@ -2658,9 +2655,9 @@ static LRESULT CALLBACK AnmViweerInterpProc(HWND hWnd, UINT msg, WPARAM wParam,
}
angle *= angleMult;
setting->result[i].sx = FloatToInt((float) sxMag * 4096.0f);
setting->result[i].sy = FloatToInt((float) syMag * 4096.0f);
setting->result[i].rotZ = FloatToInt((float) angle * 65536.0f / RAD_360DEG) & 0xFFFF;
setting->result[i].sx = FloatToInt(sxMag * 4096.0);
setting->result[i].sy = FloatToInt(syMag * 4096.0);
setting->result[i].rotZ = FloatToInt(angle * 65536.0 / RAD_360DEG) & 0xFFFF;
} else {
//nonlinear: interpolate each parameter
int sx = setting->start.sx * weight0 + setting->end.sx * weight1;

View File

@ -12,11 +12,11 @@
#include "framebuffer.h"
typedef struct AnmTransSrt_ {
float sx; // scale Y
float sy; // scale X
float rot; // rotation (radians)
float tx; // translate X
float ty; // translate Y
double sx; // scale Y
double sy; // scale X
double rot; // rotation (radians)
double tx; // translate X
double ty; // translate Y
} AnmTransSrt;
typedef struct {
@ -43,7 +43,7 @@ typedef struct {
int mouseDownCircleR; // guide circle radius size on mouse down (to stabilize view)
int mouseDownCircleX; // guide circle X on mouse down
int mouseDownCircleY; // guide circle Y on mouse down
float rotAngleOffset; // rotation angle offset when changing
double rotAngleOffset; // rotation angle offset when changing
AnmTransSrt transStart;
int anchorX; // edit anchor X

View File

@ -1006,6 +1006,10 @@ static void CellViewerRenderObj(COLOR32 *out, NCER_CELL_INFO *info, NCGR *ncgr,
}
}
static int FloatToInt(double x) {
return (int) (x + (x < 0.0f ? -0.5f : 0.5f));
}
void CellViewerRenderCell(
COLOR32 *px,
int *covbuf,
@ -1016,10 +1020,10 @@ void CellViewerRenderCell(
NCER_CELL *cell,
int xOffs,
int yOffs,
float a,
float b,
float c,
float d
double a,
double b,
double c,
double d
) {
//adjust (X,Y) offset to center of preview
xOffs += 256;
@ -1035,21 +1039,21 @@ void CellViewerRenderCell(
}
//compute inverse matrix parameters.
float invA = 1.0f, invB = 0.0f, invC = 0.0f, invD = 1.0f;
if (a != 1.0f || b != 0.0f || c != 0.0f || d != 1.0f) {
double invA = 1.0, invB = 0.0, invC = 0.0, invD = 1.0;
if (a != 1.0 || b != 0.0 || c != 0.0 || d != 1.0) {
//not identity matrix
float det = a * d - b * c; // DBCA
if (det != 0.0f) {
double det = a * d - b * c; // DBCA
if (det != 0.0) {
invA = d / det;
invB = -b / det;
invC = -c / det;
invD = a / det;
} else {
//max scale identity
invA = 127.99609375f;
invB = 0.0f;
invC = 0.0f;
invD = 127.99609375f;
invA = 127.99609375;
invB = 0.0;
invC = 0.0;
invD = 127.99609375;
}
}
@ -1116,14 +1120,14 @@ void CellViewerRenderCell(
//transform about center
int realWidth = info.width << info.doubleSize;
int realHeight = info.height << info.doubleSize;
float cx = (realWidth - 1) * 0.5f; // rotation center X in OBJ
float cy = (realHeight - 1) * 0.5f; // rotation center Y in OBJ
double cx = (realWidth - 1) * 0.5; // rotation center X in OBJ
double cy = (realHeight - 1) * 0.5; // rotation center Y in OBJ
//transform coordinate origin by matrix transform
int movedX = x + realWidth / 2;
int movedY = y + realHeight / 2;
int movedX2 = (int) (movedX * a + movedY * b);
int movedY2 = (int) (movedX * c + movedY * d);
int movedX2 = FloatToInt(movedX * a + movedY * b);
int movedY2 = FloatToInt(movedX * c + movedY * d);
//un-correct moved position from center to top-left
movedX = movedX2 - realWidth / 2;
@ -1134,8 +1138,8 @@ void CellViewerRenderCell(
for (int k = 0; k < realWidth; k++) {
int destX = (movedX + k + xOffs) & 0x1FF;
int srcX = (int) (((((float) k) - cx) * invA + (((float) j) - cy) * invB) + cx);
int srcY = (int) (((((float) k) - cx) * invC + (((float) j) - cy) * invD) + cy);
int srcX = FloatToInt(((((double) k) - cx) * invA + (((double) j) - cy) * invB) + cx);
int srcY = FloatToInt(((((double) k) - cx) * invC + (((double) j) - cy) * invD) + cy);
//if double size, adjust source coordinate by the excess size
if (info.doubleSize) {

View File

@ -90,6 +90,6 @@ HWND CreateNcerViewerImmediate(int x, int y, int width, int height, HWND hWndPar
void CellViewerRenderGridlines(FrameBuffer *fb, int scale, int scrollX, int scrollY);
void CellViewerRenderCell(COLOR32 *px, int *covbuf, NCER *ncer, NCGR *ncgr, NCLR *nclr, int cellIndex, NCER_CELL *cell, int xOffs, int yOffs, float a, float b, float c, float d);
void CellViewerRenderCell(COLOR32 *px, int *covbuf, NCER *ncer, NCGR *ncgr, NCLR *nclr, int cellIndex, NCER_CELL *cell, int xOffs, int yOffs, double a, double b, double c, double d);
COLOR32 *CellViewerCropRenderedCell(COLOR32 *px, int width, int height, int *pMinX, int *pMinY, int *outWidth, int *outHeight);