797 lines
18 KiB
C
797 lines
18 KiB
C
/*
|
|
Raydium - CQFD Corp.
|
|
http://raydium.org/
|
|
License: GPL - GNU General Public License, see "gpl.txt" file.
|
|
*/
|
|
|
|
#ifndef DONT_INCLUDE_HEADERS
|
|
#include "index.h"
|
|
#else
|
|
#include "headers/live.h"
|
|
#endif
|
|
|
|
#include "live.h"
|
|
|
|
|
|
|
|
// YUV420P to RGB code (next 2 functions) from:
|
|
// Peopletracking with an omnicamera
|
|
// Daniel Hammarin & Mihajlo Miladinovic
|
|
|
|
// !! Since this code is not native, no "raydium_" prefix is used !!
|
|
|
|
/* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
|
|
#define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
|
|
void
|
|
v4l_copy_420_block (int yTL, int yTR, int yBL, int yBR,
|
|
int u, int v, int rowPixels, unsigned char *rgb, int bits)
|
|
{
|
|
const int rvScale = 91881;
|
|
const int guScale = -22553;
|
|
const int gvScale = -46801;
|
|
const int buScale = 116129;
|
|
const int yScale = 65536;
|
|
int r, g, b;
|
|
g = guScale * u + gvScale * v;
|
|
b = rvScale * v;
|
|
r = buScale * u;
|
|
yTL *= yScale;
|
|
yTR *= yScale;
|
|
yBL *= yScale;
|
|
yBR *= yScale;
|
|
if (bits == 24)
|
|
{
|
|
/* Write out top two pixels */
|
|
rgb[0] = LIMIT (b + yTL);
|
|
rgb[1] = LIMIT (g + yTL);
|
|
rgb[2] = LIMIT (r + yTL);
|
|
rgb[3] = LIMIT (b + yTR);
|
|
rgb[4] = LIMIT (g + yTR);
|
|
rgb[5] = LIMIT (r + yTR);
|
|
/* Skip down to next line to write out bottom two pixels */
|
|
rgb += 3 * rowPixels;
|
|
rgb[0] = LIMIT (b + yBL);
|
|
rgb[1] = LIMIT (g + yBL);
|
|
rgb[2] = LIMIT (r + yBL);
|
|
rgb[3] = LIMIT (b + yBR);
|
|
rgb[4] = LIMIT (g + yBR);
|
|
rgb[5] = LIMIT (r + yBR);
|
|
}
|
|
else if (bits == 16)
|
|
{
|
|
/* Write out top two pixels */
|
|
rgb[0] =
|
|
((LIMIT (b + yTL) >> 3) & 0x1F) | ((LIMIT (g + yTL) << 3) & 0xE0);
|
|
rgb[1] = ((LIMIT (g + yTL) >> 5) & 0x07) | (LIMIT (r + yTL) & 0xF8);
|
|
rgb[2] =
|
|
((LIMIT (b + yTR) >> 3) & 0x1F) | ((LIMIT (g + yTR) << 3) & 0xE0);
|
|
rgb[3] = ((LIMIT (g + yTR) >> 5) & 0x07) | (LIMIT (r + yTR) & 0xF8);
|
|
/* Skip down to next line to write out bottom two pixels */
|
|
rgb += 2 * rowPixels;
|
|
rgb[0] =
|
|
((LIMIT (b + yBL) >> 3) & 0x1F) | ((LIMIT (g + yBL) << 3) & 0xE0);
|
|
rgb[1] = ((LIMIT (g + yBL) >> 5) & 0x07) | (LIMIT (r + yBL) & 0xF8);
|
|
rgb[2] =
|
|
((LIMIT (b + yBR) >> 3) & 0x1F) | ((LIMIT (g + yBR) << 3) & 0xE0);
|
|
rgb[3] = ((LIMIT (g + yBR) >> 5) & 0x07) | (LIMIT (r + yBR) & 0xF8);
|
|
}
|
|
}
|
|
|
|
int
|
|
v4l_yuv420p2rgb (unsigned char *rgb_out, unsigned char *yuv_in, int width, int
|
|
height, int bits)
|
|
{
|
|
const int numpix = width * height;
|
|
const unsigned int bytes = bits >> 3;
|
|
int h, w, y00, y01, y10, y11, u, v;
|
|
unsigned char *pY = yuv_in;
|
|
unsigned char *pU = pY + numpix;
|
|
unsigned char *pV = pU + numpix / 4;
|
|
unsigned char *pOut = rgb_out;
|
|
if (!rgb_out || !yuv_in)
|
|
return -1;
|
|
for (h = 0; h <= height - 2; h += 2)
|
|
{
|
|
for (w = 0; w <= width - 2; w += 2)
|
|
{
|
|
y00 = *(pY);
|
|
y01 = *(pY + 1);
|
|
y10 = *(pY + width);
|
|
y11 = *(pY + width + 1);
|
|
u = (*pU++) - 128;
|
|
v = (*pV++) - 128;
|
|
v4l_copy_420_block (y00, y01, y10, y11, u, v, width, pOut, bits);
|
|
pY += 2;
|
|
pOut += bytes << 1;
|
|
}
|
|
pY += width;
|
|
pOut += width * bytes;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/////// video (devices) part
|
|
|
|
|
|
signed char raydium_live_video_isvalid(int i)
|
|
{
|
|
if(i>=0 && i<RAYDIUM_MAX_VIDEO_DEVICES &&
|
|
raydium_live_device[i].capture_style!=RAYDIUM_LIVE_FREE)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int raydium_live_video_find_free(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_VIDEO_DEVICES;i++)
|
|
if(raydium_live_device[i].capture_style==RAYDIUM_LIVE_FREE)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
int raydium_live_video_open(char *device, int sizex, int sizey)
|
|
{
|
|
#ifndef WIN32
|
|
char *default_device=RAYDIUM_LIVE_DEVICE_DEFAULT;
|
|
int id;
|
|
int capture_style = RAYDIUM_LIVE_FREE;
|
|
char palette[128];
|
|
raydium_live_Device *dev;
|
|
char force_read=0;
|
|
char cli_device[RAYDIUM_MAX_NAME_LEN];
|
|
|
|
|
|
strcpy(palette,"(none)");
|
|
|
|
if(!device)
|
|
{
|
|
raydium_init_cli_option_default("video-device",cli_device,default_device);
|
|
device=cli_device;
|
|
}
|
|
|
|
id=raydium_live_video_find_free();
|
|
if(id<0)
|
|
{
|
|
raydium_log("live: ERROR: no more free device slot available (max: %i)",RAYDIUM_MAX_VIDEO_DEVICES);
|
|
return -1;
|
|
}
|
|
|
|
dev=&raydium_live_device[id];
|
|
|
|
dev->fd=open(device, O_RDWR);
|
|
|
|
if (dev->fd<0)
|
|
{
|
|
perror("open");
|
|
raydium_log("live: ERROR: cannot open device '%s'",device);
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (ioctl(dev->fd, VIDIOCGCAP, &dev->cap) < 0)
|
|
{
|
|
perror("VIDIOGCAP");
|
|
raydium_log("live: ERROR: not a video4linux device '%s'",device);
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (ioctl(dev->fd, VIDIOCGWIN, &dev->win) < 0)
|
|
{
|
|
perror("VIDIOCGWIN");
|
|
raydium_log("live: ERROR: early error");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
if (ioctl(dev->fd, VIDIOCGPICT, &dev->vpic) < 0)
|
|
{
|
|
perror("VIDIOCGPICT");
|
|
raydium_log("live: ERROR: early error");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
raydium_log("live: device '%s' (%s)",dev->cap.name,device);
|
|
|
|
raydium_log("live: min %ix%i, max %ix%i, default %ix%i",
|
|
dev->cap.minwidth,dev->cap.minheight,
|
|
dev->cap.maxwidth,dev->cap.maxheight,
|
|
dev->win.width,dev->win.height);
|
|
|
|
dev->win.x=0;
|
|
dev->win.y=0;
|
|
|
|
if(sizex<0 || sizey<0)
|
|
{
|
|
char s[RAYDIUM_MAX_NAME_LEN];
|
|
char sx[RAYDIUM_MAX_NAME_LEN];
|
|
char sy[RAYDIUM_MAX_NAME_LEN];
|
|
|
|
dev->win.width=RAYDIUM_LIVE_SIZEX_DEFAULT;
|
|
dev->win.height=RAYDIUM_LIVE_SIZEY_DEFAULT;
|
|
|
|
if(raydium_init_cli_option("video-size",s))
|
|
{
|
|
if(!raydium_parser_cut(s,sx,sy,'x'))
|
|
{
|
|
// apply to every video device ... :/
|
|
raydium_log("live: ERROR: --video-size format invalid (ex: 352x288)");
|
|
}
|
|
else
|
|
{
|
|
dev->win.width=atoi(sx);
|
|
dev->win.height=atoi(sy);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dev->win.width=sizex;
|
|
dev->win.height=sizey;
|
|
}
|
|
|
|
dev->win.flags=0;
|
|
dev->win.clips=NULL;
|
|
dev->win.clipcount=0;
|
|
dev->win.chromakey=0;
|
|
|
|
if (ioctl(dev->fd, VIDIOCSWIN, &dev->win) < 0)
|
|
{
|
|
perror("VIDIOCSWIN");
|
|
raydium_log("live: ERROR: video mode refused: %ix%i",dev->win.width,dev->win.height);
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
// read back
|
|
if (ioctl(dev->fd, VIDIOCGWIN, &dev->win) < 0)
|
|
{
|
|
perror("VIDIOCGWIN");
|
|
raydium_log("live: ERROR: cannot read back window settings. Should never happen.");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (dev->cap.type & VID_TYPE_MONOCHROME)
|
|
{
|
|
dev->vpic.depth=8;
|
|
dev->vpic.palette=VIDEO_PALETTE_GREY; // 8bit grey
|
|
strcpy(palette,"grey, 8 bpp");
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic) < 0)
|
|
{
|
|
strcpy(palette,"grey, 6 bpp");
|
|
dev->vpic.depth=6;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic) < 0)
|
|
{
|
|
strcpy(palette,"grey, 4 bpp");
|
|
dev->vpic.depth=4;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic) < 0)
|
|
{
|
|
raydium_log("live: ERROR: cannot found suitable grey palette");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(palette,"RGB, 24 bpp");
|
|
dev->vpic.depth=24;
|
|
dev->vpic.palette=VIDEO_PALETTE_RGB24;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic) < 0)
|
|
{
|
|
strcpy(palette,"RGB565, 16 bpp");
|
|
dev->vpic.palette=VIDEO_PALETTE_RGB565;
|
|
dev->vpic.depth=16;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic)==-1)
|
|
{
|
|
strcpy(palette,"RGB555, 15 bpp");
|
|
dev->vpic.palette=VIDEO_PALETTE_RGB555;
|
|
dev->vpic.depth=15;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic)==-1)
|
|
{
|
|
strcpy(palette,"YUV420P, 24 bpp");
|
|
dev->vpic.palette=VIDEO_PALETTE_YUV420P;
|
|
dev->vpic.depth=24;
|
|
if(ioctl(dev->fd, VIDIOCSPICT, &dev->vpic)==-1)
|
|
{
|
|
raydium_log("live: ERROR: cannot found suitable color palette");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
dev->buffer2 = malloc(dev->win.width * dev->win.height * dev->vpic.depth);
|
|
if (!dev->buffer2)
|
|
{
|
|
raydium_log("live: ERROR: buffer2: out of memory (!?)");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
|
|
do // just to allow break in this if :)
|
|
{
|
|
if(dev->cap.type & VID_TYPE_CAPTURE)
|
|
{
|
|
capture_style=RAYDIUM_LIVE_CAPTURE_MMAP;
|
|
if(ioctl(dev->fd,VIDIOCGMBUF,&dev->gb_buffers)==-1)
|
|
{
|
|
perror("VIDIOCGMBUF");
|
|
raydium_log("live: ERROR: hardware refuse our mmap capture style (but is claiming this feature ...)");
|
|
force_read=1;
|
|
break;
|
|
}
|
|
|
|
dev->buffer = mmap(0,dev->gb_buffers.size,PROT_READ|PROT_WRITE,MAP_SHARED,dev->fd,0);
|
|
if(dev->buffer==(void *) -1)
|
|
{
|
|
perror("mmap");
|
|
raydium_log("live: ERROR: mmap failed");
|
|
force_read=1;
|
|
break;
|
|
}
|
|
|
|
dev->gb_buf.frame=0;
|
|
dev->gb_buf.height = dev->win.height;
|
|
dev->gb_buf.width = dev->win.width;
|
|
dev->gb_buf.format = dev->vpic.palette;
|
|
|
|
if(ioctl(dev->fd, VIDIOCMCAPTURE, &dev->gb_buf)==-1)
|
|
{
|
|
perror("VIDIOCMCAPTURE");
|
|
raydium_log("live: ERROR: mmap capture test failed");
|
|
munmap(dev->buffer,dev->gb_buffers.size);
|
|
force_read=1;
|
|
break;
|
|
}
|
|
}
|
|
} while(0); // i'm not proud of this ... :)
|
|
|
|
if(force_read)
|
|
{
|
|
raydium_log("live: fallback to read method. MAY BE SLOW !");
|
|
}
|
|
|
|
if( (!(dev->cap.type & VID_TYPE_CAPTURE)) || force_read )
|
|
{
|
|
capture_style=RAYDIUM_LIVE_CAPTURE_READ;
|
|
|
|
dev->buffer = malloc(dev->win.width * dev->win.height * dev->vpic.depth);
|
|
if (!dev->buffer)
|
|
{
|
|
raydium_log("live: ERROR: buffer2: out of memory (!?)");
|
|
close(dev->fd);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
raydium_log("live: current: %ix%i, palette %s, %s",
|
|
dev->win.width,dev->win.height,palette,
|
|
(capture_style==RAYDIUM_LIVE_CAPTURE_READ?"read method":"mmap method") );
|
|
|
|
// reserve slot
|
|
dev->capture_style=capture_style;
|
|
strcpy(dev->name,device);
|
|
raydium_log("live: video init for this device is ok");
|
|
return id;
|
|
#else
|
|
raydium_log("live: Live API is not supported under win32 yet");
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
int raydium_live_video_open_auto(void)
|
|
{
|
|
return raydium_live_video_open(RAYDIUM_LIVE_DEVICE_AUTO,RAYDIUM_LIVE_SIZE_AUTO,RAYDIUM_LIVE_SIZE_AUTO);
|
|
}
|
|
|
|
|
|
int raydium_live_video_read(raydium_live_Device *dev)
|
|
{
|
|
#ifndef WIN32
|
|
fd_set fds;
|
|
struct timeval tv;
|
|
int r;
|
|
|
|
|
|
if(dev->capture_style==RAYDIUM_LIVE_FREE)
|
|
{
|
|
raydium_log("live: ERROR: read failed: invalid device");
|
|
return -1;
|
|
}
|
|
|
|
// polling
|
|
FD_ZERO (&fds);
|
|
FD_SET (dev->fd, &fds);
|
|
tv.tv_sec=0;
|
|
tv.tv_usec=0;
|
|
r = select(dev->fd + 1, &fds, NULL, NULL, &tv);
|
|
|
|
// nothing to read, we'll try later (next frame)
|
|
if(r<=0)
|
|
return 0;
|
|
|
|
dev->src = dev->buffer;
|
|
|
|
if(dev->capture_style==RAYDIUM_LIVE_CAPTURE_READ)
|
|
{
|
|
read(dev->fd, dev->buffer, dev->win.width * dev->win.height * dev->vpic.depth);
|
|
}
|
|
else
|
|
{
|
|
dev->frame=dev->gb_buf.frame;
|
|
dev->gb_buf.height = dev->win.height;
|
|
dev->gb_buf.width = dev->win.width;
|
|
dev->gb_buf.format = dev->vpic.palette;
|
|
|
|
dev->gb_buf.frame=!dev->frame;
|
|
ioctl(dev->fd, VIDIOCMCAPTURE, &dev->gb_buf);
|
|
if(ioctl(dev->fd, VIDIOCSYNC, &dev->frame)==-1)
|
|
{
|
|
perror("mmap");
|
|
return 0;
|
|
}
|
|
dev->src+=dev->gb_buffers.offsets[dev->frame];
|
|
}
|
|
|
|
|
|
if(dev->vpic.palette==VIDEO_PALETTE_YUV420P)
|
|
{
|
|
// YUV420P style
|
|
v4l_yuv420p2rgb (dev->buffer2,dev->src,dev->win.width,dev->win.height,dev->vpic.depth);
|
|
}
|
|
else
|
|
{
|
|
// RGB style
|
|
int i,j;
|
|
int r,g,b;
|
|
for (i = j = 0; i < dev->win.width * dev->win.height; i++)
|
|
{
|
|
READ_VIDEO_PIXEL(dev->src, dev->vpic.palette, dev->vpic.depth, r, g, b);
|
|
dev->buffer2[j++]=b>>8;
|
|
dev->buffer2[j++]=g>>8;
|
|
dev->buffer2[j++]=r>>8;
|
|
}
|
|
}
|
|
|
|
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
|
|
void raydium_internal_live_video_callback(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_VIDEO_DEVICES;i++)
|
|
if(raydium_live_device[i].capture_style!=RAYDIUM_LIVE_FREE)
|
|
if(raydium_live_video_read(&raydium_live_device[i]))
|
|
raydium_live_texture_refresh(i);
|
|
}
|
|
|
|
|
|
/////////////// live API core
|
|
|
|
void raydium_internal_live_close(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_VIDEO_DEVICES;i++)
|
|
if(raydium_live_device[i].capture_style!=RAYDIUM_LIVE_FREE)
|
|
{
|
|
#ifndef WIN32
|
|
munmap(raydium_live_device[i].buffer, raydium_live_device[i].gb_buffers.size);
|
|
close(raydium_live_device[i].fd);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void raydium_live_init(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_VIDEO_DEVICES;i++)
|
|
{
|
|
raydium_live_device[i].capture_style=RAYDIUM_LIVE_FREE;
|
|
raydium_live_device[i].buffer=NULL;
|
|
raydium_live_device[i].frame=0;
|
|
}
|
|
|
|
for(i=0;i<RAYDIUM_MAX_LIVE_TEXTURES;i++)
|
|
{
|
|
raydium_live_texture[i].state=0;
|
|
raydium_live_texture[i].device=NULL;
|
|
raydium_live_texture[i].OnRefresh=NULL;
|
|
raydium_live_texture[i].data_source=NULL;
|
|
}
|
|
|
|
raydium_log("video (live): OK");
|
|
}
|
|
|
|
|
|
|
|
signed char raydium_live_texture_isvalid(int i)
|
|
{
|
|
if(i>=0 && i<RAYDIUM_MAX_LIVE_TEXTURES && raydium_live_texture[i].state)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
int raydium_live_texture_find_free(void)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_LIVE_TEXTURES;i++)
|
|
if(!raydium_live_texture[i].state)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
int raydium_live_texture_find(int original_texture)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<RAYDIUM_MAX_LIVE_TEXTURES;i++)
|
|
if(raydium_live_texture[i].state &&
|
|
raydium_live_texture[i].texture==original_texture)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
|
|
int raydium_live_texture_video(int device_id, char *as)
|
|
{
|
|
#ifndef WIN32
|
|
int id;
|
|
raydium_live_Device *dev;
|
|
raydium_live_Texture *tex;
|
|
|
|
if(!raydium_live_video_isvalid(device_id))
|
|
{
|
|
raydium_log("live: ERROR: invalid device id, cannot create live source");
|
|
return -1;
|
|
}
|
|
|
|
dev=&raydium_live_device[device_id];
|
|
id=raydium_live_texture_find_free();
|
|
|
|
if(id<0)
|
|
{
|
|
raydium_log("live: ERROR: no more free live texture slot available (max: %i)",RAYDIUM_MAX_LIVE_TEXTURES);
|
|
return -1;
|
|
}
|
|
|
|
tex=&raydium_live_texture[id];
|
|
|
|
tex->tx=dev->win.width;
|
|
tex->ty=dev->win.height;
|
|
tex->hardware_tx=raydium_trigo_pow2_next(dev->win.width);
|
|
tex->hardware_ty=raydium_trigo_pow2_next(dev->win.height);
|
|
tex->bpp=dev->vpic.depth;
|
|
tex->texture=raydium_texture_load_internal("not needed :)",as,1,0,0,0,id);
|
|
|
|
|
|
if(tex->texture<=0)
|
|
{
|
|
raydium_log("live: ERROR: cannot create 'faked' texture (see above)");
|
|
return -1;
|
|
}
|
|
|
|
tex->device=dev;
|
|
tex->data_source=dev->buffer2;
|
|
tex->state=1;
|
|
raydium_log("live: %s linked to %s (live)",dev->name,as);
|
|
return id;
|
|
#else
|
|
raydium_log("live: Live API is not supported under win32 yet");
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
void raydium_live_texture_refresh(int livetex)
|
|
{
|
|
raydium_live_Texture *tex;
|
|
int (*f)(unsigned char *data, int tx, int ty, int bpp);
|
|
|
|
if(!raydium_live_texture_isvalid(livetex))
|
|
{
|
|
raydium_log("live: cannot refresh live texture: wrong name or id");
|
|
return;
|
|
}
|
|
|
|
tex=&raydium_live_texture[livetex];
|
|
|
|
f=tex->OnRefresh;
|
|
if(f && !f(tex->data_source,tex->tx,tex->ty,tex->bpp))
|
|
return;
|
|
|
|
//printf("%i - %ix%i %i bpp\n",tex->texture,tex->tx,tex->ty,tex->bpp);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D,tex->texture);
|
|
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,
|
|
tex->tx,
|
|
tex->ty,
|
|
(tex->bpp==24?GL_RGB:GL_RGBA),
|
|
GL_UNSIGNED_BYTE,
|
|
tex->data_source);
|
|
}
|
|
|
|
|
|
|
|
void raydium_live_texture_refresh_name(char *texture)
|
|
{
|
|
raydium_live_texture_refresh(raydium_live_texture_find(raydium_texture_find_by_name(texture)));
|
|
}
|
|
|
|
|
|
int raydium_live_texture_create(char *as, unsigned char *data_source, int tx, int ty, int bpp)
|
|
{
|
|
int id,i;
|
|
raydium_live_Texture *tex;
|
|
|
|
id=raydium_live_texture_find_free();
|
|
|
|
if(id<0)
|
|
{
|
|
raydium_log("live: ERROR: no more free live texture slot available (max: %i)",RAYDIUM_MAX_LIVE_TEXTURES);
|
|
return -1;
|
|
}
|
|
|
|
if(bpp!=24 && bpp!=32)
|
|
{
|
|
raydium_log("live: ERROR: live textures are limited to 24 or 32 bpp color depth only, for now");
|
|
return -1;
|
|
}
|
|
|
|
|
|
// duplicated ?
|
|
for(i=0;i<raydium_texture_index;i++)
|
|
if(!strcmp(raydium_texture_name[i],as))
|
|
{
|
|
raydium_log("live: WARNING ! %s is duplicated",as);
|
|
// this is the right answer only if duplicated texture
|
|
// is already a "live" one ! (to fix ?)
|
|
|
|
id=raydium_live_texture_find(i);
|
|
// ... but reset/update some values
|
|
tex=&raydium_live_texture[id];
|
|
tex->device=NULL;
|
|
tex->data_source=data_source;
|
|
|
|
raydium_live_texture_refresh(id);
|
|
return id;
|
|
}
|
|
|
|
|
|
tex=&raydium_live_texture[id];
|
|
tex->tx=tx;
|
|
tex->ty=ty;
|
|
tex->hardware_tx=raydium_trigo_pow2_next(tex->tx);
|
|
tex->hardware_ty=raydium_trigo_pow2_next(tex->ty);
|
|
tex->bpp=bpp;
|
|
tex->texture=raydium_texture_load_internal("not needed :)",as,1,0,0,0,id);
|
|
|
|
if(tex->texture<=0)
|
|
{
|
|
raydium_log("live: ERROR: cannot create 'faked' texture (see above)");
|
|
return -1;
|
|
}
|
|
|
|
tex->device=NULL;
|
|
tex->data_source=data_source;
|
|
tex->state=1;
|
|
raydium_live_texture_refresh(id);
|
|
raydium_log("live: texture '%s' created",as);
|
|
return id;
|
|
}
|
|
|
|
void raydium_live_texture_mask(int livetex, GLfloat alpha)
|
|
{
|
|
raydium_live_Texture *tex;
|
|
GLfloat u,v;
|
|
|
|
if(!raydium_live_texture_isvalid(livetex))
|
|
{
|
|
raydium_log("live: cannot draw live mask: wrong name or id");
|
|
return;
|
|
}
|
|
|
|
tex=&raydium_live_texture[livetex];
|
|
|
|
u=tex->tx/(float)tex->hardware_tx;
|
|
v=tex->ty/(float)tex->hardware_ty;
|
|
|
|
//raydium_osd_mask_texture_clip(tex->texture,alpha,u*100,v*100,0,0);
|
|
raydium_osd_mask_texture_clip(tex->texture,alpha,0,v*100,u*100,0);
|
|
}
|
|
|
|
|
|
void raydium_live_texture_mask_name(char *texture, GLfloat alpha)
|
|
{
|
|
raydium_live_texture_mask(raydium_live_texture_find(raydium_texture_find_by_name(texture)),alpha);
|
|
}
|
|
|
|
|
|
// (the current code of this function is quiet a hack ...)
|
|
void raydium_live_texture_draw(int livetex, GLfloat alpha,GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
|
|
{
|
|
raydium_live_Texture *tex;
|
|
GLfloat u,v;
|
|
|
|
if(!raydium_live_texture_isvalid(livetex))
|
|
{
|
|
raydium_log("live: cannot draw live mask: wrong name or id");
|
|
return;
|
|
}
|
|
|
|
tex=&raydium_live_texture[livetex];
|
|
|
|
u=tex->tx/(float)tex->hardware_tx;
|
|
v=tex->ty/(float)tex->hardware_ty;
|
|
|
|
raydium_osd_start();
|
|
|
|
raydium_texture_current_set(tex->texture);
|
|
raydium_rendering_internal_prepare_texture_render(tex->texture);
|
|
glColor4f(1,1,1,alpha);
|
|
glEnable(GL_BLEND);
|
|
glDepthMask(GL_FALSE);
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0,v);
|
|
glVertex3f(x1,y1,0);
|
|
glTexCoord2f(u,v);
|
|
glVertex3f(x2,y1,0);
|
|
glTexCoord2f(u,0);
|
|
glVertex3f(x2,y2,0);
|
|
glTexCoord2f(0,0);
|
|
glVertex3f(x1,y2,0);
|
|
glEnd();
|
|
raydium_rendering_internal_restore_render_state();
|
|
|
|
raydium_osd_stop();
|
|
}
|
|
|
|
|
|
void raydium_live_texture_draw_name(char *texture, GLfloat alpha,GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
|
|
{
|
|
raydium_live_texture_draw(raydium_live_texture_find(raydium_texture_find_by_name(texture)),alpha,x1,y1,x2,y2);
|
|
}
|
|
|
|
void raydium_live_texture_refresh_callback_set(int livetex, void *callback)
|
|
{
|
|
raydium_live_Texture *tex;
|
|
|
|
if(!raydium_live_texture_isvalid(livetex))
|
|
{
|
|
raydium_log("live: cannot set OnRefresh callback: wrong name or id");
|
|
return;
|
|
}
|
|
|
|
tex=&raydium_live_texture[livetex];
|
|
tex->OnRefresh=callback;
|
|
}
|
|
|
|
void raydium_live_texture_refresh_callback_set_name(char *texture, void *callback)
|
|
{
|
|
raydium_live_texture_refresh_callback_set(raydium_live_texture_find(raydium_texture_find_by_name(texture)),callback);
|
|
}
|
|
|
|
|