Skip to content

Commit

Permalink
Test
Browse files Browse the repository at this point in the history
  • Loading branch information
weihsinyeh committed Oct 12, 2024
1 parent 1b140a1 commit e256088
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files.associations": {
"apps_animation.h": "c",
"cstdlib": "c",
"apps_multi.h": "c"
}
}
41 changes: 40 additions & 1 deletion apps/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
* Copyright (c) 2004 Keith Packard <keithp@keithp.com>
* All rights reserved.
*/
#include <stddef.h>

#include "apps_multi.h"

#define ASSET_PATH "assets/"
#define D(x) twin_double_to_fixed(x)

static void apps_line_start(twin_screen_t *screen, int x, int y, int w, int h)
Expand Down Expand Up @@ -220,6 +221,43 @@ static void apps_jelly_start(twin_screen_t *screen, int x, int y, int w, int h)
twin_window_show(window);
}

static void apps_JPGloader_start(twin_screen_t *screen, int x, int y, int w, int h)
{
twin_window_t *window = twin_window_create(
screen, TWIN_ARGB32, TwinWindowApplication, x, y, w, h);
twin_pixmap_t *raw_background = twin_pixmap_from_file("assets/test.png", TWIN_ARGB32);
if (!raw_background) /* Fallback to a default pattern */
return twin_make_pattern();

if (h == raw_background->height && w == raw_background->width)
return raw_background;

/* Scale as needed. */
twin_pixmap_t *scaled_background =
twin_pixmap_create(TWIN_ARGB32, w, h);
if (!scaled_background) {
twin_pixmap_destroy(raw_background);
return twin_make_pattern();
}
twin_fixed_t sx, sy;
sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
twin_int_to_fixed(w));
sy = twin_fixed_div(twin_int_to_fixed(raw_background->height),
twin_int_to_fixed(h));

twin_matrix_scale(&raw_background->transform, sx, sy);
twin_operand_t srcop = {
.source_kind = TWIN_PIXMAP,
.u.pixmap = raw_background,
};
twin_composite(scaled_background, 0, 0, &srcop, 0, 0, NULL, 0, 0,
TWIN_SOURCE, w, h);

twin_pixmap_destroy(raw_background);
window->pixmap = scaled_background;

}

