Move line and circle rendering to framebuffer.c

This commit is contained in:
Garhoogin 2025-05-29 12:49:02 -05:00 committed by GitHub
parent 5eb98a58e3
commit c8077dfe59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 117 additions and 186 deletions

View File

@ -61,3 +61,87 @@ void FbDraw(FrameBuffer *fb, HDC hDC, int x, int y, int width, int height, int s
BitBlt(hDC, x, y, width, height, fb->hDC, srcX, srcY, SRCCOPY);
}
// ----- rendering helper routines
static void SwapInts(int *i1, int *i2) {
int temp = *i1;
*i1 = *i2;
*i2 = temp;
}
static void SwapPoints(int *x1, int *y1, int *x2, int *y2) {
SwapInts(x1, x2);
SwapInts(y1, y2);
}
void FbPutPixel(FrameBuffer *fb, int x, int y, COLOR32 col) {
if (x < 0 || x >= fb->width) return;
if (y < 0 || y >= fb->height) return;
fb->px[x + y * fb->width] = col;
}
void FbDrawLine(FrameBuffer *fb, COLOR32 col, int x1, int y1, int x2, int y2) {
//compute deltas
int dx = x2 - x1, dy = y2 - y1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
//if dx and dy are zero, put one pixel (avoid divide by zero)
if (dx == 0 && dy == 0) {
if (x1 >= 0 && y1 >= 0 && x1 < fb->width && y1 < fb->height) {
fb->px[x1 + y1 * fb->width] = col;
}
return;
}
//draw horizontally or vertically
if (dx >= dy) {
//draw left->right
if (x2 < x1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dx; i++) {
int px = i + x1;
int py = ((i * (y2 - y1)) * 2 + dx) / (dx * 2) + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
} else {
//draw top->bottom. ensure top point first
if (y2 < y1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dy; i++) {
int px = ((i * (x2 - x1)) * 2 + dy) / (dy * 2) + x1;
int py = i + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
}
}
void FbRenderSolidCircle(FrameBuffer *fb, int cx, int cy, int cr, COLOR32 col) {
int r2 = cr * cr;
col = REVERSE(col);
//use midpoint circle algorithm
int nStep = (int) ceil(((float) cr) * 0.7071f);
for (int x = 0; x < nStep; x++) {
//compute intersection
int y = (int) (sqrt(r2 - x * x) + 0.5f);
FbPutPixel(fb, cx + x, cy + y, col);
FbPutPixel(fb, cx - x, cy + y, col);
FbPutPixel(fb, cx + x, cy - y, col);
FbPutPixel(fb, cx - x, cy - y, col);
FbPutPixel(fb, cx + y, cy + x, col);
FbPutPixel(fb, cx - y, cy + x, col);
FbPutPixel(fb, cx + y, cy - x, col);
FbPutPixel(fb, cx - y, cy - x, col);
}
}

View File

@ -17,3 +17,10 @@ void FbDestroy(FrameBuffer *fb);
void FbSetSize(FrameBuffer *fb, int width, int height);
void FbDraw(FrameBuffer *fb, HDC hDC, int x, int y, int width, int height, int srcX, int srcY);
// ----- rendering helpers
void FbPutPixel(FrameBuffer *fb, int x, int y, COLOR32 col);
void FbDrawLine(FrameBuffer *fb, COLOR32 col, int x1, int y1, int x2, int y2);
void FbRenderSolidCircle(FrameBuffer *fb, int cx, int cy, int cr, COLOR32 col);

View File

@ -336,90 +336,8 @@ static void AnmViewerGetCurrentFrameTransform(NANRVIEWERDATA *data, double *pMtx
}
// ----- rendering helper routines
static void SwapInts(int *i1, int *i2) {
int temp = *i1;
*i1 = *i2;
*i2 = temp;
}
static void SwapPoints(int *x1, int *y1, int *x2, int *y2) {
SwapInts(x1, x2);
SwapInts(y1, y2);
}
static void AnmViewerPutPixel(FrameBuffer *fb, int x, int y, COLOR32 col) {
if (x < 0 || x >= fb->width) return;
if (y < 0 || y >= fb->height) return;
fb->px[x + y * fb->width] = col;
}
static void AnmViewerDrawLine(FrameBuffer *fb, COLOR32 col, int x1, int y1, int x2, int y2) {
//compute deltas
int dx = x2 - x1, dy = y2 - y1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
//if dx and dy are zero, put one pixel (avoid divide by zero)
if (dx == 0 && dy == 0) {
if (x1 >= 0 && y1 >= 0 && x1 < fb->width && y1 < fb->height) {
fb->px[x1 + y1 * fb->width] = col;
}
return;
}
//draw horizontally or vertically
if (dx >= dy) {
//draw left->right
if (x2 < x1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dx; i++) {
int px = i + x1;
int py = ((i * (y2 - y1)) * 2 + dx) / (dx * 2) + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
} else {
//draw top->bottom. ensure top point first
if (y2 < y1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dy; i++) {
int px = ((i * (x2 - x1)) * 2 + dy) / (dy * 2) + x1;
int py = i + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
}
}
static void AnmViewerRenderSolidCircle(FrameBuffer *fb, int cx, int cy, int cr, COLOR32 col) {
int r2 = cr * cr;
col = REVERSE(col);
//use midpoint circle algorithm
int nStep = (int) ceil(((float) cr) * 0.7071f);
for (int x = 0; x < nStep; x++) {
//compute intersection
int y = (int) (sqrt(r2 - x * x) + 0.5f);
AnmViewerPutPixel(fb, cx + x, cy + y, col);
AnmViewerPutPixel(fb, cx - x, cy + y, col);
AnmViewerPutPixel(fb, cx + x, cy - y, col);
AnmViewerPutPixel(fb, cx - x, cy - y, col);
AnmViewerPutPixel(fb, cx + y, cy + x, col);
AnmViewerPutPixel(fb, cx - y, cy + x, col);
AnmViewerPutPixel(fb, cx + y, cy - x, col);
AnmViewerPutPixel(fb, cx - y, cy - x, col);
}
}
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;
@ -440,10 +358,10 @@ static void AnmViewerDrawBoxRot(FrameBuffer *fb, const COLOR32 *cols, int x, int
AnmViewerGetCellBoundCorners(&ptUL[0], &ptUR[0], &ptDL[0], &ptDR[0], x, y, w, h, a, b, c, d, cx, cy);
//draw lines
AnmViewerDrawLine(fb, cols[0], ptUL[0], ptUL[1], ptUR[0], ptUR[1]);
AnmViewerDrawLine(fb, cols[3], ptUR[0], ptUR[1], ptDR[0], ptDR[1]);
AnmViewerDrawLine(fb, cols[1], ptDR[0], ptDR[1], ptDL[0], ptDL[1]);
AnmViewerDrawLine(fb, cols[2], ptDL[0], ptDL[1], ptUL[0], ptUL[1]);
FbDrawLine(fb, cols[0], ptUL[0], ptUL[1], ptUR[0], ptUR[1]);
FbDrawLine(fb, cols[3], ptUR[0], ptUR[1], ptDR[0], ptDR[1]);
FbDrawLine(fb, cols[1], ptDR[0], ptDR[1], ptDL[0], ptDL[1]);
FbDrawLine(fb, cols[2], ptDL[0], ptDL[1], ptUL[0], ptUL[1]);
}
static void AnmViewerGetCellBounds(NCER_CELL *cell, int *pBoundX, int *pBoundY, int *pBoundW, int *pBoundH) {
@ -1691,7 +1609,7 @@ static void AnmViewerPreviewOnPaint(NANRVIEWERDATA *data) {
int cx, cy, r;
AnmViewerGetRotCircle(data, &cx, &cy, &r);
AnmViewerRenderSolidCircle(&data->fb, cx + 256 * data->scale - scrollX, cy + 128 * data->scale - scrollY, r, col);
FbRenderSolidCircle(&data->fb, cx + 256 * data->scale - scrollX, cy + 128 * data->scale - scrollY, r, col);
}
//draw anchor
@ -1703,10 +1621,10 @@ static void AnmViewerPreviewOnPaint(NANRVIEWERDATA *data) {
int hit = AnmViewerGetEffectiveHit(data);
COLOR32 col = (hit == ANM_HIT_ANCHOR ? 0xFF0000 : 0xFFFF00);
AnmViewerDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
}
//draw rotation point
@ -1718,10 +1636,10 @@ static void AnmViewerPreviewOnPaint(NANRVIEWERDATA *data) {
int hit = AnmViewerGetEffectiveHit(data);
COLOR32 col = (hit == ANM_HIT_ROT_POINT ? 0xFF0000 : 0xFFFF00);
AnmViewerDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
AnmViewerDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX + ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2);
FbDrawLine(&data->fb, col, anchorX - ANCHOR_SIZE / 2, anchorY + ANCHOR_SIZE / 2, anchorX - ANCHOR_SIZE / 2, anchorY - ANCHOR_SIZE / 2);
}
FbDraw(&data->fb, hDC, 0, 0, rcClient.right, rcClient.bottom, 0, 0);

View File

@ -3143,13 +3143,6 @@ static LRESULT CALLBACK NcerCreateCellWndProc(HWND hWnd, UINT msg, WPARAM wParam
// ----- preview code
static void CellViewerPutPixel(FrameBuffer *fb, int x, int y, COLOR32 col) {
if (x < 0 || x >= fb->width) return;
if (y < 0 || y >= fb->height) return;
fb->px[x + y * fb->width] = col;
}
static void CellViewerRenderHighContrastPixel(FrameBuffer *fb, int x, int y, int chno) {
if (x < 0 || x >= fb->width) return;
if (y < 0 || y >= fb->height) return;
@ -3216,26 +3209,6 @@ static void CellViewerRenderDottedRect(FrameBuffer *fb, int x, int y, int w, int
}
}
static void CellViewerRenderSolidCircle(FrameBuffer *fb, int cx, int cy, int cr, COLOR32 col) {
int r2 = cr * cr;
col = REVERSE(col);
//use midpoint circle algorithm
int nStep = (int) ceil(((float) cr) * 0.7071f);
for (int x = 0; x < nStep; x++) {
//compute intersection
int y = (int) (sqrt(r2 - x * x) + 0.5f);
CellViewerPutPixel(fb, cx + x, cy + y, col);
CellViewerPutPixel(fb, cx - x, cy + y, col);
CellViewerPutPixel(fb, cx + x, cy - y, col);
CellViewerPutPixel(fb, cx - x, cy - y, col);
CellViewerPutPixel(fb, cx + y, cy + x, col);
CellViewerPutPixel(fb, cx - y, cy + x, col);
CellViewerPutPixel(fb, cx + y, cy - x, col);
CellViewerPutPixel(fb, cx - y, cy - x, col);
}
}
void CellViewerRenderGridlines(FrameBuffer *fb, int scale, int scrollX, int scrollY) {
//main borders: red (X=256, Y=128)
CellViewerRenderDottedLineV(fb, 256 * scale - scrollX, 0, 1);
@ -3331,7 +3304,7 @@ static void CellViewerPreviewOnPaint(NCERVIEWERDATA *data) {
//get mid point
int midX = (cell->minX + cell->maxX) / 2;
int midY = (cell->minY + cell->maxY) / 2;
CellViewerRenderSolidCircle(&data->fb, (midX + 256) * data->scale - scrollX, (midY + 128) * data->scale - scrollY,
FbRenderSolidCircle(&data->fb, (midX + 256) * data->scale - scrollX, (midY + 128) * data->scale - scrollY,
((cell->cellAttr & 0x3F) << 2) * data->scale, 0x00FFFF);
}

View File

@ -6,57 +6,6 @@ static void SwapInts(int *i1, int *i2) {
*i2 = temp;
}
static void SwapPoints(int *x1, int *y1, int *x2, int *y2) {
SwapInts(x1, x2);
SwapInts(y1, y2);
}
// ----- internal functions for rendering
static void TedDrawLine(FrameBuffer *fb, COLOR32 col, int x1, int y1, int x2, int y2) {
//compute deltas
int dx = x2 - x1, dy = y2 - y1;
if (dx < 0) dx = -dx;
if (dy < 0) dy = -dy;
//if dx and dy are zero, put one pixel (avoid divide by zero)
if (dx == 0 && dy == 0) {
if (x1 >= 0 && y1 >= 0 && x1 < fb->width && y1 < fb->height) {
fb->px[x1 + y1 * fb->width] = col;
}
return;
}
//draw horizontally or vertically
if (dx >= dy) {
//draw left->right
if (x2 < x1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dx; i++) {
int px = i + x1;
int py = ((i * (y2 - y1)) * 2 + dx) / (dx * 2) + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
} else {
//draw top->bottom. ensure top point first
if (y2 < y1) SwapPoints(&x1, &y1, &x2, &y2);
//scan
for (int i = 0; i <= dy; i++) {
int px = ((i * (x2 - x1)) * 2 + dy) / (dy * 2) + x1;
int py = i + y1;
if (px >= 0 && py >= 0 && px < fb->width && py < fb->height) {
fb->px[px + py * fb->width] = col;
}
}
}
}
// ----- margin functions
@ -175,12 +124,12 @@ void TedMarginPaint(HWND hWnd, EDITOR_DATA *data, TedData *ted) {
for (int x = 0; x < viewWidth; x++) {
if (((x + scrollX) % tileW) == 0) {
//tick
TedDrawLine(&ted->fbMargin, 0xFFFFFF, x + MARGIN_TOTAL_SIZE, 0, x + MARGIN_TOTAL_SIZE, tickHeight - 1);
FbDrawLine(&ted->fbMargin, 0xFFFFFF, x + MARGIN_TOTAL_SIZE, 0, x + MARGIN_TOTAL_SIZE, tickHeight - 1);
}
}
for (int y = 0; y < viewHeight; y++) {
if (((y + scrollY) % tileH) == 0) {
TedDrawLine(&ted->fbMargin, 0xFFFFFF, 0, y + MARGIN_TOTAL_SIZE, tickHeight - 1, y + MARGIN_TOTAL_SIZE);
FbDrawLine(&ted->fbMargin, 0xFFFFFF, 0, y + MARGIN_TOTAL_SIZE, tickHeight - 1, y + MARGIN_TOTAL_SIZE);
}
}
@ -190,16 +139,16 @@ void TedMarginPaint(HWND hWnd, EDITOR_DATA *data, TedData *ted) {
int selX2 = (max(ted->selStartX, ted->selEndX) + 1) * tileW + MARGIN_TOTAL_SIZE - scrollX;
int selY1 = (min(ted->selStartY, ted->selEndY) + 0) * tileH + MARGIN_TOTAL_SIZE - scrollY;
int selY2 = (max(ted->selStartY, ted->selEndY) + 1) * tileH + MARGIN_TOTAL_SIZE - scrollY;
TedDrawLine(&ted->fbMargin, 0xFFFF00, selX1, 0, selX1, MARGIN_SIZE - 1);
TedDrawLine(&ted->fbMargin, 0xFFFF00, selX2, 0, selX2, MARGIN_SIZE - 1);
TedDrawLine(&ted->fbMargin, 0xFFFF00, 0, selY1, MARGIN_SIZE - 1, selY1);
TedDrawLine(&ted->fbMargin, 0xFFFF00, 0, selY2, MARGIN_SIZE - 1, selY2);
FbDrawLine(&ted->fbMargin, 0xFFFF00, selX1, 0, selX1, MARGIN_SIZE - 1);
FbDrawLine(&ted->fbMargin, 0xFFFF00, selX2, 0, selX2, MARGIN_SIZE - 1);
FbDrawLine(&ted->fbMargin, 0xFFFF00, 0, selY1, MARGIN_SIZE - 1, selY1);
FbDrawLine(&ted->fbMargin, 0xFFFF00, 0, selY2, MARGIN_SIZE - 1, selY2);
}
//draw mouse pos?
if (mouse.x != -1 && mouse.y != -1) {
TedDrawLine(&ted->fbMargin, 0xFF0000, mouse.x + MARGIN_TOTAL_SIZE, 0, mouse.x + MARGIN_TOTAL_SIZE, marginSize - 1);
TedDrawLine(&ted->fbMargin, 0xFF0000, 0, mouse.y + MARGIN_TOTAL_SIZE, marginSize - 1, mouse.y + MARGIN_TOTAL_SIZE);
FbDrawLine(&ted->fbMargin, 0xFF0000, mouse.x + MARGIN_TOTAL_SIZE, 0, mouse.x + MARGIN_TOTAL_SIZE, marginSize - 1);
FbDrawLine(&ted->fbMargin, 0xFF0000, 0, mouse.y + MARGIN_TOTAL_SIZE, marginSize - 1, mouse.y + MARGIN_TOTAL_SIZE);
}
}
@ -425,13 +374,13 @@ void TedOnViewerPaint(EDITOR_DATA *data, TedData *ted) {
int dy = -scrollY;
int borderOffsetX = -(!data->showBorders || selEndX == (ted->tilesX - 1));
int borderOffsetY = -(!data->showBorders || selEndY == (ted->tilesY - 1));
TedDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, selStartY * tileH + dy,
FbDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, selStartY * tileH + dy,
(selEndX + 1) * tileW + dx - 1, selStartY * tileH + dy);
TedDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, selStartY * tileH + dy,
FbDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, selStartY * tileH + dy,
selStartX * tileW + dx, (selEndY + 1) * tileH + dy - 1);
TedDrawLine(&ted->fb, 0xFFFF00, (selEndX + 1) * tileW + dx + borderOffsetX, selStartY * tileH + dy,
FbDrawLine(&ted->fb, 0xFFFF00, (selEndX + 1) * tileW + dx + borderOffsetX, selStartY * tileH + dy,
(selEndX + 1) * tileW + dx + borderOffsetX, (selEndY + 1) * tileH + dy + borderOffsetY);
TedDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, (selEndY + 1) * tileH + dy + borderOffsetY,
FbDrawLine(&ted->fb, 0xFFFF00, selStartX * tileW + dx, (selEndY + 1) * tileH + dy + borderOffsetY,
(selEndX + 1) * tileW + dx + borderOffsetX, (selEndY + 1) * tileH + dy + borderOffsetY);
}