/* FreeJ
* (c) Copyright 2001-2002 Denis Rojo aka jaromil <jaromil@dyne.org>
*/
#include <string.h>
#include <layer.h>
#include <context.h>
#include <lubrify.h>
#include <jutils.h>
#include <config.h>
Layer::Layer() {
quit = false;
active = false;
running = false;
hidden = false;
alpha_blit = false;
bgcolor = 0;
bgmatte = NULL;
blit_offset = 0;
_blit_algo = 1;
setname("???");
buffer = NULL;
}
Layer::~Layer() {
if(bgmatte) jfree(bgmatte);
}
void Layer::_init(Context *screen, int wdt, int hgt, int bpp) {
this->screen = screen;
geo.w = (wdt == 0) ? screen->w : wdt;
geo.h = (hgt == 0) ? screen->h : hgt;
geo.bpp = (bpp) ? bpp : screen->bpp;
geo.size = geo.w*geo.h*(geo.bpp>>3);
geo.pitch = geo.w*(geo.bpp>>3);
geo.fps = screen->fps;
geo.x = (screen->w - geo.w)/2;
geo.y = (screen->h - geo.h)/2;
crop();
screen->add_layer(this);
/* allocate memory for the matte background */
bgmatte = jalloc(bgmatte,geo.size);
notice("initialized %s layer %ix%i %ibpp",getname(),geo.w,geo.h,geo.bpp);
}
void Layer::run() {
void *res;
while(!feed()) jsleep(0,50);
func("ok, layer %s in rolling loop",getname());
running = true;
wait_feed();
while(!quit) {
if(bgcolor==0) {
res = feed();
if(!res) error("feed error on layer %s",_name);
else buffer = res;
wait_feed();
} else if(bgcolor==1) { /* go to white */
memset(bgmatte,0xff,geo.size);
jsleep(0,10);
} else if(bgcolor==2) { /* go to black */
memset(bgmatte,0x0,geo.size);
jsleep(0,10);
}
}
running = false;
}
bool Layer::add_filter(Filter *newfilt) {
/* PARANOIA */
if(!newfilt) {
warning("Layer::add_filter called with an invalid NULL filter");
return(false);
}
func("Layer::add_filter(%s)",newfilt->getname());
/* bpp support of the filter is checked by plugger */
/* let the filter initialize */
if(!newfilt->initialized) {
if(!newfilt->init(&geo)) {
error("cannot initialize plugin %s",newfilt->getname());
return false;
}
func("initialization OK");
newfilt->initialized = true;
}
/* add the filter to the linklist */
lock();
filters.add(newfilt);
unlock();
newfilt->inuse = true;
show_osd("NEW filter %s pos %u",newfilt->getname(),filters.len());
return(true);
}
bool Layer::del_filter(int sel) {
func("Layer::del_filter(%u)",sel);
Filter *filt = (Filter *) filters[sel];
/* PARANOIA */
if(!filt) {
warning("Layer::del_filter - filters.pick(%u) returned NULL",sel);
return(false);
};
lock();
filters.rem(sel);
filt->inuse = false;
filt->initialized = false;
unlock();
show_osd("DEL filter %s pos %u",filt->getname(),sel);
return(true);
}
void Layer::clear_filters() {
int c = 0;
func("Layer::clear_filters()");
lock();
Filter *f = (Filter *)filters.begin();
while(f!=NULL) {
c++;
filters.rem(1);
f->inuse = false;
f->initialized = false;
f = (Filter *)filters.begin();
}
unlock();
show_osd("CLEARED %u filters",c);
}
bool Layer::moveup_filter(int sel) {
bool res = filters.moveup(sel);
if(res)
show_osd("MOVE UP filter %u -> %u",sel,sel-1);
return(res);
}
bool Layer::movedown_filter(int sel) {
bool res = filters.movedown(sel);
if(res)
show_osd("MOVE DOWN filter %u -> %u",sel,sel+1);
return(res);
}
Filter *Layer::active_filter(int sel) {
Filter *filt = (Filter *)filters.pick(sel);
filt->active = !filt->active;
show_osd("%s filter %s pos %u",
filt->active ? "ACTIVATED" : "DEACTIVATED",
filt->getname(), sel);
return(filt);
}
void Layer::set_blit(int b) {
_blit_algo = b;
}
bool Layer::cafudda() {
if((!active) || (hidden))
return false;
offset = (bgcolor) ? bgmatte : get_buffer();
if(!offset) {
signal_feed();
return(false);
}
// lock();
Filter *filt = (Filter *)filters.begin();
while(filt) {
if(filt->active) offset = filt->process(offset);
filt = (Filter *)filt->next;
}
blit(offset);
// unlock();
signal_feed();
return(true);
}
void Layer::crop() {
Uint32 blit_xoff=0;
Uint32 blit_yoff=0;
blit_x = geo.x;
blit_y = geo.y;
blit_width = geo.w;
blit_height = geo.h;
blit_xoff = 0;
blit_yoff = 0;
func("CROP layer x[%i] y[%i] w[%i] h[%i] on screen w[%i] h[%i]",
geo.x,geo.y,geo.w,geo.h,screen->w,screen->h);
/* left bound
affects x-offset and width */
if(geo.x<0) {
blit_xoff = (-geo.x);
blit_x = 1;
if(blit_xoff>geo.w) {
func("layer out of screen to the left");
hidden = true; /* out of the screen */
geo.x = -(geo.w+1); /* don't let it go far */
} else {
hidden = false;
blit_width -= blit_xoff;
}
}
/* right bound
affects width */
if((geo.x+geo.w)>screen->w) {
if(geo.x>screen->w) { /* out of screen */
func("layer out of screen to the right");
hidden = true;
geo.x = screen->w+1; /* don't let it go far */
} else {
hidden = false;
blit_width -= (geo.w - (screen->w - geo.x));
}
}
/* upper bound
affects y-offset and height */
if(geo.y<0) {
blit_yoff = (-geo.y);
blit_y = 1;
if(blit_yoff>geo.h) {
func("layer out of screen up");
hidden = true; /* out of the screen */
geo.y = -(geo.h+1); /* don't let it go far */
} else {
hidden = false;
blit_height -= blit_yoff;
}
}
/* lower bound
affects height */
if((geo.y+geo.h)>screen->h) {
if(geo.y>screen->h) { /* out of screen */
func("layer out of screen down");
hidden = true;
geo.y = screen->h+1; /* don't let it go far */
} else {
hidden = false;
blit_height -= (geo.h - (screen->h - geo.y));
}
}
blit_offset = (blit_xoff<<2) + (blit_yoff*geo.pitch);
func("LAY BLIT x[%i] y[%i] w[%i] h[%i] xoff[%i] yoff[%i]",
blit_x, blit_y, blit_width, blit_height, blit_xoff, blit_yoff);
}
#define BLIT(op) \
{ \
scr = pscr = (uint32_t*) screen->coords(blit_x,blit_y); \
off = poff = (uint32_t*) ((uint8_t*)video+blit_offset); \
for(c=blit_height;c>0;c--) { \
for(cc=blit_width;cc>0;cc--) { \
*scr op *off; \
scr++; off++; \
} \
off = poff = poff + geo.w; \
scr = pscr = pscr + screen->w; \
} \
}
#define BLIT_ALPHA(op) \
{ \
scr = pscr = (uint32_t *) screen->coords(blit_x,blit_y); \
off = poff = (uint32_t *) ((uint8_t*)video+blit_offset); \
for(c=blit_height;c>0;c--) { \
for(cc=blit_width;cc>0;cc--) { \
alpha = (uint8_t *) off; \
if(*(alpha+4)) *scr op *off; \
scr++; off++; \
} \
off = poff = poff + geo.w; \
scr = pscr = pscr + screen->w; \
} \
}
void Layer::blit(void *video) {
/* transparence aware blits:
if alpha channel is 0x00 then pixel is not blitted
works with 32bpp */
if(hidden) return;
if(alpha_blit) {
/* ALPHA CHANNEL AWARE BLIT */
switch(_blit_algo) {
case 1:
BLIT_ALPHA(=); return;
return;
case 2:
case 3:
case 4:
{
chan = _blit_algo-2;
char *scr, *pscr, *off, *poff;
scr = pscr = (char *) screen->coords(blit_x,blit_y);
off = poff = (char *) ((Uint8*)video+blit_offset);
for(c=blit_height;c>0;c--) {
for(cc=blit_width;cc>0;cc--) {
alpha = (Uint8 *) off;
if(*(alpha+3)) *(scr+chan) = *(off+chan);
scr+=4; off+=4;
}
off = poff = poff + geo.pitch;
scr = pscr = pscr + screen->pitch;
}
}
return;
case 5: BLIT_ALPHA(+=); return;
case 6: BLIT_ALPHA(-=); return;
case 7: BLIT_ALPHA(&=); return;
case 8: BLIT_ALPHA(|=); return;
default: return;
}
} else {
/* SOLID COLOR BLIT (NO ALPHA TRANSPARENCE) */
switch(_blit_algo) {
case 1:
BLIT(=);
return;
case 2:
case 3:
case 4:
{
chan = _blit_algo-2;
char *scr, *pscr, *off, *poff;
scr = pscr = (char *) screen->coords(blit_x,blit_y);
off = poff = (char *) ((Uint8*)video+blit_offset);
for(c=blit_height;c>0;c--) {
for(cc=blit_width;cc>0;cc--) {
*(scr+chan) = *(off+chan);
scr+=4; off+=4;
}
off = poff = poff + geo.pitch;
scr = pscr = pscr + screen->pitch;
}
}
return;
case 5:
BLIT(+=);
return;
case 6:
BLIT(-=);
return;
case 7:
BLIT(&=);
return;
case 8:
BLIT(|=);
return;
default: return;
}
}
}
/* SIMPLE C CODE
(where all this blit trip started)
char *scr, *pscr;
scr = pscr = (char *) screen->coords(geo.x,geo.y);
char *off, *poff;
off = poff = (char *)video;
int c,cc;
for(c=geo.h;c>0;c--) {
off = poff = poff + geo.pitch;
scr = pscr = pscr + screen->pitch;
for(cc=geo.pitch;cc>0;cc--) *scr++ = *off++;
}
*/
void Layer::setname(char *s) {
snprintf(_name,4,"%s",s);
}
char *Layer::getname() { return _name; }
char *Layer::get_blit() {
switch(_blit_algo) {
case 1: return "RGB";
case 2: return "BLU";
case 3: return "GRE";
case 4: return "RED";
case 5: return "ADD";
case 6: return "SUB";
case 7: return "AND";
case 8: return "OR";
default: return "???";
}
}
void Layer::set_filename(char *f) {
char *p = f + strlen(f);
while(*p!='/' && (p > f)) p--;
strncpy(filename,p,256);
}
void Layer::set_position(int x, int y) {
lock();
geo.x = x;
geo.y = y;
crop();
unlock();
}
Select source code:
back to 'READ ME' (main page)
'linklist.cpp'(code that keeps layers and effects inside dynamic arrays)
'layer.h'(class declaration for the layer)
'v4l_layer.cpp'(code that feeds the video image of the
person standing in front of the screen to the layer)