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

📄 zmbv.cpp

📁 DOSBox emulates a full x86 pc with sound and dos. Its main use is to run old dosgames on platforms w
💻 CPP
字号:
/* *  Copyright (C) 2002-2007  The DOSBox Team * *  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. */#include <zlib.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include "zmbv.h"#define DBZV_VERSION_HIGH 0#define DBZV_VERSION_LOW 1#define COMPRESSION_NONE 0#define COMPRESSION_ZLIB 1#define MAX_VECTOR	16#define Mask_KeyFrame			0x01#define	Mask_DeltaPalette		0x02zmbv_format_t BPPFormat( int bpp ) {	switch (bpp) {	case 8:		return ZMBV_FORMAT_8BPP;	case 15:		return ZMBV_FORMAT_15BPP;	case 16:		return ZMBV_FORMAT_16BPP;	case 32:		return ZMBV_FORMAT_32BPP;	}	return ZMBV_FORMAT_NONE;}int VideoCodec::NeededSize( int _width, int _height, zmbv_format_t _format) {	int f;	switch (_format) {	case ZMBV_FORMAT_8BPP:f = 1;break;	case ZMBV_FORMAT_15BPP:f = 2;break;	case ZMBV_FORMAT_16BPP:f = 2;break;	case ZMBV_FORMAT_32BPP:f = 4;break;	default:		return -1;	}	f = f*_width*_height + 2*(1+(_width/8)) * (1+(_height/8))+1024;	return f + f/1000;}bool VideoCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight) {	FreeBuffers();	palsize = 0;	switch (_format) {	case ZMBV_FORMAT_8BPP:		pixelsize = 1;		palsize = 256;		break;	case ZMBV_FORMAT_15BPP:		pixelsize = 2;		break;	case ZMBV_FORMAT_16BPP:		pixelsize = 2;		break;	case ZMBV_FORMAT_32BPP:		pixelsize = 4;		break;	default:		return false;	};	bufsize = (height+2*MAX_VECTOR)*pitch*pixelsize+2048;	buf1 = new unsigned char[bufsize];	buf2 = new unsigned char[bufsize];	work = new unsigned char[bufsize];	int xblocks = (width/blockwidth);	int xleft = width % blockwidth;	if (xleft) xblocks++;	int yblocks = (height/blockheight);	int yleft = height % blockheight;	if (yleft) yblocks++;	blockcount=yblocks*xblocks;	blocks=new FrameBlock[blockcount];	if (!buf1 || !buf2 || !work || !blocks) {		FreeBuffers();		return false;	}	int y,x,i;	i=0;	for (y=0;y<yblocks;y++) {		for (x=0;x<xblocks;x++) {			blocks[i].start=((y*blockheight)+MAX_VECTOR)*pitch+				(x*blockwidth)+MAX_VECTOR;			if (xleft && x==(xblocks-1)) {                blocks[i].dx=xleft;			} else {				blocks[i].dx=blockwidth;			}			if (yleft && y==(yblocks-1)) {                blocks[i].dy=yleft;			} else {				blocks[i].dy=blockheight;			}			i++;		}	}	memset(buf1,0,bufsize);	memset(buf2,0,bufsize);	memset(work,0,bufsize);	oldframe=buf1;	newframe=buf2;	format = _format;	return true;}void VideoCodec::CreateVectorTable(void) {	int x,y,s;	VectorCount=1;	VectorTable[0].x=VectorTable[0].y=0;	for (s=1;s<=10;s++) {		for (y=0-s;y<=0+s;y++) for (x=0-s;x<=0+s;x++) {			if (abs(x)==s || abs(y)==s) {				VectorTable[VectorCount].x=x;				VectorTable[VectorCount].y=y;				VectorCount++;			}		}	}}template<class P>INLINE int VideoCodec::PossibleBlock(int vx,int vy,FrameBlock * block) {	int ret=0;	P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;	P * pnew=((P*)newframe)+block->start;;		for (int y=0;y<block->dy;y+=4) {		for (int x=0;x<block->dx;x+=4) {			int test=0-((pold[x]-pnew[x])&0x00ffffff);			ret-=(test>>31);		}		pold+=pitch*4;		pnew+=pitch*4;	}	return ret;}template<class P>INLINE int VideoCodec::CompareBlock(int vx,int vy,FrameBlock * block) {	int ret=0;	P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;	P * pnew=((P*)newframe)+block->start;;		for (int y=0;y<block->dy;y++) {		for (int x=0;x<block->dx;x++) {			int test=0-((pold[x]-pnew[x])&0x00ffffff);			ret-=(test>>31);		}		pold+=pitch;		pnew+=pitch;	}	return ret;}template<class P>INLINE void VideoCodec::AddXorBlock(int vx,int vy,FrameBlock * block) {	P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;	P * pnew=((P*)newframe)+block->start;	for (int y=0;y<block->dy;y++) {		for (int x=0;x<block->dx;x++) {			*((P*)&work[workUsed])=pnew[x] ^ pold[x];			workUsed+=sizeof(P);		}		pold+=pitch;		pnew+=pitch;	}}template<class P>void VideoCodec::AddXorFrame(void) {	int written=0;	int lastvector=0;	signed char * vectors=(signed char*)&work[workUsed];	/* Align the following xor data on 4 byte boundary*/	workUsed=(workUsed + blockcount*2 +3) & ~3;	int totalx=0;	int totaly=0;	for (int b=0;b<blockcount;b++) {		FrameBlock * block=&blocks[b];		int bestvx = 0;		int bestvy = 0;		int bestchange=CompareBlock<P>(0,0, block);		int possibles=64;		for (int v=0;v<VectorCount && possibles;v++) {			if (bestchange<4) break;			int vx = VectorTable[v].x;			int vy = VectorTable[v].y;			if (PossibleBlock<P>(vx, vy, block) < 4) {				possibles--;//				if (!possibles) Msg("Ran out of possibles, at %d of %d best %d\n",v,VectorCount,bestchange);				int testchange=CompareBlock<P>(vx,vy, block);				if (testchange<bestchange) {					bestchange=testchange;					bestvx = vx;					bestvy = vy;				}			}		}		vectors[b*2+0]=(bestvx << 1);		vectors[b*2+1]=(bestvy << 1);		if (bestchange) {			vectors[b*2+0]|=1;			AddXorBlock<P>(bestvx, bestvy, block);		}	}}bool VideoCodec::SetupCompress( int _width, int _height ) {	width = _width;	height = _height;	pitch = _width + 2*MAX_VECTOR;	format = ZMBV_FORMAT_NONE;	if (deflateInit (&zstream, 4) != Z_OK)		return false;	return true;}bool VideoCodec::SetupDecompress( int _width, int _height) {	width = _width;	height = _height;	pitch = _width + 2*MAX_VECTOR;	format = ZMBV_FORMAT_NONE;	if (inflateInit (&zstream) != Z_OK)		return false;	return true;}bool VideoCodec::PrepareCompressFrame(int flags,  zmbv_format_t _format, char * pal, void *writeBuf, int writeSize) {	int i;	unsigned char *firstByte;	if (_format != format) {		if (!SetupBuffers( _format, 16, 16))			return false;		flags|=1;	//Force a keyframe	}	/* replace oldframe with new frame */	unsigned char *copyFrame = newframe;	newframe = oldframe;	oldframe = copyFrame;	compress.linesDone = 0;	compress.writeSize = writeSize;	compress.writeDone = 1;	compress.writeBuf = (unsigned char *)writeBuf;	/* Set a pointer to the first byte which will contain info about this frame */	firstByte = compress.writeBuf;	*firstByte = 0;	//Reset the work buffer	workUsed = 0;workPos = 0;	if (flags & 1) {		/* Make a keyframe */		*firstByte |= Mask_KeyFrame;		KeyframeHeader * header = (KeyframeHeader *)(compress.writeBuf + compress.writeDone);		header->high_version = DBZV_VERSION_HIGH;		header->low_version = DBZV_VERSION_LOW;		header->compression = COMPRESSION_ZLIB;		header->format = format;		header->blockwidth = 16;		header->blockheight = 16;		compress.writeDone += sizeof(KeyframeHeader);		/* Copy the new frame directly over */		if (palsize) {			if (pal)				memcpy(&palette, pal, sizeof(palette));			else 				memset(&palette,0, sizeof(palette));			/* keyframes get the full palette */			for (i=0;i<palsize;i++) {				work[workUsed++] = palette[i*4+0];				work[workUsed++] = palette[i*4+1];				work[workUsed++] = palette[i*4+2];			}		}		/* Restart deflate */		deflateReset(&zstream);	} else {		if (palsize && pal && memcmp(pal, palette, palsize * 4)) {			*firstByte |= Mask_DeltaPalette;			for(i=0;i<palsize;i++) {				work[workUsed++]=palette[i*4+0] ^ pal[i*4+0];				work[workUsed++]=palette[i*4+1] ^ pal[i*4+1];				work[workUsed++]=palette[i*4+2] ^ pal[i*4+2];			}			memcpy(&palette,pal, palsize * 4);		}	}	return true;}void VideoCodec::CompressLines(int lineCount, void *lineData[]) {	int linePitch = pitch * pixelsize;	int lineWidth = width * pixelsize;	int i = 0;	unsigned char *destStart = newframe + pixelsize*(MAX_VECTOR+(compress.linesDone+MAX_VECTOR)*pitch);	while ( i < lineCount && (compress.linesDone < height)) {		memcpy(destStart, lineData[i],  lineWidth );		destStart += linePitch;		i++;compress.linesDone++;	}}int VideoCodec::FinishCompressFrame( void ) {	unsigned char firstByte = *compress.writeBuf;	if (firstByte & Mask_KeyFrame) {		int i;		/* Add the full frame data */		unsigned char * readFrame = newframe + pixelsize*(MAX_VECTOR+MAX_VECTOR*pitch);			for (i=0;i<height;i++) {			memcpy(&work[workUsed], readFrame, width*pixelsize);			readFrame += pitch*pixelsize;			workUsed += width*pixelsize;		}	} else {		/* Add the delta frame data */		switch (format) {		case ZMBV_FORMAT_8BPP:			AddXorFrame<char>();			break;		case ZMBV_FORMAT_15BPP:		case ZMBV_FORMAT_16BPP:			AddXorFrame<short>();			break;		case ZMBV_FORMAT_32BPP:			AddXorFrame<long>();			break;		}	}	/* Create the actual frame with compression */	zstream.next_in = (Bytef *)work;	zstream.avail_in = workUsed;	zstream.total_in = 0;	zstream.next_out = (Bytef *)(compress.writeBuf + compress.writeDone);	zstream.avail_out = compress.writeSize - compress.writeDone;	zstream.total_out = 0;	int res = deflate(&zstream, Z_SYNC_FLUSH);	return compress.writeDone + zstream.total_out;}template<class P>INLINE void VideoCodec::UnXorBlock(int vx,int vy,FrameBlock * block) {	P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;	P * pnew=((P*)newframe)+block->start;	for (int y=0;y<block->dy;y++) {		for (int x=0;x<block->dx;x++) {			pnew[x]=pold[x]^*((P*)&work[workPos]);			workPos+=sizeof(P);		}		pold+=pitch;		pnew+=pitch;	}}template<class P>INLINE void VideoCodec::CopyBlock(int vx,int vy,FrameBlock * block) {	P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx;	P * pnew=((P*)newframe)+block->start;	for (int y=0;y<block->dy;y++) {		for (int x=0;x<block->dx;x++) {			pnew[x]=pold[x];		}		pold+=pitch;		pnew+=pitch;	}}template<class P>void VideoCodec::UnXorFrame(void) {	signed char * vectors=(signed char *)&work[workPos];	workPos=(workPos + blockcount*2 + 3) & ~3;	for (int b=0;b<blockcount;b++) {		FrameBlock * block=&blocks[b];		int delta = vectors[b*2+0] & 1;		int vx = vectors[b*2+0] >> 1;		int vy = vectors[b*2+1] >> 1;		if (delta) UnXorBlock<P>(vx,vy,block);		else CopyBlock<P>(vx,vy,block);	}}bool VideoCodec::DecompressFrame(void * framedata, int size) {	unsigned char *data=(unsigned char *)framedata;	unsigned char tag;int i;	tag = *data++;	if (--size<=0)		return false;	if (tag & Mask_KeyFrame) {		KeyframeHeader * header = (KeyframeHeader *)data;		size -= sizeof(KeyframeHeader);data += sizeof(KeyframeHeader);		if (size<=0)            return false;		if (header->low_version != DBZV_VERSION_LOW || header->high_version != DBZV_VERSION_HIGH) 			return false;		if (format != (zmbv_format_t)header->format && !SetupBuffers((zmbv_format_t)header->format, header->blockwidth, header->blockheight))			return false;		inflateReset(&zstream);	} 	zstream.next_in = (Bytef *)data;	zstream.avail_in = size;	zstream.total_in = 0;	zstream.next_out = (Bytef *)work;	zstream.avail_out = bufsize;	zstream.total_out = 0;	int res = inflate(&zstream, Z_FINISH);	workUsed= zstream.total_out;	workPos = 0;	if (tag & Mask_KeyFrame) {		if (palsize) {			for (i=0;i<palsize;i++) {				palette[i*4+0] = work[workPos++];				palette[i*4+1] = work[workPos++];				palette[i*4+2] = work[workPos++];			}		}		newframe = buf1;		oldframe = buf2;		unsigned char * writeframe = newframe + pixelsize*(MAX_VECTOR+MAX_VECTOR*pitch);			for (i=0;i<height;i++) {			memcpy(writeframe,&work[workPos],width*pixelsize);			writeframe+=pitch*pixelsize;			workPos+=width*pixelsize;		}	} else {		data = oldframe;		oldframe = newframe;		newframe = data;		if (tag & Mask_DeltaPalette) {			for (i=0;i<palsize;i++) {				palette[i*4+0] ^= work[workPos++];				palette[i*4+1] ^= work[workPos++];				palette[i*4+2] ^= work[workPos++];			}		}		switch (format) {		case ZMBV_FORMAT_8BPP:			UnXorFrame<char>();			break;		case ZMBV_FORMAT_15BPP:		case ZMBV_FORMAT_16BPP:			UnXorFrame<short>();			break;		case ZMBV_FORMAT_32BPP:			UnXorFrame<long>();			break;		}	}	return true;}void VideoCodec::Output_UpsideDown_24(void *output) {	int i;	unsigned char *r;	unsigned char *w = (unsigned char *)output;	int pad = width & 3;	for (i=height-1;i>=0;i--) {		r = newframe + pixelsize*(MAX_VECTOR+(i+MAX_VECTOR)*pitch);		switch (format) {		case ZMBV_FORMAT_8BPP:			for (int j=0;j<width;j++) {				int c=r[j];				*w++=palette[c*4+2];				*w++=palette[c*4+1];				*w++=palette[c*4+0];			}			break;		case ZMBV_FORMAT_15BPP:			for (int j=0;j<width;j++) {				unsigned short c = *(unsigned short *)&r[j*2];				*w++ = (unsigned char)(((c & 0x001f) * 0x21) >>  2);				*w++ = (unsigned char)(((c & 0x03e0) * 0x21) >>  7);				*w++ = (unsigned char)(((c & 0x7c00) * 0x21) >> 12);			}			break;		case ZMBV_FORMAT_16BPP:			for (int j=0;j<width;j++) {				unsigned short c = *(unsigned short *)&r[j*2];				*w++ = (unsigned char)(((c & 0x001f) * 0x21) >>  2);				*w++ = (unsigned char)(((c & 0x07e0) * 0x41) >>  9);				*w++ = (unsigned char)(((c & 0xf800) * 0x21) >> 13);			}			break;		case ZMBV_FORMAT_32BPP:			for (int j=0;j<width;j++) {				*w++ = r[j*4+0];				*w++ = r[j*4+1];				*w++ = r[j*4+2];			}			break;		}		// Maintain 32-bit alignment for scanlines.		w += pad;	}}void VideoCodec::FreeBuffers(void) {	if (blocks) {		delete[] blocks;blocks=0;	}	if (buf1) {		delete[] buf1;buf1=0;	}	if (buf2) {		delete[] buf2;buf2=0;	}	if (work) {		delete[] work;work=0;	}}VideoCodec::VideoCodec() {	CreateVectorTable();	blocks = 0;	buf1 = 0;	buf2 = 0;	work = 0;	memset( &zstream, 0, sizeof(zstream));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -