Files
veejay/veejay-current/veejay-server/libvje/effects/pixelsortalpha.c
2019-09-08 15:08:29 +02:00

389 lines
11 KiB
C

/*
* Linux VeeJay
*
* Copyright(C)2019 Niels Elburg <nwelburg@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License , or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 , USA.
*/
/**
*
* Based on the original implementation of Kim Asendorf
*
* https://github.com/kimasendorf/ASDFPixelSort/blob/master/ASDFPixelSort.pde
*
* ASDFPixelSort
* Processing script to sort portions of pixels in an image.
* DEMO: http://kimasendorf.com/mountain-tour/ http://kimasendorf.com/sorted-aerial/
* Kim Asendorf 2010 http://kimasendorf.com
*/
#include "common.h"
#include <veejaycore/vjmem.h>
#include "pixelsortalpha.h"
vj_effect *pixelsortalpha_init(int w, int h)
{
vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect));
ve->num_params = 2;
ve->defaults = (int *) vj_calloc(sizeof(int) * ve->num_params); /* default values */
ve->limits[0] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* min */
ve->limits[1] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* max */
ve->limits[0][0] = 0;
ve->limits[1][0] = 2;
ve->limits[0][1] = 0;
ve->limits[1][1] = 3;
ve->defaults[0] = 0;
ve->defaults[1] = 3;
ve->description = "Alpha: Asendorf Glitch";
ve->sub_format = 1;
ve->extra_frame = 0;
ve->parallel = 0;
ve->has_user = 0;
ve->alpha = FLAG_ALPHA_SRC_A | FLAG_ALPHA_OUT;
ve->param_description = vje_build_param_list( ve->num_params, "Mode", "Columns first, Rows first, Columns Only, Rows Only");
return ve;
}
static inline unsigned int firstNotBlackY(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid, unsigned int hei)
{
while( Y[y * wid + x] <= pixel_Y_lo_ ) { /* skip black pixels in column */
if( y >= hei )
break;
y ++;
}
return y;
}
static inline unsigned int nextBlackY(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid, unsigned int hei)
{
while( Y[y * wid + x] > pixel_Y_lo_ ) { /* skip pixels until a black pixel is found */
if( y >= hei )
break;
y ++;
}
return y;
}
static inline unsigned int firstNonWhiteY(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid, unsigned int hei)
{
while( Y[y * wid + x] >= pixel_Y_hi_ ) { /* skip white pixels in column */
if( y >= hei )
break;
y ++;
}
return y;
}
static inline unsigned int nextWhiteY(uint8_t * Y, unsigned int x, unsigned int y, unsigned int wid, unsigned int hei)
{
while( Y[y * wid + x] < pixel_Y_hi_ ) { /* skip pixels until a white pixel is found */
if( y >= hei )
break;
y ++;
}
return y;
}
static inline unsigned int firstNotBlackX(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid)
{
while( Y[y * wid + x] <= pixel_Y_lo_ ) {
if( x >= wid )
break;
x ++;
}
return x;
}
static inline unsigned int nextBlackX(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid)
{
while( Y[y * wid + x] > pixel_Y_lo_ ) {
if( x >= wid )
break;
x ++;
}
return x;
}
static inline unsigned int firstNonWhiteX(uint8_t *Y, unsigned int x, unsigned int y, unsigned int wid)
{
while( Y[y * wid + x] >= pixel_Y_hi_ ) {
if( x >= wid )
break;
x ++;
}
return x;
}
static inline unsigned int nextWhiteX(uint8_t * Y, unsigned int x, unsigned int y, unsigned int wid)
{
while( Y[(y * wid + x)] < pixel_Y_hi_ ) {
if( x >= wid )
break;
x ++;
}
return x;
}
/* counting sort
*
* this routine sorts only by the first byte in uint32_t (range is 0-255)
*
* this is to 'remember' what UVA values went with Y once it is done sorting
*
* byte 0-8: Y <- sort by
* byte 8-16: U
* byte 16-24: V
* byte 24-32: A
*
*/
static void csort32( uint32_t *input, size_t n, uint32_t *output )
{
unsigned int i;
unsigned int k = 256;
uint16_t count[k];
memset( count,0,sizeof(count));
for( i = 0; i < n; i ++ )
count[ (input[i] & 0xff) ] ++;
for( i = 1; i < k; i ++ )
count[i] += count[i-1];
for( i = 0; i < n; i ++ ) {
output[ count[ (input[i] & 0xff) ] - 1 ] = input[i];
count[ (input[i] & 0xff) ] --;
}
}
/* pack by column */
static void csort32_packY( uint8_t *p[4], uint32_t *dst, size_t n, unsigned int x, unsigned int y, unsigned int wid )
{
unsigned int i,pos,dy=y;
const uint8_t *Y = p[0];
const uint8_t *U = p[1];
const uint8_t *V = p[2];
const uint8_t *A = p[3];
for( i = 0; i < n; i ++, dy ++ ) {
pos = (dy * wid) + x;
dst[i] = (Y[pos] & 0xff) + ((U[pos] & 0xff) << 8) + ((V[pos] & 0xff) << 16) + ((A[pos] & 0xff) << 24);
}
}
/* pack by column */
static void csort32_unpackY( uint8_t *p[4], uint32_t *src, size_t n, unsigned int x, unsigned int y, unsigned int wid)
{
unsigned int i,pos,dy=y;
uint8_t *Y = p[0];
uint8_t *U = p[1];
uint8_t *V = p[2];
uint8_t *A = p[3];
for( i = 0; i < n; i ++, dy ++ ) {
pos = (dy * wid) + x;
Y[pos] = (src[i] & 0xff);
U[pos] = (src[i] >> 8) & 0xff;
V[pos] = (src[i] >> 16) & 0xff;
A[pos] = (src[i] >> 24) & 0xff;
}
}
/* pack by row */
static void csort32_unpackX( uint8_t *p[4], uint32_t *src, size_t n, unsigned int x, unsigned int y, unsigned int wid)
{
unsigned int i,pos,dx=x;
uint8_t *Y = p[0];
uint8_t *U = p[1];
uint8_t *V = p[2];
uint8_t *A = p[3];
for( i = 0; i < n; i ++, dx ++ ) {
pos = (y * wid) + dx;
Y[pos] = (src[i] & 0xff);
U[pos] = (src[i] >> 8) & 0xff;
V[pos] = (src[i] >> 16) & 0xff;
A[pos] = (src[i] >> 24) & 0xff;
}
}
/* pack by row */
static void csort32_packX( uint8_t *p[4], uint32_t *dst, size_t n, unsigned int x, unsigned int y, unsigned int wid )
{
unsigned int i,pos,dx=x;
const uint8_t *Y = p[0];
const uint8_t *U = p[1];
const uint8_t *V = p[2];
const uint8_t *A = p[3];
for( i = 0; i < n; i ++,dx++ ) {
pos = (y * wid) + dx;
dst[i] = (Y[pos] & 0xff) + ((U[pos] & 0xff) << 8) + ((V[pos] & 0xff) << 16) + ((A[pos] & 0xff) << 24);
}
}
static inline void sort_x(uint8_t *P[4], unsigned int width, unsigned int x, unsigned int y, unsigned int x_end)
{
int sortlen = x_end - x;
uint32_t sorted[sortlen];
uint32_t unsorted[sortlen];
csort32_packX( P, unsorted, sortlen, x, y, width );
csort32( unsorted, sortlen, sorted );
csort32_unpackX( P, sorted, sortlen, x, y, width );
}
static inline void sort_y(uint8_t *P[4], unsigned int width, unsigned int x, unsigned int y, unsigned int y_end)
{
int sortlen = (y_end - y);
uint32_t sorted[sortlen];
uint32_t unsorted[sortlen];
csort32_packY( P, unsorted, sortlen, x, y, width );
csort32( unsorted, sortlen, sorted );
csort32_unpackY( P, sorted, sortlen, x, y, width );
}
static unsigned int pixelsortalpha_column(uint8_t *P[4], unsigned int width, unsigned int x1, unsigned int y1, unsigned int height, int mode )
{
unsigned int x = x1;
unsigned int y = y1;
unsigned int y_end = y + 1;
switch(mode) {
case 0:
y = firstNotBlackY(P[3],x,y,width,height);
y_end = nextBlackY(P[3],x,y,width,height);
break;
case 1:
y = nextWhiteY(P[3],x,y,width,height);
y_end = firstNonWhiteY(P[3],x,y,width,height);
break;
case 2:
y = firstNonWhiteY(P[3],x,y,width,height);
y_end = nextWhiteY(P[3],x,y,width,height);
break;
}
if(y_end < y) {
veejay_msg(0, "Mode y_end %d before y %d",y_end,y );
return y + 1;
}
sort_y(P,width,x,y,y_end);
return y_end;
}
static unsigned int pixelsortalpha_row(uint8_t *P[4],unsigned int width, unsigned int x1, unsigned int y1, int mode)
{
unsigned int x = x1;
unsigned int y = y1;
unsigned int x_end = x + 1;
switch(mode) {
case 0:
x = firstNotBlackX(P[3],x,y,width);
x_end = nextBlackX(P[3],x,y,width);
break;
case 1:
x = nextWhiteX(P[3],x,y,width);
x_end = firstNonWhiteX(P[3],x,y,width);
break;
case 2:
x = firstNonWhiteX(P[3],x,y,width);
x_end = nextWhiteX(P[3],x,y,width);
break;
}
if(x_end < x) {
veejay_msg(0, "Mode x_end %d before x %d",x_end,x);
return x + 1;
}
sort_x(P,width,x,y,x_end);
return x_end;
}
void pixelsortalpha_apply( void *ptr, VJFrame *frame, int *args ) {
int mode = args[0];
int rows1st = args[1];
uint8_t pixel_Y_hi_ = pixel_Y_hi_;
uint8_t pixel_Y_lo_ = pixel_Y_lo_;
unsigned int x=0,y=0;
unsigned int wid = frame->width;
unsigned int hei = frame->height;
switch(rows1st) {
case 0:
for( y = 0; y < frame->height; y ++ ) {
x = 0;
while( x < wid ) {
x += pixelsortalpha_row( frame->data, frame->width, x,y, mode );
}
}
for( x = 0; x < frame->width; x ++ ) {
y = 0;
while( y < hei ) {
y += pixelsortalpha_column( frame->data, frame->width, x, y, frame->height, mode );
}
}
break;
case 1:
for( x = 0; x < frame->width; x ++ ) {
y = 0;
while( y < hei ) {
y += pixelsortalpha_column( frame->data, frame->width, x, y, frame->height, mode );
}
}
for( y = 0; y < frame->height; y ++ ) {
x = 0;
while( x < wid ) {
x += pixelsortalpha_row( frame->data, frame->width, x,y, mode );
}
}
break;
case 2:
for( x = 0; x < frame->width; x ++ ) {
y = 0;
while( y < hei ) {
y += pixelsortalpha_column( frame->data, frame->width, x, y, frame->height,mode );
}
}
break;
case 3:
for( y = 0; y < frame->height; y ++ ) {
x = 0;
while( x < wid ) {
x += pixelsortalpha_row( frame->data, frame->width, x,y, mode );
}
}
break;
}
}