void apps_multi_start(twin_screen_t *screen,
const char *name,
int x,
Expand All @@ -233,4 +271,5 @@ void apps_multi_start(twin_screen_t *screen,
apps_quickbrown_start(screen, x += 20, y += 20, w, h);
apps_ascii_start(screen, x += 20, y += 20, w, h);
apps_jelly_start(screen, x += 20, y += 20, w / 2, h);
apps_JPGloader_start(screen, x += 20, y += 20, w / 2, h);
}
Binary file added assets/test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ void _twin_apply_gaussian(twin_argb32_t v,
*b += ((((v & 0x000000ff) >> 0) * (twin_argb32_t) wght) >> 4) & 0x000000ff;
return;
}

// https://github.com/sudara/melatonin_blur/blob/main/melatonin/implementations/naive.h#L72-L109
void twin_gaussian_blur(twin_pixmap_t *px)
{
if (px->format != TWIN_ARGB32)
Expand Down
150 changes: 150 additions & 0 deletions src/reference
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// horizontal pass
for (auto y = 0u; y < h; ++y)
{
auto row = data.getLinePointer (static_cast<int> (y));

// clear everything
stackSum = sumIn = sumOut = queueIndex = 0;

// Pre-fill the left half of the queue with the leftmost pixel value
for (auto i = 0u; i <= radius; ++i)
{
queue[i] = row[0];

// these init left side AND middle of the stack
sumOut += row[0];
stackSum += row[0] * (i + 1);
}

// Fill the right half of the queue with the actual pixel values
// zero is the center pixel here, it's added to the sum radius + 1 times
for (auto i = 1u; i <= radius; ++i)
{
// edge case where queue is bigger than image width!
// for example vertical test where width = 1
auto value = (i <= w - 1) ? row[i] : row[w - 1];

queue[radius + i] = value; // look ma, no bounds checkin'
sumIn += value;
stackSum += value * (radius + 1 - i);
}

for (auto x = 0u; x < w; ++x)
{
// calculate the blurred value from the stack
row[x] = static_cast<unsigned char> (stackSum / sizeOfStack);

// remove the outgoing sum from the stack
stackSum -= sumOut;

// remove the leftmost value from sumOut
sumOut -= queue[queueIndex];

// Conveniently, after advancing the index of a circular buffer
// the old "start" (aka queueIndex) will be the new "end",
// This means we can just replace it with the incoming pixel value
// if we hit the right edge, use the rightmost pixel value
auto nextIndex = x + radius + 1;
if (nextIndex < w)
queue[queueIndex] = row[nextIndex];
else
queue[queueIndex] = row[w - 1];

// Also add the new incoming value to the sumIn
sumIn += queue[queueIndex];

// Advance the queue index by 1 position
// the new incoming element is now the "last" in the queue
if (++queueIndex == queue.size())
queueIndex = 0;

// Put into place the next incoming sums
stackSum += sumIn;

// Add the current center pixel to sumOut
auto middleIndex = (queueIndex + radius) % queue.size();
sumOut += queue[middleIndex];

// *remove* the new center pixel from sumIn
sumIn -= queue[middleIndex];
}
}

// vertical pass, loop around each column
// pretty much identical to the horizontal pass
// except the pixel access is vertical instead of horizontal
// hey, it's a naive implementation! prob better for perf this way too
for (auto x = 0u; x < w; ++x)
{
// clear everything
stackSum = sumIn = sumOut = queueIndex = 0;

// Pre-fill the left half of the queue with the topmost pixel value
auto topMostPixel = data.getLinePointer (0) + (unsigned int) data.pixelStride * x;
for (auto i = 0u; i <= radius; ++i)
{
queue[i] = topMostPixel[0];

// these init left side + middle of the stack
sumOut += queue[i];
stackSum += queue[i] * (i + 1);
}

// Fill the right half of the queue (excluding center!) with actual pixel values
// zero is the topmost/center pixel here (it was added to the sum (radius + 1) times above)
for (auto i = 1u; i <= radius; ++i)
{
if (i <= h - 1)
{
auto pixel = data.getLinePointer (i) + (unsigned int) data.pixelStride * x;
queue[radius + i] = pixel[0];
}
// edge case where queue is bigger than image height!
// for example where width = 1
else
{
auto pixel = data.getLinePointer ((h - 1)) + (unsigned int) data.pixelStride * x;
queue[radius + i] = pixel[0];
}

sumIn += queue[radius + i];
stackSum += queue[radius + i] * (radius + 1 - i);
}

for (auto y = 0u; y < h; ++y)
{
// calculate the blurred value from the stack
auto blurredValue = stackSum / sizeOfStack;
jassert (blurredValue <= 255);
auto blurredPixel = data.getLinePointer (static_cast<int> (y)) + (unsigned int) data.pixelStride * x;
blurredPixel[0] = static_cast<unsigned char> (blurredValue);

// remove outgoing sum from the stack
stackSum -= sumOut;

// start crafting the next sumOut by removing the leftmost value from sumOut
sumOut -= queue[queueIndex];

// Replace the leftmost value with the incoming value
if (y + radius + 1 < h)
queue[queueIndex] = *data.getPixelPointer (static_cast<int> (x), static_cast<int> (y + radius + 1));
else
queue[queueIndex] = *data.getPixelPointer (static_cast<int> (x), static_cast<int> (h - 1));

// Add the incoming value to the sumIn
sumIn += queue[queueIndex];

// Advance the queue index by 1 position
if (++queueIndex == queue.size()) queueIndex = 0;

// Put into place the next incoming sums
stackSum += sumIn;

// Before we move the queue/kernel, add the current center pixel to sumOut
auto middleIndex = (queueIndex + radius) % queue.size();
sumOut += queue[middleIndex];

// *remove* the new center pixel (only after the window shifts)
sumIn -= queue[middleIndex];
}
}

0 comments on commit e256088

Please sign in to comment.