⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 surface.cpp

📁 一个symbian 冒险游戏代码
💻 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 + -