mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-15 20:30:00 +01:00
214 lines
6.6 KiB
C
214 lines
6.6 KiB
C
/*
|
|
* Linux VeeJay
|
|
*
|
|
* Copyright(C)2002 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.
|
|
*/
|
|
|
|
|
|
/* Alpha blending with MMX, shamelessy ripped from libvisual
|
|
*
|
|
*
|
|
* Libvisual-plugins - Standard plugins for libvisual
|
|
*
|
|
* Copyright (C) 2004, 2005, 2006 Dennis Smit <ds@nerds-incorporated.org>
|
|
*
|
|
* Authors: Dennis Smit <ds@nerds-incorporated.org>
|
|
*
|
|
* $Id: morph_alphablend.c,v 1.19 2006/01/27 20:19:18 synap Exp $
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <libvjmem/vjmem.h>
|
|
#include "opacity.h"
|
|
#include "common.h"
|
|
#include <veejay/vj-task.h>
|
|
|
|
vj_effect *opacity_init(int w, int h)
|
|
{
|
|
vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect));
|
|
ve->num_params = 1;
|
|
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] = 255;
|
|
ve->defaults[0] = 150;
|
|
ve->description = "Normal Overlay";
|
|
ve->sub_format = 0;
|
|
ve->extra_frame = 1;
|
|
ve->parallel = 1;
|
|
ve->has_user = 0;
|
|
ve->param_description = vje_build_param_list( ve->num_params, "Opacity");
|
|
return ve;
|
|
}
|
|
|
|
#ifdef HAVE_ASM_MMX
|
|
static inline int blend_plane(uint8_t *dst, uint8_t *A, uint8_t *B, int size, int alpha)
|
|
{
|
|
uint32_t ialpha = alpha;
|
|
int i;
|
|
|
|
ialpha |= ialpha << 16;
|
|
|
|
__asm __volatile
|
|
("\n\t pxor %%mm6, %%mm6"
|
|
::);
|
|
|
|
for (i = size; i > 4; i -= 4) {
|
|
__asm __volatile
|
|
("\n\t movd %[alpha], %%mm3"
|
|
"\n\t movd %[src2], %%mm0"
|
|
"\n\t psllq $32, %%mm3"
|
|
"\n\t movd %[alpha], %%mm2"
|
|
"\n\t movd %[src1], %%mm1"
|
|
"\n\t por %%mm3, %%mm2"
|
|
"\n\t punpcklbw %%mm6, %%mm0" /* interleaving dest */
|
|
"\n\t punpcklbw %%mm6, %%mm1" /* interleaving source */
|
|
"\n\t psubsw %%mm1, %%mm0" /* (src - dest) part */
|
|
"\n\t pmullw %%mm2, %%mm0" /* alpha * (src - dest) */
|
|
"\n\t psrlw $8, %%mm0" /* / 256 */
|
|
"\n\t paddb %%mm1, %%mm0" /* + dest */
|
|
"\n\t packuswb %%mm0, %%mm0"
|
|
"\n\t movd %%mm0, %[dest]"
|
|
: [dest] "=m" (*(dst + i))
|
|
: [src1] "m" (*(A + i))
|
|
, [src2] "m" (*(B + i))
|
|
, [alpha] "m" (ialpha));
|
|
}
|
|
return i;
|
|
}
|
|
#else
|
|
static inline int blend_plane( uint8_t *dst, uint8_t *A, uint8_t *B, int size, int opacity )
|
|
{
|
|
unsigned int i, op0, op1;
|
|
op1 = (opacity > 255) ? 255 : opacity;
|
|
op0 = 255 - op1;
|
|
|
|
for( i = 0; i < size; i ++ )
|
|
dst[i] = (op0 * A[i] + op1 * B[i] ) >> 8;
|
|
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
static void opacity_apply1( VJFrame *frame, VJFrame *frame2, int width,
|
|
int height, int opacity)
|
|
{
|
|
int y = blend_plane( frame->data[0], frame->data[0], frame2->data[0], frame->len, opacity );
|
|
int u = blend_plane( frame->data[1], frame->data[1], frame2->data[1], (frame->ssm ? frame->len : frame->uv_len), opacity );
|
|
int v = blend_plane( frame->data[2], frame->data[2], frame2->data[2], (frame->ssm ? frame->len : frame->uv_len), opacity );
|
|
#ifdef HAVE_ASM_MMX
|
|
do_emms;
|
|
#endif
|
|
if( y>0) while (y--)
|
|
frame->data[0][y] = ((opacity * (frame->data[0][y] - frame2->data[0][y])) >> 8 ) + frame->data[0][y];
|
|
|
|
if( u>0) while( u-- )
|
|
frame->data[1][u] = ((opacity * (frame->data[1][u] - frame2->data[1][u])) >> 8 ) + frame->data[1][u];
|
|
|
|
if(v>0) while( v-- )
|
|
frame->data[2][v] = ((opacity * (frame->data[2][v] - frame2->data[2][v])) >> 8 ) + frame->data[2][v];
|
|
|
|
}
|
|
|
|
static void opacity_apply_job( void *arg )
|
|
{
|
|
vj_task_arg_t *t = (vj_task_arg_t*) arg;
|
|
//@ inplace
|
|
int y = blend_plane( t->input[0], t->input[0], t->output[0], t->strides[0], t->iparams[0] );
|
|
int u = blend_plane( t->input[1], t->input[1], t->output[1], t->strides[1], t->iparams[0] );
|
|
int v = blend_plane( t->input[2], t->input[2], t->output[2], t->strides[2], t->iparams[0] );
|
|
#ifdef HAVE_ASM_MMX
|
|
do_emms;
|
|
#endif
|
|
if( y>0) while (y--)
|
|
t->input[0][y] = ((t->iparams[0] * (t->input[0][y] - t->output[0][y])) >> 8 ) + t->input[0][y];
|
|
|
|
if( u>0) while( u-- )
|
|
t->input[1][u] = ((t->iparams[0] * (t->input[1][u] - t->output[1][u])) >> 8 ) + t->input[1][u];
|
|
|
|
if(v>0) while( v-- )
|
|
t->input[2][v] = ((t->iparams[0] * (t->input[2][v] - t->output[2][v])) >> 8 ) + t->input[2][v];
|
|
|
|
}
|
|
|
|
void opacity_apply( VJFrame *frame, VJFrame *frame2, int width,
|
|
int height, int opacity)
|
|
{
|
|
opacity_apply1( frame,frame2,width,height,opacity );
|
|
}
|
|
|
|
void opacity_applyN( VJFrame *frame, VJFrame *frame2, int width,
|
|
int height, int opacity)
|
|
{
|
|
if( vj_task_available() ) {
|
|
vj_task_set_from_frame( frame );
|
|
vj_task_set_param( opacity,0 );
|
|
vj_task_run( frame->data, frame2->data, NULL, NULL, 3, (performer_job_routine) &opacity_apply_job );
|
|
} else {
|
|
opacity_apply1( frame,frame2,width,height,opacity );
|
|
}
|
|
}
|
|
|
|
//@ used in performer
|
|
static void opacity_blend_apply1( uint8_t *src1[3], uint8_t *src2[3], int len, int uv_len, int opacity )
|
|
{
|
|
int y = blend_plane( src1[0], src1[0], src2[0], len, opacity );
|
|
int u = blend_plane( src1[1], src1[1], src2[1], uv_len,opacity);
|
|
int v = blend_plane( src1[2], src1[2], src2[2], uv_len, opacity);
|
|
#ifdef HAVE_ASM_MMX
|
|
do_emms;
|
|
#endif
|
|
|
|
while (y--)
|
|
src1[0][y] = ((opacity * (src1[0][y] - src2[0][y])) >> 8) + src1[0][y];
|
|
while( u-- )
|
|
src1[1][u] = ((opacity * (src1[1][u] - src2[1][u])) >> 8) + src1[1][u];
|
|
while( v-- )
|
|
src1[2][v] = ((opacity * (src1[2][v] - src2[2][v])) >> 8) + src1[2][v];
|
|
}
|
|
|
|
void opacity_blend_apply( uint8_t *src1[3], uint8_t *src2[3], int len, int uv_len, int opacity )
|
|
{
|
|
if( vj_task_available() ) {
|
|
vj_task_set_from_args( len,uv_len );
|
|
vj_task_set_param( opacity,0 );
|
|
vj_task_run( src1, src2, NULL, NULL, 3, (performer_job_routine) &opacity_apply_job );
|
|
} else {
|
|
opacity_blend_apply1( src1,src2,len,uv_len,opacity );
|
|
}
|
|
}
|
|
void opacity_blend_luma_apply( uint8_t *A, uint8_t *B, int len,int opacity )
|
|
{
|
|
int y = blend_plane( A,A,B, len, opacity );
|
|
#ifdef HAVE_ASM_MMX
|
|
do_emms;
|
|
#endif
|
|
while (y--)
|
|
A[y] = ((opacity * (A[y] - B[y])) >> 8 ) + A[y];
|
|
}
|
|
|
|
void opacity_free(){}
|