📄 surface.cpp
字号:
#include "Surface.h"
#include <gr/SurfaceFormat.h>
#include <io/OutputStream.h>
#include <io/FileInputStream.h>
#include <io/FileOutputStream.h>
#include <io/IOException.h>
#include <img/ImageReader.h>
#include <lang/Globals.h>
#include <assert.h>
#include <config.h>
using namespace gr;
using namespace io;
using namespace img;
using namespace lang;
Surface::Surface() :
m_data( 0 ),
m_pitch( 0 ),
m_width( 0 ),
m_height( 0 ),
m_frames( 0 ),
m_framerate( 0 ),
m_framew( 0 ),
m_frameh( 0 ),
m_offx( 0 ),
m_offy( 0 ),
m_viewportx0( 0 ),
m_viewporty0( 0 ),
m_flags( 0 ),
m_frameRateModifier( Fixf(1) ),
m_reversed( false )
{
calculateEndTime();
}
Surface::Surface( void* data, int pitch, int width, int height ) :
m_data( (uint8_t*)data ),
m_pitch( (uint16_t)pitch ),
m_width( (uint16_t)width ),
m_height( (uint16_t)height ),
m_frames( 1 ),
m_framerate( 1 ),
m_framew( (uint16_t)width ),
m_frameh( (uint16_t)height ),
m_offx( 0 ),
m_offy( 0 ),
m_viewportx0( 0 ),
m_viewporty0( 0 ),
m_flags( 0 ),
m_frameRateModifier( Fixf(1) )
{
calculateEndTime();
}
Surface::Surface( const Surface& other, int flags )
{
*this = other;
m_flags = flags;
calculateEndTime();
}
void Surface::setViewport( int x0, int y0 )
{
m_viewportx0 = x0;
m_viewporty0 = y0;
}
void Surface::destroy()
{
delete[] m_data;
m_data = 0;
}
void Surface::blt( int dstx, int dsty, const Surface& src, BlendType blend )
{
blt( dstx, dsty, &src, blend );
}
void Surface::blt( int dstx, int dsty, const Surface* src, BlendType blend )
{
dstx -= m_viewportx0;
dsty -= m_viewporty0;
// clip
int dstx0 = dstx;
int dsty0 = dsty;
int dstw = m_width;
int dsth = m_height;
int dstx1 = dstx0 + src->m_width;
int dsty1 = dsty0 + src->m_height;
if ( dstx1 < 0 )
return;
if ( dsty1 < 0 )
return;
if ( dstx0 > dstw )
return;
if ( dsty0 > dsth )
return;
if ( dstx1 > dstw )
dstx1 = dstw;
if ( dsty1 > dsth )
dsty1 = dsth;
if ( dstx0 < 0 )
dstx0 = 0;
if ( dsty0 < 0 )
dsty0 = 0;
if ( dstx0 >= dstx1 || dsty0 >= dsty1 )
return;
int srcx0 = dstx0 - dstx;
int srcy0 = dsty0 - dsty;
if ( src->m_flags & FLAG_MIRROR )
{
int offset = (dstx+src->m_width);
if ( offset > dstw )
{
offset -= dstx1;
if ( offset > 0 )
srcx0 += offset;
}
if ( dstx < 0 )
{
srcx0 = 0;
}
}
const int srcpitch = src->m_pitch;
const int srcpixelsize = 2;
const int dstpixelsize = 2;
const int dstpitch = m_pitch;
uint8_t* dstdata = m_data + dsty0*dstpitch + dstx0*dstpixelsize;
const uint8_t* srcdata = src->m_data + srcy0*srcpitch + srcx0*srcpixelsize;
const int w = dstx1 - dstx0;
register int dk = (src->m_flags & FLAG_MIRROR) ? -1 : 1;
register int k0 = (src->m_flags & FLAG_MIRROR) ? w-1 : 0;
switch ( blend )
{
case BLEND_COPY:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
register const uint16_t* s = (const uint16_t*)srcdata;
register int k = k0;
for ( register int i = 0 ; i < w ; ++i )
{
assert( isValid(d+k) );
assert( src->isValid(s+i) );
d[k] = s[i];
k += dk;
}
dstdata += dstpitch;
srcdata += srcpitch;
}
break;
case BLEND_ALPHA:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
register const uint16_t* s = (const uint16_t*)srcdata;
register int k = k0;
for ( register int i = 0 ; i < w ; ++i )
{
assert( src->isValid(s+i) );
assert( isValid(d+k) );
register int sa = s[i]>>12;
register int invsa = 16 - sa;
register int dr = ((d[k] >> 8) & 0xF)*invsa >> 4;
register int dg = ((d[k] >> 4) & 0xF)*invsa >> 4;
register int db = ((d[k]) & 0xF)*invsa >> 4;
register int sr = ((s[i] >> 8) & 0xF)*sa >> 4;
register int sg = ((s[i] >> 4) & 0xF)*sa >> 4;
register int sb = ((s[i]) & 0xF)*sa >> 4;
dr += sr;
dg += sg;
db += sb;
if ( dr > 15 )
dr = 15;
if ( dg > 15 )
dg = 15;
if ( db > 15 )
db = 15;
d[k] = (uint16_t)( ((dr)<<8) + ((dg)<<4) + (db) );
k += dk;
}
dstdata += dstpitch;
srcdata += srcpitch;
}
break;
case BLEND_ALPHA1B:
for ( int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
register const uint16_t* s = (const uint16_t*)srcdata;
register int k = k0;
for ( register int i = 0 ; i < w ; ++i )
{
assert( src->isValid(s+i) );
assert( isValid(d+k) );
if ( s[i] & 0xF000 )
d[k] = s[i];
k += dk;
}
dstdata += dstpitch;
srcdata += srcpitch;
}
break;
case BLEND_ADD:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
register const uint16_t* s = (const uint16_t*)srcdata;
register int k = k0;
for ( register int i = 0 ; i < w ; ++i )
{
assert( src->isValid(s+i) );
assert( isValid(d+i) );
register int dr = ((d[k] >> 8) & 0xF);
register int dg = ((d[k] >> 4) & 0xF);
register int db = ((d[k]) & 0xF);
register int sr = ((s[i] >> 8) & 0xF);
register int sg = ((s[i] >> 4) & 0xF);
register int sb = ((s[i]) & 0xF);
dr += sr;
dg += sg;
db += sb;
if ( dr > 15 )
dr = 15;
if ( dg > 15 )
dg = 15;
if ( db > 15 )
db = 15;
d[k] = (uint16_t)( ((dr)<<8) + ((dg)<<4) + (db) );
k += dk;
}
dstdata += dstpitch;
srcdata += srcpitch;
}
break;
}
}
void Surface::fill( int x, int y, int w, int h, int argb4444, BlendType blend )
{
x -= m_viewportx0;
y -= m_viewporty0;
// clip: x,y,w,h -> dstx0,dstx1,dsty0,dsty1
int dstx = x;
int dsty = y;
int dstx0 = dstx;
int dsty0 = dsty;
int dstw = m_width;
int dsth = m_height;
int dstx1 = dstx0 + w;
int dsty1 = dsty0 + h;
if ( dstx1 > dstw )
dstx1 = dstw;
if ( dsty1 > dsth )
dsty1 = dsth;
if ( dstx1 < 0 )
dstx1 = 0;
if ( dsty1 < 0 )
dsty1 = 0;
if ( dstx0 > dstw )
dstx0 = dstw;
if ( dsty0 > dsth )
dsty0 = dsth;
if ( dstx0 < 0 )
dstx0 = 0;
if ( dsty0 < 0 )
dsty0 = 0;
if ( dstx0 >= dstx1 || dsty0 >= dsty1 )
return;
const int dstpitch = m_pitch;
const int dstpixelsize = 2;
uint8_t* dstdata = m_data + dsty0*dstpitch + dstx0*dstpixelsize;
w = dstx1 - dstx0;
int sa = argb4444>>12;
int invsa = 16 - sa;
int sr = ((argb4444 >> 8) & 0xF);
int sg = ((argb4444 >> 4) & 0xF);
int sb = ((argb4444) & 0xF);
int srp = sr*sa >> 4;
int sgp = sg*sa >> 4;
int sbp = sb*sa >> 4;
switch ( blend )
{
case BLEND_COPY:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
for ( register int i = 0 ; i < w ; ++i )
{
assert( isValid(d+i) );
d[i] = (uint16_t)argb4444;
}
dstdata += dstpitch;
}
break;
case BLEND_ALPHA:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
for ( register int i = 0 ; i < w ; ++i )
{
assert( isValid(d+i) );
register int dr = ((d[i] >> 8) & 0xF)*invsa >> 4;
register int dg = ((d[i] >> 4) & 0xF)*invsa >> 4;
register int db = ((d[i]) & 0xF)*invsa >> 4;
dr += srp;
dg += sgp;
db += sbp;
if ( dr > 15 )
dr = 15;
if ( dg > 15 )
dg = 15;
if ( db > 15 )
db = 15;
d[i] = (uint16_t)( ((dr)<<8) + ((dg)<<4) + (db) );
}
dstdata += dstpitch;
}
break;
case BLEND_ALPHA1B:
if ( argb4444 & 0xF000 )
{
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
for ( register int i = 0 ; i < w ; ++i )
{
assert( isValid(d+i) );
d[i] = (uint16_t)argb4444;
}
dstdata += dstpitch;
}
}
break;
case BLEND_ADD:
for ( register int y = dsty0 ; y < dsty1 ; ++y )
{
register uint16_t* d = (uint16_t*)dstdata;
for ( register int i = 0 ; i < w ; ++i )
{
assert( isValid(d+i) );
register int dr = ((d[i] >> 8) & 0xF);
register int dg = ((d[i] >> 4) & 0xF);
register int db = ((d[i]) & 0xF);
dr += sr;
dg += sg;
db += sb;
if ( dr > 15 )
dr = 15;
if ( dg > 15 )
dg = 15;
if ( db > 15 )
db = 15;
d[i] = (uint16_t)( ((dr)<<8) + ((dg)<<4) + (db) );
}
dstdata += dstpitch;
}
break;
}
}
bool Surface::isValid( const void* p ) const
{
const uint8_t* d = (const uint8_t*)p;
return d>=m_data && d<m_data+int(m_pitch)*int(m_height);
}
void Surface::load( const char* fname, ImageResample* imageResamplingEngine, bool halfResolution )
{
FileInputStream fin( fname );
ImageReader reader( &fin, ImageReader::guessFileFormat(fname) );
reader.nextSurface();
int w = reader.surfaceWidth();
int h = reader.surfaceHeight();
SurfaceFormat fmt = SurfaceFormat::SURFACE_A4R4G4B4;
int pitch = w * ( fmt.bitsPerPixel()/8 );
uint8_t* data = 0;
calculateEndTime();
if ( !halfResolution )
{
data = new uint8_t[h*pitch];
reader.readSurface( data, pitch, w, h, fmt, 0, SurfaceFormat() );
}
else
{
//Load to resampling engine buffer
uint8_t* dst = imageResamplingEngine->getBuffer( h * pitch );
reader.readSurface( dst, pitch, w, h, fmt, 0, SurfaceFormat() );
//Resample half x half
const int sourceWidth = w;
const int sourceHeight = h;
const int sourcePitch = pitch;
w >>= 1;
h >>= 1;
pitch = w * ( fmt.bitsPerPixel()/8 );
data = new uint8_t[h*pitch];
imageResamplingEngine->resampleHalf( data, w, h, pitch, sourceWidth, sourceHeight, sourcePitch, 0, 0 );
}
*this = Surface( data, pitch, w, h );
}
void Surface::loadCustom( const char* fname, ImageResample* imageResamplingEngine, bool halfResolution )
{
FileInputStream fin( fname );
InputStream* in = &fin;
uint16_t ver;
in->read( &ver, sizeof(ver) );
if ( ver != 0x100 )
throwError( IOException(Format("{0} wrong version", fname)) );
TRACEF(1);
in->read( &m_frames, sizeof(m_frames) );
in->read( &m_framew, sizeof(m_framew) );
in->read( &m_frameh, sizeof(m_frameh) );
in->read( &m_framerate, sizeof(m_framerate) );
in->read( &m_offx, sizeof(m_offx) );
in->read( &m_offy, sizeof(m_offy) );
in->read( &m_pitch, sizeof(m_pitch) );
in->read( &m_width, sizeof(m_width) );
in->read( &m_height, sizeof(m_height) );
assert( m_pitch > 0 );
assert( m_width > 0 );
assert( m_height > 0 );
assert( m_pitch <= 1024*2 );
assert( m_width <= 1024 );
assert( m_height <= 1024 );
calculateEndTime();
m_data = 0;
if ( !halfResolution )
{
int bytes = m_height * m_pitch;
m_data = new uint8_t[bytes];
assert( m_data != 0 );
in->read( m_data, bytes );
}
else
{
//Load to resampling engine buffer
int bytes = m_height * m_pitch;
uint8_t* dst = imageResamplingEngine->getBuffer( bytes );
in->read( dst, bytes );
//Resample half x half
const SurfaceFormat fmt = SurfaceFormat::SURFACE_A4R4G4B4;
const int sourceWidth = m_width;
const int sourceHeight = m_height;
const int sourcePitch = m_pitch;
const int sourceFrameHeight = m_frameh;
m_framew >>= 1;
m_frameh >>= 1;
m_offx >>= 1;
m_offy >>= 1;
m_width >>= 1;
m_height = m_frames * m_frameh;
m_pitch = (uint16_t) ( m_width * ( fmt.bitsPerPixel()/8 ) );
bytes = m_height * m_pitch;
m_data = new uint8_t[bytes];
imageResamplingEngine->resampleHalf( m_data, m_width, m_height, m_pitch, sourceWidth, sourceHeight, sourcePitch, 0, 0, sourceFrameHeight );
}
TRACEF(1);
}
void Surface::saveCustom( const char* fname )
{
FileOutputStream fout( fname );
OutputStream* out = &fout;
uint16_t ver = 0x100;
out->write( &ver, sizeof(ver) );
out->write( &m_frames, sizeof(m_frames) );
out->write( &m_framew, sizeof(m_framew) );
out->write( &m_frameh, sizeof(m_frameh) );
out->write( &m_framerate, sizeof(m_framerate) );
out->write( &m_offx, sizeof(m_offx) );
out->write( &m_offy, sizeof(m_offy) );
out->write( &m_pitch, sizeof(m_pitch) );
out->write( &m_width, sizeof(m_width) );
out->write( &m_height, sizeof(m_height) );
int bytes = int(m_pitch)*int(m_height);
out->write( m_data, bytes );
}
void Surface::setFrames( int x )
{
m_frames = (uint16_t)x;
calculateEndTime();
}
void Surface::setFramerate( int x )
{
m_framerate = (uint16_t)x;
calculateEndTime();
}
void Surface::setFrameWidth( int x )
{
m_framew = (uint16_t)x;
}
void Surface::setFrameHeight( int x )
{
m_frameh = (uint16_t)x;
}
void Surface::setOffset( int x, int y )
{
m_offx = (uint16_t)x;
m_offy = (uint16_t)y;
}
bool Surface::isRowEmpty( int y ) const
{
if ( y >= 0 && y < (int)m_height )
{
const uint16_t* p = reinterpret_cast<uint16_t*>(m_data + int(m_pitch)*y);
for ( int i = 0 ; i < (int)m_width ; ++i )
if ( p[i] != keyColor() )
return false;
}
return true;
}
bool Surface::isColumnEmpty( int x ) const
{
if ( x >= 0 && x < (int)m_width )
{
int row = 0;
for ( int i = 0 ; i < (int)m_height ; ++i )
{
const uint16_t* p = reinterpret_cast<uint16_t*>(m_data + row) + x;
if ( *p != keyColor() )
return false;
row += m_pitch;
}
}
return true;
}
Surface Surface::clip( int x0, int y0, int x1, int y1 ) const
{
assert( x0 >= 0 && y0 >= 0 );
assert( x0 <= x1 && y0 <= y1 );
assert( x1 <= int(m_width) );
assert( y1 <= int(m_height) );
Surface clipped( *this );
clipped.m_data = m_data + y0*m_pitch + x0*2;
clipped.m_width = uint16_t(x1-x0);
clipped.m_height = uint16_t(y1-y0);
clipped.m_frames = 1;
clipped.m_flags = m_flags;
return clipped;
}
Surface Surface::clipFrame( int i ) const
{
assert( i >= 0 && i < (int)m_frames );
return clip( 0, m_frameh*i, m_framew, m_frameh*(i+1) );
}
void Surface::setViewportPixel( int x, int y, int rgba4444 )
{
x -= m_viewportx0;
y -= m_viewporty0;
if ( x >= 0 && x < m_width &&
y >= 0 && y < m_height )
{
setPixel( x, y, rgba4444 );
}
}
int Surface::getFrame( Fix time ) const
{
Fix t = !m_reversed ? time : m_endTime - time;
if ( t < Fixf(0) ) t = Fixf(0);
int f = ( t * m_frameRateModifier * Fix::fromInt( framerate() ) ).toInt();
assert( f >= 0 );
if ( m_flags & FLAG_END_STOP )
return f > frames()-1 ? frames()-1 : f;
else
return f % frames();
}
void Surface::calculateEndTime()
{
m_endTime = Fixf(0);
if ( m_framerate > 0 )
{
m_endTime = Fix::fromInt(m_frames) / Fix::fromInt(m_framerate);
}
}
// End of File
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -