📄 blit_soft.c
字号:
/*****************************************************************************
*
* 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
*
* $Id: blit_soft.c 202 2005-01-25 01:27:33Z picard $
*
* BetaPlayer Blit
* Copyright (c) 2004 Gabor Kovacs
*
****************************************************************************/
#include "../stdafx.h"
#include "../dyncode/dyncode.h"
#include "blit_soft.h"
#define SAT(Value) (Value < 0 ? 0: (Value > 255 ? 255: Value))
static rgb Gray1[2] = {
{0,0,0},{255,255,255}
};
static rgb Gray2[4] = {
{0,0,0},{85,85,85},{170,170,170},{255,255,255}
};
static rgb Gray4[16] = {
{0,0,0},{17,17,17},{34,34,34},{51,51,51},
{68,68,68},{85,85,85},{102,102,102},{119,119,119},
{136,136,136},{153,153,153},{170,170,170},{187,187,187},
{204,204,204},{221,221,221},{238,238,238},{255,255,255}
};
typedef struct blitpack
{
blitfx FX;
video Dst;
video Src;
rect DstRect;
rect SrcRect;
blit_soft Code[2];
struct blitpack* Next;
int RScaleX;
int RScaleY;
int SrcAlignPos;
int DstAlignPos;
int DstAlignSize;
bool_t SafeBorder;
} blitpack;
static blitpack* BlitPack = NULL;
void FreeBlit( blit_soft* p)
{
CodeDone(&p->Code);
Free(p->LookUp_Data);
p->LookUp_Data = NULL;
}
void Blit_Init()
{
}
void Blit_Done()
{
blitpack* q;
blitpack* p;
for (p=BlitPack;p;p=q)
{
q = p->Next;
FreeBlit(&p->Code[0]);
FreeBlit(&p->Code[1]);
Free(p);
}
BlitPack = NULL;
}
static const rgb* DefaultPal( const pixel* Format )
{
if (Format->Flags & PF_PALETTE)
{
if (!Format->Palette)
switch (Format->BitCount)
{
case 1: return Gray1;
case 2: return Gray2;
case 4: return Gray4;
}
return Format->Palette;
}
return NULL;
}
int CalcScale( int v, int Min, int Max )
{
if (v > Max) v = Max;
if (v < Min) v = Min;
return v;
}
int CalcRScale( int v, int Gray )
{
if (v<=0) return 16;
v = (16*1024 << 16) / v;
if (Gray) // only 100% and 200% scale
return v > 12288 ? 16:8;
//align to 100%
if (v > 16834-1024 && v < 16384+1024)
v = 16384;
//align to 200%
if (v > 8192-1024 && v < 8192+1024)
v = 8192;
//align to 50%
if (v > 32768-1024 && v < 32768+1024)
v = 32768;
#if defined(SH3)
if (v < 12288)
return 8;
return 16;
// if (v<1024) v=1024;
// return ((v+1024) >> 11) << 1;
#else
if (v<512) v=512;
return (v+512) >> 10;
#endif
}
void* BlitCreate( const video* Dst,
const video* Src, const blitfx* FX, int* OutCaps )
{
bool_t Gray;
int Caps = VC_BRIGHTNESS|VC_DITHER|VC_SATURATION|VC_CONTRAST|VC_RGBADJUST;
blitpack* p = BlitPack;
if (p)
BlitPack = p->Next;
else
{
p = (blitpack*) CAlloc(sizeof(blitpack),1);
if (!p)
return NULL;
CodeInit(&p->Code[0].Code);
CodeInit(&p->Code[1].Code);
}
if (!BlitCompile(&p->Code[0],Dst,Src,FX,0) ||
((FX->Flags & BLITFX_ONLYDIFF) && !BlitCompile(&p->Code[1],Dst,Src,FX,1)))
{
p->Next = BlitPack;
BlitPack = p;
return NULL;
}
p->FX = *FX;
p->Dst = *Dst;
p->Src = *Src;
Gray = (Dst->Pixel.Flags & PF_PALETTE) &&
(Dst->Pixel.BitCount == 4 || Dst->Pixel.BitCount == 2);
p->RScaleX = CalcRScale(FX->ScaleX,Gray);
p->RScaleY = CalcRScale(FX->ScaleY,Gray);
// default alignment
p->SrcAlignPos = 2;
p->DstAlignPos = 2;
p->DstAlignSize = 2;
if (Gray && Dst->Pixel.BitCount == 2) // arm_gray, mips_gray, sh3_gray
p->DstAlignPos = p->DstAlignSize = 4;
#if defined(ARM)
else
if (PlanarYUV(&Dst->Pixel,NULL,NULL,NULL)) // arm_yuv
{
p->SrcAlignPos = p->DstAlignPos = p->DstAlignSize = 8;
Caps = VC_BRIGHTNESS;
}
else
if (p->Code[0].WMMX && PlanarYUV420(&Src->Pixel) &&
(p->RScaleX==16 || p->RScaleX==8 || p->RScaleX==32) && (p->RScaleY==16 || p->RScaleY==8 || p->RScaleY==32))
{
p->SrcAlignPos = p->DstAlignPos = p->DstAlignSize = 8;
if (p->RScaleX==8) p->DstAlignSize = 16;
}
else
if (PlanarYUV420(&Src->Pixel) && p->RScaleX == 32 && p->RScaleY == 32) //arm_half
p->DstAlignPos = p->DstAlignSize = 4;
else
if (PlanarYUV420(&Src->Pixel) &&
(p->RScaleX == 8 || p->RScaleY == 8) && //arm_fix with double
(p->RScaleX == 8 || p->RScaleX == 16) &&
(p->RScaleY == 8 || p->RScaleY == 16) && !p->Code[0].ArithStretch)
p->DstAlignSize = 4;
#elif defined(SH3) || defined(MIPS)
if (p->RScaleX == 8 || p->RScaleY == 8) //sh3_fix,mips_fix
p->DstAlignSize = 4;
#else
// universal
Caps = VC_BRIGHTNESS | VC_DITHER;
if (AnyYUV(&Dst->Pixel))
Caps &= ~VC_DITHER;
#endif
if (OutCaps)
*OutCaps = Caps;
return p;
}
void BlitAlign( void* Handle, rect* DstRect, rect* SrcRect )
{
int i;
int ShrinkX,ShrinkY;
int SrcRight;
int SrcBottom;
int SrcAdjWidth,SrcAdjHeight;
blitpack* p = Handle;
int RScaleX,RScaleY;
if (!p) return;
RScaleX = p->RScaleX;
RScaleY = p->RScaleY;
p->SafeBorder = 0;
if (p->Code[0].ArithStretch && (RScaleX != 16) && (RScaleX != 32))
{
//avoid bilinear scale overrun (shrink source)
if ((p->Src.Pixel.Flags & PF_SAFEBORDER) && p->DstAlignSize > 2)
p->SafeBorder = 1; // build a one pixel border before blitting on right and bottom side
else
{
//only horizontal bilinear filtering is supported (arm_stretch)
if (SrcRect->Width>2)
SrcRect->Width -= 2;
}
}
SrcRight = SrcRect->x + SrcRect->Width;
SrcBottom = SrcRect->y + SrcRect->Height;
// convert source to destination space
if (p->FX.Direction & DIR_SWAPXY)
{
SwapInt(&RScaleX,&RScaleY);
SwapRect(SrcRect);
}
SrcAdjWidth = SrcRect->Width * 16 / RScaleX;
SrcAdjHeight = SrcRect->Height * 16 / RScaleY;
ShrinkX = DstRect->Width - SrcAdjWidth;
if (ShrinkX>=0) //shrink destination?
{
ShrinkX >>= 1;
DstRect->x += ShrinkX;
DstRect->Width = SrcAdjWidth;
}
else //adjust source position
{
ShrinkX = 0;
SrcRect->x += (SrcAdjWidth - DstRect->Width) * RScaleX >> 5;
SrcRect->Width = -1; // need calc
}
ShrinkY = DstRect->Height - SrcAdjHeight;
if (ShrinkY>=0) //shrink Dst?
{
ShrinkY >>= 1;
DstRect->y += ShrinkY;
DstRect->Height = SrcAdjHeight;
}
else //adjust source position
{
ShrinkY = 0;
SrcRect->y += (SrcAdjHeight - DstRect->Height) * RScaleY >> 5;
SrcRect->Height = -1; // need calc
}
i = DstRect->Width & (p->DstAlignSize-1);
DstRect->Width -= i;
i >>= 1;
ShrinkX += i;
DstRect->x += i;
i = DstRect->Height & (p->DstAlignSize-1);
DstRect->Height -= i;
i >>= 1;
ShrinkY += i;
DstRect->y += i;
i = DstRect->x & (p->DstAlignPos-1);
if (i && ShrinkX < i)
{
DstRect->Width -= p->DstAlignPos - i;
DstRect->Width &= ~(p->DstAlignSize-1);
DstRect->x += p->DstAlignPos - i;
}
else
DstRect->x -= i;
i = DstRect->y & (p->DstAlignPos-1);
if (i && ShrinkY < i)
{
DstRect->Height -= p->DstAlignPos - i;
DstRect->Height &= ~(p->DstAlignSize-1);
DstRect->y += p->DstAlignPos - i;
}
else
DstRect->y -= i;
SrcRect->x &= ~(p->SrcAlignPos-1);
SrcRect->y &= ~(p->SrcAlignPos-1);
// convert source back to it's space (if needed)
if (SrcRect->Width < 0)
SrcRect->Width = (DstRect->Width * RScaleX / 16 + 1) & ~1;
if (SrcRect->Height < 0)
SrcRect->Height = (DstRect->Height * RScaleY / 16 + 1) & ~1;
if (p->FX.Direction & DIR_SWAPXY)
SwapRect(SrcRect);
if (SrcRect->x + SrcRect->Width > SrcRight)
SrcRect->Width = SrcRight - SrcRect->x;
if (SrcRect->y + SrcRect->Height > SrcBottom)
SrcRect->Height = SrcBottom - SrcRect->y;
p->DstRect = *DstRect;
p->SrcRect = *SrcRect;
}
void BlitRelease(void* Handle)
{
blitpack* p = (blitpack*)Handle;
if (p)
{
p->Next = BlitPack;
BlitPack = p;
}
}
int AnyAlign( rect* DstRect, rect* SrcRect, const blitfx* FX,
int DstAlignSize, int DstAlignPos,
int MinScale, int MaxScale )
{
int i,ShrinkX,ShrinkY;
int ScaleX,ScaleY;
int SrcRight;
int SrcBottom;
int SrcAdjWidth,SrcAdjHeight;
if (!DstRect || !SrcRect || !FX)
return ERR_INVALID_PARAM;
ScaleX = CalcScale(FX->ScaleX,MinScale,MaxScale);
ScaleY = CalcScale(FX->ScaleY,MinScale,MaxScale);
SrcRight = SrcRect->x + SrcRect->Width;
SrcBottom = SrcRect->y + SrcRect->Height;
// convert source to destination space
if (FX->Direction & DIR_SWAPXY)
{
SwapInt(&ScaleX,&ScaleY);
SwapRect(SrcRect);
}
SrcAdjWidth = (SrcRect->Width * ScaleX + 32768 ) >> 16;
SrcAdjHeight = (SrcRect->Height * ScaleY + 32768 ) >> 16;
ShrinkX = DstRect->Width - SrcAdjWidth;
if (ShrinkX>0) //shrink destination?
{
ShrinkX >>= 1;
DstRect->x += ShrinkX;
DstRect->Width = SrcAdjWidth;
}
else //adjust source position
{
ShrinkX = 0;
SrcRect->x += ((SrcAdjWidth - DstRect->Width) << 15) / ScaleX;
SrcRect->Width = -1;
}
ShrinkY = DstRect->Height - SrcAdjHeight;
if (ShrinkY>0) //shrink Dst?
{
ShrinkY >>= 1;
DstRect->y += ShrinkY;
DstRect->Height = SrcAdjHeight;
}
else //adjust source position
{
ShrinkY = 0;
SrcRect->y += ((SrcAdjHeight - DstRect->Height) << 15) / ScaleY;
SrcRect->Height = -1;
}
// final alignment
i = DstRect->Width & (DstAlignSize-1);
DstRect->Width -= i;
i >>= 1;
ShrinkX += i;
DstRect->x += i;
i = DstRect->Height & (DstAlignSize-1);
DstRect->Height -= i;
i >>= 1;
ShrinkY += i;
DstRect->y += i;
i = DstRect->x & (DstAlignPos-1);
if (i && ShrinkX < i)
{
DstRect->Width -= DstAlignPos - i;
DstRect->Width &= ~(DstAlignSize-1);
DstRect->x += DstAlignPos - i;
}
else
DstRect->x -= i;
i = DstRect->y & (DstAlignPos-1);
if (i && ShrinkY < i)
{
DstRect->Height -= DstAlignPos - i;
DstRect->Height &= ~(DstAlignSize-1);
DstRect->y += DstAlignPos - i;
}
else
DstRect->y -= i;
SrcRect->x &= ~1;
SrcRect->y &= ~1;
if (SrcRect->Width < 0)
SrcRect->Width = ((DstRect->Width << 16) / ScaleX +1) & ~1;
if (SrcRect->Height < 0)
SrcRect->Height = ((DstRect->Height << 16) / ScaleY +1) & ~1;
if (FX->Direction & DIR_SWAPXY)
SwapRect(SrcRect);
if (SrcRect->x + SrcRect->Width > SrcRight)
SrcRect->Width = SrcRight - SrcRect->x;
if (SrcRect->y + SrcRect->Height > SrcBottom)
SrcRect->Height = SrcBottom - SrcRect->y;
return ERR_NONE;
}
void SafeBorder( const planes Planes, const video* Format )
{
//!!!
}
static INLINE void SurfacePtr( uint8_t** Ptr, const planes Planes, const video* Format, int BPP, int x, int y, int Pitch)
{
int Adj = (x & 1) << 1;
Ptr[0] = (uint8_t*)Planes[0] + ((x * BPP) >> 3) + y * Pitch;
if (Format->Pixel.Flags & (PF_YUV420|PF_YUV422|PF_YUV444))
{
if (Format->Pixel.Flags & PF_YUV420)
{
Ptr[1] = (uint8_t*)Planes[1] + (x >> 1) + (y >> 1) * (Pitch >> 1);
Ptr[2] = (uint8_t*)Planes[2] + (x >> 1) + (y >> 1) * (Pitch >> 1);
}
else
if (Format->Pixel.Flags & PF_YUV422)
{
Ptr[1] = (uint8_t*)Planes[1] + (x >> 1) + y * (Pitch >> 1);
Ptr[2] = (uint8_t*)Planes[2] + (x >> 1) + y * (Pitch >> 1);
}
else
if (Format->Pixel.Flags & PF_YUV444)
{
Ptr[1] = (uint8_t*)Planes[1] + x + y * Pitch;
Ptr[2] = (uint8_t*)Planes[2] + x + y * Pitch;
}
}
else
if (Format->Pixel.Flags & PF_FOURCC)
switch (Format->Pixel.FourCC)
{
case FOURCC_IMC2:
Ptr[2] = (uint8_t*)Planes[0] + Format->Height * Pitch + (x >> 1) + (y >> 1) * Pitch;
Ptr[1] = Ptr[1] + (Pitch >> 1);
break;
case FOURCC_IMC4:
Ptr[1] = (uint8_t*)Planes[0] + Format->Height * Pitch + (x >> 1) + (y >> 1) * Pitch;
Ptr[2] = Ptr[1] + (Pitch >> 1);
break;
case FOURCC_I420:
case FOURCC_IYUV:
Ptr[1] = (uint8_t*)Planes[0] + Format->Height * Pitch + (x >> 1) + (y >> 1) * (Pitch >> 1);
Ptr[2] = Ptr[1] + ((Format->Height * Pitch) >> 2);
break;
case FOURCC_YV16:
Ptr[2] = (uint8_t*)Planes[0] + Format->Height * Pitch + (x >> 1) + y * (Pitch >> 1);
Ptr[1] = Ptr[2] + ((Format->Height * Pitch) >> 1);
break;
case FOURCC_YV12:
Ptr[2] = (uint8_t*)Planes[0] + Format->Height * Pitch + (x >> 1) + (y >> 1) * (Pitch >> 1);
Ptr[1] = Ptr[2] + ((Format->Height * Pitch) >> 2);
break;
case FOURCC_YUY2:
case FOURCC_YUNV:
case FOURCC_V422:
case FOURCC_YUYV:
Ptr[1] = Ptr[0]+1-Adj;
Ptr[2] = Ptr[0]+3-Adj;
break;
case FOURCC_YVYU:
Ptr[1] = Ptr[0]+3-Adj;
Ptr[2] = Ptr[0]+1-Adj;
break;
case FOURCC_UYVY:
case FOURCC_Y422:
case FOURCC_UYNV:
Ptr[1] = Ptr[0]-Adj;
Ptr[2] = Ptr[0]+2-Adj;
Ptr[0]++;
break;
case FOURCC_VYUY:
Ptr[2] = Ptr[0]-Adj;
Ptr[1] = Ptr[0]+2-Adj;
Ptr[0]++;
break;
}
}
void BlitImage( void* Handle, const planes Dst, const planes Src, const planes SrcLast, int DstPitch, int SrcPitch )
{
blitpack* Pack = (blitpack*)Handle;
uint8_t* DstPtr[MAXPLANES];
uint8_t* SrcPtr[MAXPLANES];
bool_t OnlyDiff;
int Width,Height;
blit_soft* p;
int Src2SrcLast;
int DstStepX;
int DstStepY;
int DstX;
int DstY;
int SrcY;
// nothing to do?
if (!Pack || Pack->DstRect.Width<=0 || Pack->DstRect.Height<=0)
return;
OnlyDiff = (Pack->FX.Flags & BLITFX_ONLYDIFF) && SrcLast && SrcLast[0] != NULL;
p = &Pack->Code[OnlyDiff];
// calculate the Src and Dst pointers
// Src: always upperleft corner
// Dst: according to swapxy and mirroring
Width = Pack->DstRect.Width;
Height = Pack->DstRect.Height;
if (p->SwapXY)
SwapInt(&Width,&Height);
if (DstPitch < 0)
DstPitch = Pack->Dst.Pitch;
if (SrcPitch < 0)
SrcPitch = Pack->Src.Pitch;
SrcY = Pack->SrcRect.y;
if (p->SrcUpDown)
SrcY += Pack->SrcRect.Height-1;
if (Pack->SafeBorder)
SafeBorder(Src,&Pack->Src);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -