mirror of
https://github.com/libretro/fmsx-libretro.git
synced 2026-11-07 10:36:03 -10:00
version 4.9 changes
This commit is contained in:
1 parent
81ec0f95b2
commit
8d5f4a128e
25 files changed
+6562
-78
No files matched your search
Executable
+233
@@ -0,0 +1,233 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Hunt.c **/
|
||||
/** **/
|
||||
/** This file implements mechanism for searching possible **/
|
||||
/** cheats inside running game data. Also see Hunt.h. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2013-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "Hunt.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(VGBA)
|
||||
#include "ARM.h"
|
||||
#define MEMREAD32(A) QRdARM(A)
|
||||
#define MEMREAD16(A) WRdARM(A)
|
||||
#define MEMREAD8(A) BRdARM(A)
|
||||
#elif defined(INES)
|
||||
#include "M6502.h"
|
||||
#define MEMREAD32(A) (Rd6502(A)+((int)Rd6502(A+1)<<8)+((int)Rd6502(A+2)<<16)+((int)Rd6502(A+3)<<24))
|
||||
#define MEMREAD16(A) (Rd6502(A)+((int)Rd6502(A+1)<<8))
|
||||
#define MEMREAD8(A) Rd6502(A)
|
||||
#elif defined(VGB) || defined(MG) || defined(COLEM) || defined(SPECCY) || defined(FMSX)
|
||||
#include "Z80.h"
|
||||
#define MEMREAD32(A) (RdZ80(A)+((int)RdZ80(A+1)<<8)+((int)RdZ80(A+2)<<16)+((int)RdZ80(A+3)<<24))
|
||||
#define MEMREAD16(A) (RdZ80(A)+((int)RdZ80(A+1)<<8))
|
||||
#define MEMREAD8(A) RdZ80(A)
|
||||
#else
|
||||
#define MEMREAD32(A) (0)
|
||||
#define MEMREAD16(A) (0)
|
||||
#define MEMREAD8(A) (0)
|
||||
#endif
|
||||
|
||||
static HUNTEntry Buf[HUNT_BUFSIZE];
|
||||
static int Count;
|
||||
|
||||
/** InitHUNT() ***********************************************/
|
||||
/** Initialize cheat search, clearing all data. **/
|
||||
/*************************************************************/
|
||||
void InitHUNT(void) { Count=0; }
|
||||
|
||||
/** TotalHUNT() **********************************************/
|
||||
/** Get total number of currently watched locations. **/
|
||||
/*************************************************************/
|
||||
int TotalHUNT(void) { return(Count); }
|
||||
|
||||
/** GetHUNT() ************************************************/
|
||||
/** Get Nth memory location. Returns 0 for invalid N. **/
|
||||
/*************************************************************/
|
||||
HUNTEntry *GetHUNT(int N)
|
||||
{ return((N>=0)&&(N<Count)? &Buf[N]:0); }
|
||||
|
||||
/** AddHUNT() ************************************************/
|
||||
/** Add a new value to search for, with the address range **/
|
||||
/** to search in. Returns number of memory locations found. **/
|
||||
/*************************************************************/
|
||||
int AddHUNT(unsigned int Addr,unsigned int Size,unsigned int Value,unsigned int NewValue,unsigned int Flags)
|
||||
{
|
||||
unsigned int J,M;
|
||||
int I;
|
||||
|
||||
/* Force 32bit/16bit mode for large values */
|
||||
if((Value>=0x10000)||(NewValue>=0x10000))
|
||||
Flags = (Flags&~HUNT_MASK_SIZE)|HUNT_32BIT;
|
||||
else if((Value>=0x100)||(NewValue>=0x100))
|
||||
Flags = (Flags&~HUNT_MASK_SIZE)|HUNT_16BIT;
|
||||
|
||||
/* Compute mask for given value size and truncate value */
|
||||
M = Flags&HUNT_32BIT? 0xFFFFFFFF:Flags&HUNT_16BIT? 0xFFFF:0x00FF;
|
||||
|
||||
#ifdef VGBA
|
||||
/* ARM aligns data to the size boundary */
|
||||
if(M>0xFFFF) Addr&=~3; else if(M>0xFF) Addr&=~1;
|
||||
#endif
|
||||
|
||||
/* Scan memory for given value */
|
||||
for(Size+=Addr,I=0;(Addr<Size)&&(Count<HUNT_BUFSIZE);++Addr)
|
||||
{
|
||||
J = (M>0xFFFF? MEMREAD32(Addr):M>0xFF? MEMREAD16(Addr):MEMREAD8(Addr))&M;
|
||||
|
||||
if((J==Value)||(J==((Value-1)&M)))
|
||||
{
|
||||
Buf[Count].Addr = Addr;
|
||||
Buf[Count].Flags = Flags;
|
||||
Buf[Count].Value = J;
|
||||
Buf[Count].Orig = J==Value? NewValue:((NewValue-1)&M);
|
||||
Buf[Count].Count = 0;
|
||||
++Count;
|
||||
++I;
|
||||
}
|
||||
|
||||
#ifdef VGBA
|
||||
/* ARM aligns data to the size boundary */
|
||||
if(M>0xFFFF) Addr+=3; else if(M>0xFF) Addr+=1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the number of matches found */
|
||||
return(I);
|
||||
}
|
||||
|
||||
/** ScanHUNT() ***********************************************/
|
||||
/** Scan memory for changed values and update search data. **/
|
||||
/** Returns number of memory locations updated. **/
|
||||
/*************************************************************/
|
||||
int ScanHUNT(void)
|
||||
{
|
||||
unsigned int K,L;
|
||||
int J,I;
|
||||
|
||||
/* Scan active search entries */
|
||||
for(J=I=0;J<Count;++J)
|
||||
{
|
||||
L = Buf[J].Flags&HUNT_32BIT? 0xFFFFFFFF:Buf[J].Flags&HUNT_16BIT? 0xFFFF:0x00FF;
|
||||
K = (L>0xFFFF? MEMREAD32(Buf[J].Addr):L>0xFF? MEMREAD16(Buf[J].Addr):MEMREAD8(Buf[J].Addr))&L;
|
||||
|
||||
/* Check for expected changes */
|
||||
switch(Buf[J].Flags&HUNT_MASK_CHANGE)
|
||||
{
|
||||
case HUNT_PLUSONE: L = K==((Buf[J].Value+1)&L);break;
|
||||
case HUNT_PLUSMANY: L = K>Buf[J].Value;break;
|
||||
case HUNT_MINUSONE: L = K==((Buf[J].Value-1)&L);break;
|
||||
case HUNT_MINUSMANY: L = K<Buf[J].Value;break;
|
||||
default:
|
||||
case HUNT_CONSTANT: L = K==Buf[J].Value;break;
|
||||
}
|
||||
|
||||
/* Delete any entry that does not change as expected */
|
||||
if(L)
|
||||
{
|
||||
if(Buf[J].Count<(1<<(sizeof(Buf[J].Count)<<3))-1) ++Buf[J].Count;
|
||||
Buf[J].Value = K;
|
||||
Buf[I++] = Buf[J];
|
||||
}
|
||||
}
|
||||
|
||||
/* Return number of successfully updated entries */
|
||||
return(Count=I);
|
||||
}
|
||||
|
||||
/** HUNT2Cheat() *********************************************/
|
||||
/** Create cheat code from Nth hunt entry. Returns 0 if the **/
|
||||
/** entry is invalid. **/
|
||||
/*************************************************************/
|
||||
const char *HUNT2Cheat(int N,unsigned int Type)
|
||||
{
|
||||
static char Buf[32];
|
||||
HUNTEntry *HE;
|
||||
|
||||
/* Must have a valid entry */
|
||||
if(!(HE=GetHUNT(N))) return(0);
|
||||
|
||||
/* Depending on cheat type... */
|
||||
switch(Type)
|
||||
{
|
||||
/** GameBoy Advance ******************************************/
|
||||
/** There are two versions of GameShark (v1/v3) differing **/
|
||||
/** by encryption and CodeBreaker. Not encrypting here. **/
|
||||
/*************************************************************/
|
||||
case HUNT_GBA_GS:
|
||||
/* 00AAAAAA NNNNNNDD - Multiple 8bit RAM Write */
|
||||
/* 02AAAAAA NNNNDDDD - Multiple 816bit RAM Write */
|
||||
sprintf(Buf,"0%c%06X 0000%04X",
|
||||
HE->Flags&HUNT_16BIT? '2':'0',
|
||||
(HE->Addr&0x000FFFFF)|((HE->Addr&0x0F000000)>>4),
|
||||
HE->Orig
|
||||
);
|
||||
return(Buf);
|
||||
|
||||
case HUNT_GBA_CB:
|
||||
/* 2AAAAAAA XXXX - 16bit RAM Write */
|
||||
/* 3AAAAAAA 00XX - 8bit RAM Write */
|
||||
sprintf(Buf,"%c%07X %04X",
|
||||
HE->Flags&HUNT_16BIT? '2':'3',
|
||||
HE->Addr&0x0FFFFFFF,
|
||||
HE->Orig
|
||||
);
|
||||
return(Buf);
|
||||
|
||||
/** GameBoy **************************************************/
|
||||
/** GameBoy has GameShark and GameGenie, but only GameShark **/
|
||||
/** can modify RAM. **/
|
||||
/*************************************************************/
|
||||
case HUNT_GB_GS:
|
||||
/* 00DDAAAA - 8bit RAM Write, No Bank */
|
||||
sprintf(Buf,"00%02X%02X%02X",(HE->Orig)&0xFF,HE->Addr&0x00FF,(HE->Addr&0xFF00)>>8);
|
||||
if(HE->Flags&HUNT_16BIT)
|
||||
sprintf(Buf+8,";00%02X%02X%02X",HE->Orig>>8,(HE->Addr+1)&0x00FF,((HE->Addr+1)&0xFF00)>>8);
|
||||
return(Buf);
|
||||
|
||||
/** NES ******************************************************/
|
||||
/** NES has both Pro Action Replay and GameGenie, but only **/
|
||||
/** Pro Action Replay can modify RAM. **/
|
||||
/*************************************************************/
|
||||
case HUNT_NES_AR:
|
||||
/* 00AAAADD - 8bit RAM Write */
|
||||
sprintf(Buf,"00%04X%02X",HE->Addr&0xFFFF,HE->Orig&0xFF);
|
||||
if(HE->Flags&HUNT_16BIT)
|
||||
sprintf(Buf+8,";00%04X%02X",(HE->Addr+1)&0xFFFF,HE->Orig>>8);
|
||||
return(Buf);
|
||||
|
||||
/** Sega MasterSystem and GameGear ***************************/
|
||||
/** MasterSystem has Pro Action Replay, while GameGear has **/
|
||||
/** GameGenie. Only Pro Action Replay can modify RAM. **/
|
||||
/*************************************************************/
|
||||
case HUNT_SMS_AR:
|
||||
/* 00AA-AADD - 8bit RAM Write */
|
||||
sprintf(Buf,"00%02X-%02X%02X",(HE->Addr&0xFF00)>>8,HE->Addr&0x00FF,HE->Orig&0xFF);
|
||||
if(HE->Flags&HUNT_16BIT)
|
||||
sprintf(Buf+9,";00%02X-%02X%02X",((HE->Addr+1)&0xFF00)>>8,(HE->Addr+1)&0x00FF,HE->Orig>>8);
|
||||
return(Buf);
|
||||
|
||||
/** ColecoVision, MSX, ZX Spectrum ***************************/
|
||||
/** There was no official cheating hardware for these **/
|
||||
/** systems, so we come up with our own "hardware". **/
|
||||
/*************************************************************/
|
||||
case HUNT_MSX:
|
||||
case HUNT_ZXS:
|
||||
case HUNT_COLECO:
|
||||
/* AAAA-DD[DD] - 8bit[16bit] RAM Write */
|
||||
if(HE->Flags&HUNT_16BIT)
|
||||
sprintf(Buf,"%04X-%04X",HE->Addr,HE->Orig&0xFFFF);
|
||||
else
|
||||
sprintf(Buf,"%04X-%02X",HE->Addr,HE->Orig&0x00FF);
|
||||
return(Buf);
|
||||
}
|
||||
|
||||
/* Invalid cheat type */
|
||||
return(0);
|
||||
}
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Hunt.h **/
|
||||
/** **/
|
||||
/** This file declares functions to search for possible **/
|
||||
/** cheats inside running game data. Also see Hunt.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2013-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#ifndef HUNT_H
|
||||
#define HUNT_H
|
||||
|
||||
#define HUNT_BUFSIZE 1024
|
||||
|
||||
/** Flags used in AddHUNT() **********************************/
|
||||
#define HUNT_MASK_ID 0x00FF
|
||||
#define HUNT_MASK_CHANGE 0x0700
|
||||
#define HUNT_CONSTANT 0x0000
|
||||
#define HUNT_PLUSONE 0x0100
|
||||
#define HUNT_PLUSMANY 0x0200
|
||||
#define HUNT_MINUSONE 0x0300
|
||||
#define HUNT_MINUSMANY 0x0400
|
||||
#define HUNT_MASK_SIZE 0x1800
|
||||
#define HUNT_8BIT 0x0000
|
||||
#define HUNT_16BIT 0x0800
|
||||
#define HUNT_32BIT 0x1000
|
||||
|
||||
/** Types used in HUNT2Cheat() *******************************/
|
||||
#define HUNT_GBA_GS 0 /* GBA GameShark Advance */
|
||||
#define HUNT_GBA_CB 1 /* GBA CodeBreaker Advance */
|
||||
#define HUNT_SMS_AR 2 /* SMS Pro Action Replay */
|
||||
#define HUNT_NES_AR 3 /* NES Pro Action Replay */
|
||||
#define HUNT_GB_GS 4 /* GB GameShark */
|
||||
#define HUNT_COLECO 5 /* ColecoVision cheats */
|
||||
#define HUNT_MSX 6 /* MSX cheats */
|
||||
#define HUNT_ZXS 7 /* ZX Spectrum cheats */
|
||||
|
||||
/** HUNTEntry ************************************************/
|
||||
/** Search entry containing data on one memory location. **/
|
||||
/*************************************************************/
|
||||
typedef struct
|
||||
{
|
||||
unsigned int Addr; /* Memory location address */
|
||||
unsigned int Orig; /* Original value at the address */
|
||||
unsigned int Value; /* Current value at the address */
|
||||
unsigned short Flags; /* Options supplied in AddHUNT() */
|
||||
unsigned short Count; /* Number of detected changes */
|
||||
} HUNTEntry;
|
||||
|
||||
/** InitHUNT() ***********************************************/
|
||||
/** Initialize cheat search, clearing all data. **/
|
||||
/*************************************************************/
|
||||
void InitHUNT(void);
|
||||
|
||||
/** AddHUNT() ************************************************/
|
||||
/** Add a new value to search for, with the address range **/
|
||||
/** to search in. Returns number of memory locations found. **/
|
||||
/*************************************************************/
|
||||
int AddHUNT(unsigned int Addr,unsigned int Size,unsigned int Value,unsigned int NewValue,unsigned int Flags);
|
||||
|
||||
/** ScanHUNT() ***********************************************/
|
||||
/** Scan memory for changed values and update search data. **/
|
||||
/** Returns number of memory locations updated. **/
|
||||
/*************************************************************/
|
||||
int ScanHUNT(void);
|
||||
|
||||
/** TotalHUNT() **********************************************/
|
||||
/** Get total number of currently watched locations. **/
|
||||
/*************************************************************/
|
||||
int TotalHUNT(void);
|
||||
|
||||
/** GetHUNT() ************************************************/
|
||||
/** Get Nth memory location. Returns 0 for invalid N. **/
|
||||
/*************************************************************/
|
||||
HUNTEntry *GetHUNT(int N);
|
||||
|
||||
/** HUNT2Cheat() *********************************************/
|
||||
/** Create cheat code from Nth hunt entry. Returns 0 if the **/
|
||||
/** entry is invalid. **/
|
||||
/*************************************************************/
|
||||
const char *HUNT2Cheat(int N,unsigned int Type);
|
||||
|
||||
#endif /* HUNT_H */
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#include "IPS.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(ANDROID)
|
||||
#include "MemFS.h"
|
||||
#define fopen mopen
|
||||
#define fclose mclose
|
||||
#define fread mread
|
||||
#define fseek mseek
|
||||
#elif defined(ZLIB)
|
||||
#include <zlib.h>
|
||||
#define fopen(F,M) (FILE *)gzopen(F,M)
|
||||
#define fclose(F) gzclose((gzFile)(F))
|
||||
#define fread(B,N,L,F) gzread((gzFile)(F),B,(L)*(N))
|
||||
#define fseek(F,N,W) (gzseek((gzFile)(F),N,W)<0? -1:0)
|
||||
#endif
|
||||
|
||||
/** MeasureIPS() *********************************************/
|
||||
/** Find total data size assumed by a given .IPS file. **/
|
||||
/*************************************************************/
|
||||
unsigned int MeasureIPS(const char *FileName)
|
||||
{
|
||||
return(ApplyIPS(FileName,0,0));
|
||||
}
|
||||
|
||||
/** ApplyIPS() ***********************************************/
|
||||
/** Loads patches from an .IPS file and applies them to the **/
|
||||
/** given data buffer. Returns number of patches applied. **/
|
||||
/*************************************************************/
|
||||
unsigned int ApplyIPS(const char *FileName,unsigned char *Data,unsigned int Size)
|
||||
{
|
||||
unsigned char Buf[16];
|
||||
unsigned int Result,Count,J,N;
|
||||
FILE *F;
|
||||
|
||||
F = fopen(FileName,"rb");
|
||||
if(!F) return(0);
|
||||
|
||||
/* Verify file header */
|
||||
if(fread(Buf,1,5,F)!=5) { fclose(F);return(0); }
|
||||
if(memcmp(Buf,"PATCH",5)) { fclose(F);return(0); }
|
||||
|
||||
for(Result=0,Count=1;fread(Buf,1,5,F)==5;++Count)
|
||||
{
|
||||
J = Buf[2]+((unsigned int)Buf[1]<<8)+((unsigned int)Buf[0]<<16);
|
||||
N = Buf[4]+((unsigned int)Buf[3]<<8);
|
||||
|
||||
/* Apparently, these may signal the end of .IPS file */
|
||||
if((J==0xFFFFFF) || !memcmp(Buf,"EOF",3)) break;
|
||||
|
||||
/* If patching with a block of data... */
|
||||
if(N)
|
||||
{
|
||||
/* Copying data */
|
||||
|
||||
if(!Data)
|
||||
{
|
||||
/* Just measuring patch size */
|
||||
if(Result<J+N) Result=J+N;
|
||||
if(fseek(F,N,SEEK_CUR)<0) break;
|
||||
}
|
||||
else if(J+N>Size)
|
||||
{
|
||||
printf("IPS: Failed applying COPY patch #%d to 0x%X..0x%X of 0x%X bytes.\n",Count,J,J+N-1,Size);
|
||||
if(fseek(F,N,SEEK_CUR)<0) break;
|
||||
}
|
||||
else if(fread(Data+J,1,N,F)==N)
|
||||
{
|
||||
// printf("IPS: Applied COPY patch #%d to 0x%X..0x%X.\n",Count,J,J+N-1);
|
||||
++Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IPS: Failed reading COPY patch #%d from the file.\n",Count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Filling with a value */
|
||||
|
||||
if(fread(Buf,1,3,F)!=3)
|
||||
{
|
||||
if(Data) printf("IPS: Failed reading FILL patch #%d from the file.\n",Count);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Compute fill length */
|
||||
N = ((unsigned int)Buf[0]<<8)+Buf[1];
|
||||
|
||||
if(!Data)
|
||||
{
|
||||
if(Result<J+N) Result=J+N;
|
||||
}
|
||||
else if(!N || (J+N>Size))
|
||||
{
|
||||
printf("IPS: Failed applying FILL patch #%d (0x%02X) to 0x%X..0x%X of 0x%X bytes.\n",Count,Buf[1],J,J+N-1,Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// printf("IPS: Applied FILL patch #%d (0x%02X) to 0x%X..0x%X.\n",Count,Buf[1],J,J+N-1);
|
||||
memset(Data+J,Buf[2],N);
|
||||
++Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(F);
|
||||
return(Result);
|
||||
}
|
||||
|
||||
#if defined(ZLIB) || defined(ANDROID)
|
||||
#undef fopen
|
||||
#undef fclose
|
||||
#undef fread
|
||||
#undef fseek
|
||||
#endif
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#ifndef IPS_H
|
||||
#define IPS_H
|
||||
|
||||
/** ApplyIPS() ***********************************************/
|
||||
/** Loads patches from an .IPS file and applies them to the **/
|
||||
/** given data buffer. Returns number of patches applied. **/
|
||||
/*************************************************************/
|
||||
unsigned int ApplyIPS(const char *FileName,unsigned char *Data,unsigned int Size);
|
||||
|
||||
/** MeasureIPS() *********************************************/
|
||||
/** Find total data size assumed by a given .IPS file. **/
|
||||
/*************************************************************/
|
||||
unsigned int MeasureIPS(const char *FileName);
|
||||
|
||||
#endif /* IPS_H */
|
||||
Executable
+1236
File diff suppressed because it is too large.
Load diff
Executable
+524
@@ -0,0 +1,524 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** ImageMux.h **/
|
||||
/** **/
|
||||
/** This file wraps Image.c routines for multiple display **/
|
||||
/** depths (BPP8,BPP16,BPP32). It is used automatically **/
|
||||
/** when none of BPP* values are defined. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2008-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#ifndef IMAGEMUX_H
|
||||
#define IMAGEMUX_H
|
||||
|
||||
#include "EMULib.h"
|
||||
|
||||
#undef BPP8
|
||||
#undef BPP16
|
||||
#undef BPP24
|
||||
#undef BPP32
|
||||
#undef RMASK
|
||||
#undef GMASK
|
||||
#undef BMASK
|
||||
#undef PIXEL
|
||||
|
||||
#define BPP8
|
||||
#define pixel unsigned char
|
||||
#define PIXEL(R,G,B) (pixel)(((7*(R)/255)<<5)|((7*(G)/255)<<2)|(3*(B)/255))
|
||||
#define GetColor GetColor_8
|
||||
#define IMGCopy IMGCopy_8
|
||||
#define IMGDrawRect IMGDrawRect_8
|
||||
#define IMGFillRect IMGFillRect_8
|
||||
#define CropImage CropImage_8
|
||||
#define ClearImage ClearImage_8
|
||||
#define ScaleImage ScaleImage_8
|
||||
#define RasterizeImage RasterizeImage_8
|
||||
#define TelevizeImage TelevizeImage_8
|
||||
#define LcdizeImage LcdizeImage_8
|
||||
#define CMYizeImage CMYizeImage_8
|
||||
#define RGBizeImage RGBizeImage_8
|
||||
#define MonoImage MonoImage_8
|
||||
#define SepiaImage SepiaImage_8
|
||||
#define GreenImage GreenImage_8
|
||||
#define AmberImage AmberImage_8
|
||||
#define SoftenImage SoftenImage_8
|
||||
#define SoftenSCALE2X SoftenSCALE2X_8
|
||||
#define SoftenEPX SoftenEPX_8
|
||||
#define SoftenEAGLE SoftenEAGLE_8
|
||||
#define LoadPNG LoadPNG_8
|
||||
#include "Image.c"
|
||||
#undef pixel
|
||||
#undef PIXEL
|
||||
#undef GetColor
|
||||
#undef IMGCopy
|
||||
#undef IMGDrawRect
|
||||
#undef IMGFillRect
|
||||
#undef CropImage
|
||||
#undef ClearImage
|
||||
#undef ScaleImage
|
||||
#undef RasterizeImage
|
||||
#undef TelevizeImage
|
||||
#undef LcdizeImage
|
||||
#undef CMYizeImage
|
||||
#undef RGBizeImage
|
||||
#undef MonoImage
|
||||
#undef SepiaImage
|
||||
#undef GreenImage
|
||||
#undef AmberImage
|
||||
#undef SoftenImage
|
||||
#undef SoftenSCALE2X
|
||||
#undef SoftenEPX
|
||||
#undef SoftenEAGLE
|
||||
#undef LoadPNG
|
||||
#undef BPP8
|
||||
|
||||
#define BPP16
|
||||
#define pixel unsigned short
|
||||
#if defined(UNIX) || defined(ANDROID) || defined(S60) || defined(UIQ) || defined(NXC2600) || defined(STMP3700)
|
||||
/* Symbian and Unix use true 16BPP color */
|
||||
#define PIXEL(R,G,B) (pixel)(((31*(R)/255)<<11)|((63*(G)/255)<<5)|(31*(B)/255))
|
||||
#define RMASK 0xF800
|
||||
#define GMASK 0x07E0
|
||||
#define BMASK 0x001F
|
||||
#else
|
||||
/* Other platforms use 15BPP color */
|
||||
#define PIXEL(R,G,B) (pixel)(((31*(R)/255)<<10)|((31*(G)/255)<<5)|(31*(B)/255))
|
||||
#define RMASK 0x7C00
|
||||
#define GMASK 0x03E0
|
||||
#define BMASK 0x001F
|
||||
#endif
|
||||
#define GetColor GetColor_16
|
||||
#define IMGCopy IMGCopy_16
|
||||
#define IMGDrawRect IMGDrawRect_16
|
||||
#define IMGFillRect IMGFillRect_16
|
||||
#define CropImage CropImage_16
|
||||
#define ClearImage ClearImage_16
|
||||
#define ScaleImage ScaleImage_16
|
||||
#define RasterizeImage RasterizeImage_16
|
||||
#define TelevizeImage TelevizeImage_16
|
||||
#define LcdizeImage LcdizeImage_16
|
||||
#define CMYizeImage CMYizeImage_16
|
||||
#define RGBizeImage RGBizeImage_16
|
||||
#define MonoImage MonoImage_16
|
||||
#define SepiaImage SepiaImage_16
|
||||
#define GreenImage GreenImage_16
|
||||
#define AmberImage AmberImage_16
|
||||
#define SoftenImage SoftenImage_16
|
||||
#define SoftenSCALE2X SoftenSCALE2X_16
|
||||
#define SoftenEPX SoftenEPX_16
|
||||
#define SoftenEAGLE SoftenEAGLE_16
|
||||
#define LoadPNG LoadPNG_16
|
||||
#define ARMScaleImage ARMScaleImage_16
|
||||
#define Merge2 Merge2_16
|
||||
#define Merge4 Merge4_16
|
||||
#undef LIBARM_H
|
||||
#include "Image.c"
|
||||
#undef pixel
|
||||
#undef PIXEL
|
||||
#undef RMASK
|
||||
#undef GMASK
|
||||
#undef BMASK
|
||||
#undef GetColor
|
||||
#undef IMGCopy
|
||||
#undef IMGDrawRect
|
||||
#undef IMGFillRect
|
||||
#undef CropImage
|
||||
#undef ClearImage
|
||||
#undef ScaleImage
|
||||
#undef RasterizeImage
|
||||
#undef TelevizeImage
|
||||
#undef LcdizeImage
|
||||
#undef CMYizeImage
|
||||
#undef RGBizeImage
|
||||
#undef MonoImage
|
||||
#undef SepiaImage
|
||||
#undef GreenImage
|
||||
#undef AmberImage
|
||||
#undef SoftenImage
|
||||
#undef SoftenSCALE2X
|
||||
#undef SoftenEPX
|
||||
#undef SoftenEAGLE
|
||||
#undef LoadPNG
|
||||
#undef ARMScaleImage
|
||||
#undef Merge2
|
||||
#undef Merge4
|
||||
#undef BPP16
|
||||
|
||||
#define BPP32
|
||||
#define pixel unsigned int
|
||||
#if defined(ANDROID)
|
||||
#define PIXEL(R,G,B) (pixel)(((int)R<<16)|((int)G<<8)|B|0xFF000000)
|
||||
#else
|
||||
#define PIXEL(R,G,B) (pixel)(((int)R<<16)|((int)G<<8)|B)
|
||||
#endif
|
||||
#define RMASK 0xFF0000
|
||||
#define GMASK 0x00FF00
|
||||
#define BMASK 0x0000FF
|
||||
#define GetColor GetColor_32
|
||||
#define IMGCopy IMGCopy_32
|
||||
#define IMGDrawRect IMGDrawRect_32
|
||||
#define IMGFillRect IMGFillRect_32
|
||||
#define CropImage CropImage_32
|
||||
#define ClearImage ClearImage_32
|
||||
#define ScaleImage ScaleImage_32
|
||||
#define RasterizeImage RasterizeImage_32
|
||||
#define TelevizeImage TelevizeImage_32
|
||||
#define LcdizeImage LcdizeImage_32
|
||||
#define CMYizeImage CMYizeImage_32
|
||||
#define RGBizeImage RGBizeImage_32
|
||||
#define MonoImage MonoImage_32
|
||||
#define SepiaImage SepiaImage_32
|
||||
#define GreenImage GreenImage_32
|
||||
#define AmberImage AmberImage_32
|
||||
#define SoftenImage SoftenImage_32
|
||||
#define SoftenSCALE2X SoftenSCALE2X_32
|
||||
#define SoftenEPX SoftenEPX_32
|
||||
#define SoftenEAGLE SoftenEAGLE_32
|
||||
#define LoadPNG LoadPNG_32
|
||||
#define ARMScaleImage ARMScaleImage_32
|
||||
#define Merge2 Merge2_32
|
||||
#define Merge4 Merge4_32
|
||||
#undef LIBARM_H
|
||||
#include "Image.c"
|
||||
#undef pixel
|
||||
#undef PIXEL
|
||||
#undef RMASK
|
||||
#undef GMASK
|
||||
#undef BMASK
|
||||
#undef GetColor
|
||||
#undef IMGCopy
|
||||
#undef IMGDrawRect
|
||||
#undef IMGFillRect
|
||||
#undef CropImage
|
||||
#undef ClearImage
|
||||
#undef ScaleImage
|
||||
#undef RasterizeImage
|
||||
#undef TelevizeImage
|
||||
#undef LcdizeImage
|
||||
#undef CMYizeImage
|
||||
#undef RGBizeImage
|
||||
#undef MonoImage
|
||||
#undef SepiaImage
|
||||
#undef GreenImage
|
||||
#undef AmberImage
|
||||
#undef SoftenImage
|
||||
#undef SoftenSCALE2X
|
||||
#undef SoftenEPX
|
||||
#undef SoftenEAGLE
|
||||
#undef LoadPNG
|
||||
#undef ARMScaleImage
|
||||
#undef Merge2
|
||||
#undef Merge4
|
||||
#undef BPP32
|
||||
|
||||
/** GetColor() ***********************************************/
|
||||
/** Return pixel corresponding to the given <R,G,B> value. **/
|
||||
/** This only works for non-palletized modes. **/
|
||||
/*************************************************************/
|
||||
pixel GetColor(unsigned char R,unsigned char G,unsigned char B)
|
||||
{
|
||||
if(VideoImg)
|
||||
switch(VideoImg->D)
|
||||
{
|
||||
case 8: return(GetColor_8(R,G,B));
|
||||
case 16: return(GetColor_16(R,G,B));
|
||||
case 24:
|
||||
case 32: return(GetColor_32(R,G,B));
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** ClearImage() *********************************************/
|
||||
/** Clear image with a given color. **/
|
||||
/*************************************************************/
|
||||
void ClearImage(Image *Img,pixel Color)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: ClearImage_8(Img,Color);break;
|
||||
case 16: ClearImage_16(Img,Color);break;
|
||||
case 24:
|
||||
case 32: ClearImage_32(Img,Color);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** IMGCopy() ************************************************/
|
||||
/** Copy one image into another. **/
|
||||
/*************************************************************/
|
||||
void IMGCopy(Image *Dst,int DX,int DY,const Image *Src,int SX,int SY,int W,int H,int TColor)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: IMGCopy_8(Dst,DX,DY,Src,SX,SY,W,H,TColor);break;
|
||||
case 16: IMGCopy_16(Dst,DX,DY,Src,SX,SY,W,H,TColor);break;
|
||||
case 24:
|
||||
case 32: IMGCopy_32(Dst,DX,DY,Src,SX,SY,W,H,TColor);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** IMGDrawRect()/IMGFillRect() ******************************/
|
||||
/** Draw filled/unfilled rectangle in a given image. **/
|
||||
/*************************************************************/
|
||||
void IMGDrawRect(Image *Img,int X,int Y,int W,int H,pixel Color)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: IMGDrawRect_8(Img,X,Y,W,H,Color);break;
|
||||
case 16: IMGDrawRect_16(Img,X,Y,W,H,Color);break;
|
||||
case 24:
|
||||
case 32: IMGDrawRect_32(Img,X,Y,W,H,Color);break;
|
||||
}
|
||||
}
|
||||
|
||||
void IMGFillRect(Image *Img,int X,int Y,int W,int H,pixel Color)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: IMGFillRect_8(Img,X,Y,W,H,Color);break;
|
||||
case 16: IMGFillRect_16(Img,X,Y,W,H,Color);break;
|
||||
case 24:
|
||||
case 32: IMGFillRect_32(Img,X,Y,W,H,Color);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** SoftenImage() ********************************************/
|
||||
/** Uses softening algorithm to interpolate image Src into **/
|
||||
/** a bigger image Dst. **/
|
||||
/*************************************************************/
|
||||
void SoftenImage(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: SoftenImage_8(Dst,Src,X,Y,W,H);break;
|
||||
case 16: SoftenImage_16(Dst,Src,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: SoftenImage_32(Dst,Src,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** SoftenEPX() **********************************************/
|
||||
/** Uses softening algorithm to interpolate image Src into **/
|
||||
/** a bigger image Dst. **/
|
||||
/*************************************************************/
|
||||
void SoftenEPX(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: SoftenEPX_8(Dst,Src,X,Y,W,H);break;
|
||||
case 16: SoftenEPX_16(Dst,Src,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: SoftenEPX_32(Dst,Src,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** SoftenEAGLE() ********************************************/
|
||||
/** Uses softening algorithm to interpolate image Src into **/
|
||||
/** a bigger image Dst. **/
|
||||
/*************************************************************/
|
||||
void SoftenEAGLE(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: SoftenEAGLE_8(Dst,Src,X,Y,W,H);break;
|
||||
case 16: SoftenEAGLE_16(Dst,Src,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: SoftenEAGLE_32(Dst,Src,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** SoftenSCALE2X() ******************************************/
|
||||
/** Uses softening algorithm to interpolate image Src into **/
|
||||
/** a bigger image Dst. **/
|
||||
/*************************************************************/
|
||||
void SoftenSCALE2X(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: SoftenSCALE2X_8(Dst,Src,X,Y,W,H);break;
|
||||
case 16: SoftenSCALE2X_16(Dst,Src,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: SoftenSCALE2X_32(Dst,Src,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** ScaleImage() *********************************************/
|
||||
/** Copy Src into Dst, scaling as needed **/
|
||||
/*************************************************************/
|
||||
void ScaleImage(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
if(Src->D!=Dst->D) return;
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 8: ScaleImage_8(Dst,Src,X,Y,W,H);break;
|
||||
case 16: ScaleImage_16(Dst,Src,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: ScaleImage_32(Dst,Src,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** TelevizeImage() ******************************************/
|
||||
/** Create televizion effect on the image. **/
|
||||
/*************************************************************/
|
||||
void TelevizeImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: TelevizeImage_8(Img,X,Y,W,H);break;
|
||||
case 16: TelevizeImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: TelevizeImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** LcdizeImage() ********************************************/
|
||||
/** Create LCD effect on the image. **/
|
||||
/*************************************************************/
|
||||
void LcdizeImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: LcdizeImage_8(Img,X,Y,W,H);break;
|
||||
case 16: LcdizeImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: LcdizeImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** RasterizeImage() *****************************************/
|
||||
/** Create raster effect on the image. **/
|
||||
/*************************************************************/
|
||||
void RasterizeImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: RasterizeImage_8(Img,X,Y,W,H);break;
|
||||
case 16: RasterizeImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: RasterizeImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** CMYizeImage() ********************************************/
|
||||
/** Apply vertical CMY stripes to the image. **/
|
||||
/*************************************************************/
|
||||
void CMYizeImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: CMYizeImage_8(Img,X,Y,W,H);break;
|
||||
case 16: CMYizeImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: CMYizeImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** RGBizeImage() ********************************************/
|
||||
/** Apply vertical RGB stripes to the image. **/
|
||||
/*************************************************************/
|
||||
void RGBizeImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: RGBizeImage_8(Img,X,Y,W,H);break;
|
||||
case 16: RGBizeImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: RGBizeImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** MonoImage() **********************************************/
|
||||
/** Turn image into monochrome. **/
|
||||
/*************************************************************/
|
||||
void MonoImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: MonoImage_8(Img,X,Y,W,H);break;
|
||||
case 16: MonoImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: MonoImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** SepiaImage() *********************************************/
|
||||
/** Turn image into sepia tones. **/
|
||||
/*************************************************************/
|
||||
void SepiaImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: SepiaImage_8(Img,X,Y,W,H);break;
|
||||
case 16: SepiaImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: SepiaImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** GreenImage() *********************************************/
|
||||
/** Simulate green CRT phosphor. **/
|
||||
/*************************************************************/
|
||||
void GreenImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: GreenImage_8(Img,X,Y,W,H);break;
|
||||
case 16: GreenImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: GreenImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
/** AmberImage() *********************************************/
|
||||
/** Simulate amber CRT phosphor. **/
|
||||
/*************************************************************/
|
||||
void AmberImage(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: AmberImage_8(Img,X,Y,W,H);break;
|
||||
case 16: AmberImage_16(Img,X,Y,W,H);break;
|
||||
case 24:
|
||||
case 32: AmberImage_32(Img,X,Y,W,H);break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM_CPU
|
||||
/** ARMScaleImage() ******************************************/
|
||||
/** Copy Src into Dst using ARM-optimized assembly code. **/
|
||||
/** Returns 0 if this function is not supported or there is **/
|
||||
/** an alignment problem. Returns destination height and **/
|
||||
/** width on success in <Height 31:16><Width 15:0> format. **/
|
||||
/*************************************************************/
|
||||
unsigned int ARMScaleImage(Image *Dst,Image *Src,int X,int Y,int W,int H,int Attrs)
|
||||
{
|
||||
if(Src->D!=Dst->D) return(0);
|
||||
|
||||
switch(Dst->D)
|
||||
{
|
||||
case 16: return(ARMScaleImage_16(Dst,Src,X,Y,W,H,Attrs));
|
||||
case 24:
|
||||
case 32: return(ARMScaleImage_32(Dst,Src,X,Y,W,H,Attrs));
|
||||
}
|
||||
|
||||
/* ARMScaleImage() does not support this image depth */
|
||||
ScaleImage(Dst,Src,X,Y,W,H);
|
||||
return((Dst->H<<16)|Dst->W);
|
||||
}
|
||||
#endif /* ARM_CPU */
|
||||
|
||||
#endif /* IMAGEMUX_H */
|
||||
Executable
+130
@@ -0,0 +1,130 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** NetPlay.c **/
|
||||
/** **/
|
||||
/** This file contains platform-independent part of the **/
|
||||
/** NetPlay implementation. See NetPlay.h for declarations. **/
|
||||
/** Platform specific implementation for platform XXX goes **/
|
||||
/** into NetXXX.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "EMULib.h"
|
||||
#include "Console.h"
|
||||
#include "NetPlay.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/** Dummy NET*() Functions ***********************************/
|
||||
/** These dummy functions are for systems where networking **/
|
||||
/** is not implemented. **/
|
||||
/*************************************************************/
|
||||
#if !defined(WINDOWS) && !defined(UNIX) && !defined(ANDROID) && !defined(MAEMO) && !defined(MEEGO) && !defined(S60) && !defined(UIQ)
|
||||
const char *NETMyName(char *Buffer,int MaxChars) { return(0); }
|
||||
int NETConnect(const char *Server,unsigned short Port) { return(NET_OFF); }
|
||||
int NETConnectAsync(const char *Server,unsigned short Port) { return(0); }
|
||||
int NETSend(const char *Out,int N) { return(0); }
|
||||
int NETRecv(char *In,int N) { return(0); }
|
||||
int NETBlock(int Switch) { return(NET_OFF); }
|
||||
int NETConnected(void) { return(NET_OFF); }
|
||||
void NETClose(void) { }
|
||||
#endif
|
||||
|
||||
/** NETPlay() ************************************************/
|
||||
/** Connect/disconnect NetPlay interface, toggle or query **/
|
||||
/** connection status (use NET_* as argument). Returns the **/
|
||||
/** NetPlay connection status. **/
|
||||
/*************************************************************/
|
||||
int NETPlay(int Switch)
|
||||
{
|
||||
char S[256],T[256],*P;
|
||||
int J;
|
||||
|
||||
// Toggle connection if requested
|
||||
if(Switch==NET_TOGGLE) Switch=NETConnected()? NET_OFF:NET_ON;
|
||||
|
||||
switch(Switch)
|
||||
{
|
||||
case NET_OFF:
|
||||
// Disconnect NetPlay
|
||||
NETClose();
|
||||
break;
|
||||
case NET_ON:
|
||||
case NET_SERVER:
|
||||
// If already connected, drop out
|
||||
if(NETConnected()==Switch) break;
|
||||
// If connecting in client mode, ask for hostname
|
||||
if((Switch==NET_SERVER)||CONInput(
|
||||
-1,-1,NET_FGCOLOR,NET_BGCOLOR,
|
||||
"Enter Hostname",S,sizeof(S)
|
||||
))
|
||||
{
|
||||
// Compose title
|
||||
T[0]='~';
|
||||
if(!NETMyName(T+1,sizeof(T)-1)) strcpy(T+1,"Network Play");
|
||||
// Show "Connecting" message
|
||||
CONMsg(-1,-1,-1,-1,NET_FGCOLOR,NET_OKCOLOR,T," \0 Connecting... \0 \0");
|
||||
ShowVideo();
|
||||
// Convert string to lower case, remove spaces
|
||||
if(Switch==NET_SERVER)
|
||||
{
|
||||
for(J=0,P=S;*P;++P)
|
||||
if(*P>' ') S[J++]=(*P>='A')&&(*P<='Z')? *P+'a'-'A':*P;
|
||||
S[J]='\0';
|
||||
}
|
||||
// Connect second player, report problems if present
|
||||
if(!NETConnect(Switch==NET_SERVER? 0:S,NET_PORT))
|
||||
CONMsg(
|
||||
-1,-1,-1,-1,NET_FGCOLOR,NET_ERRCOLOR,
|
||||
T+1," \0 Failed! \0 \0"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Always return connection status
|
||||
return(NETConnected());
|
||||
}
|
||||
|
||||
/** NETExchange() ********************************************/
|
||||
/** Exchanges given number of bytes with the other side and **/
|
||||
/** returns 1 on success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
int NETExchange(char *In,const char *Out,int N)
|
||||
{
|
||||
/* Send data */
|
||||
if(NETSend(Out,N)!=N) return(0);
|
||||
/* Receive data */
|
||||
if(NETRecv(In,N)!=N) return(0);
|
||||
/* Success */
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** NETJoystick() ********************************************/
|
||||
/** When NetPlay disconnected, returns GetJoystick(). Else, **/
|
||||
/** exchanges joystick states over the network and presents **/
|
||||
/** server as player #1, client as player #2. **/
|
||||
/*************************************************************/
|
||||
unsigned int NETJoystick(void)
|
||||
{
|
||||
unsigned int J,I;
|
||||
|
||||
/* Get local joystick state */
|
||||
J = GetJoystick();
|
||||
|
||||
/* When ALT pressed, swap players back */
|
||||
if(J&BTN_ALT) J=(J&BTN_MODES)|((J>>16)&BTN_ALL)|((J&BTN_ALL)<<16);
|
||||
|
||||
/* If exchanged joystick states over the network... */
|
||||
/* Assume server to be player #1, client to be player #2 */
|
||||
if(NETExchange((char *)&I,(const char *)&J,sizeof(J)))
|
||||
J = NETConnected()==NET_SERVER?
|
||||
((J&(BTN_ALL|BTN_MODES))|((I&BTN_ALL)<<16))
|
||||
: ((I&(BTN_ALL|BTN_MODES))|((J&BTN_ALL)<<16));
|
||||
|
||||
/* Done */
|
||||
return(J);
|
||||
}
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** NetPlay.h **/
|
||||
/** **/
|
||||
/** This file contains declarations for routines that let **/
|
||||
/** people play over the network. See NetPlay.c for the **/
|
||||
/** platform-independent implementation part. Platform **/
|
||||
/** specific implementation for platform XXX goes into **/
|
||||
/** NetXXX.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#ifndef NETPLAY_H
|
||||
#define NETPLAY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** NetPlay **************************************************/
|
||||
/** NET_PORT is used by NetPlay to exchange joypad states **/
|
||||
/** with the other player. NET_* values are arguments to **/
|
||||
/** NETPlay(). **/
|
||||
/*************************************************************/
|
||||
#define NET_PORT 6666
|
||||
|
||||
#define NET_OFF 0
|
||||
#define NET_ON 1
|
||||
#define NET_CLIENT 1
|
||||
#define NET_SERVER 2
|
||||
#define NET_TOGGLE 3
|
||||
#define NET_QUERY 4
|
||||
|
||||
#define NET_FGCOLOR PIXEL(255,255,255)
|
||||
#define NET_BGCOLOR PIXEL(80,40,0)
|
||||
#define NET_OKCOLOR PIXEL(0,80,0)
|
||||
#define NET_ERRCOLOR PIXEL(200,0,0)
|
||||
|
||||
/** NETPlay() ************************************************/
|
||||
/** Connect/disconnect NetPlay interface, toggle or query **/
|
||||
/** connection status (use NET_* as argument). Returns the **/
|
||||
/** NetPlay connection status, like NETConnected(). **/
|
||||
/*************************************************************/
|
||||
int NETPlay(int Switch);
|
||||
|
||||
/** NETExchange() ********************************************/
|
||||
/** Exchanges given number of bytes with the other side and **/
|
||||
/** returns 1 on success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
int NETExchange(char *In,const char *Out,int N);
|
||||
|
||||
/** NETJoystick() ********************************************/
|
||||
/** When NetPlay disconnected, returns GetJoystick(). Else, **/
|
||||
/** exchanges joystick states over the network and presents **/
|
||||
/** server as player #1, client as player #2. **/
|
||||
/*************************************************************/
|
||||
unsigned int NETJoystick(void);
|
||||
|
||||
/** NETConnected() *******************************************/
|
||||
/** Returns NET_SERVER, NET_CLIENT, or NET_OFF. **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETConnected(void);
|
||||
|
||||
/** NETConnect() *********************************************/
|
||||
/** Connects to Server:Port. When Host=0, becomes a server, **/
|
||||
/** waits at for an incoming request, and connects. Returns **/
|
||||
/** the NetPlay connection status, like NETConnected(). **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETConnect(const char *Server,unsigned short Port);
|
||||
|
||||
/** UDPConnect() *********************************************/
|
||||
/** Connects to Server:Port. When Server=0, becomes server, **/
|
||||
/** waits at for an incoming request, and connects. Returns **/
|
||||
/** the NetPlay connection status, like NETConnected(). **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int UDPConnect(const char *Server,unsigned short Port);
|
||||
|
||||
/** NETClose() ***********************************************/
|
||||
/** Closes connection open with NETConnect(). **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
void NETClose(void);
|
||||
|
||||
/** NETConnectAsync() ****************************************/
|
||||
/** Asynchronous version of NETConnect(). **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETConnectAsync(const char *Server,unsigned short Port);
|
||||
|
||||
/** NETBlock() ***********************************************/
|
||||
/** Makes NETSend()/NETRecv() blocking or not blocking. **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETBlock(int Switch);
|
||||
|
||||
/** NETSend() ************************************************/
|
||||
/** Send N bytes. Returns number of bytes sent or 0. **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETSend(const char *Out,int N);
|
||||
|
||||
/** NETRecv() ************************************************/
|
||||
/** Receive N bytes. Returns number of bytes received or 0. **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
int NETRecv(char *In,int N);
|
||||
|
||||
/** NETMyName() **********************************************/
|
||||
/** Returns local hostname/address or 0 on failure. **/
|
||||
/*************************************** PLATFORM DEPENDENT **/
|
||||
const char *NETMyName(char *Buffer,int MaxChars);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* NETPLAY_H */
|
||||
Executable
+533
@@ -0,0 +1,533 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Record.c **/
|
||||
/** **/
|
||||
/** This file contains routines for gameplay recording and **/
|
||||
/** replay. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2013-2016 **/
|
||||
/** The contents of this file are property of Marat **/
|
||||
/** Fayzullin and should only be used as agreed with **/
|
||||
/** him. The file is confidential. Absolutely no **/
|
||||
/** distribution allowed. **/
|
||||
/*************************************************************/
|
||||
#include "Record.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef DEFINE_ONCE
|
||||
#define DEFINE_ONCE
|
||||
|
||||
#define RPL_RECSIZE 64
|
||||
#define RPL_BUFSIZE 16
|
||||
#define RPL_STEP 60
|
||||
#define RPL_SIGNSIZE 12
|
||||
|
||||
#define READ_INT(Buf) \
|
||||
((Buf)[0]+((int)(Buf)[1]<<8)+((int)(Buf)[2]<<16)+((int)(Buf)[3]<<24))
|
||||
|
||||
#define WRITE_INT(Buf,V) { \
|
||||
(Buf)[0] = ((V)&0xFF); \
|
||||
(Buf)[1] = (((V)>>8)&0xFF); \
|
||||
(Buf)[2] = (((V)>>16)&0xFF); \
|
||||
(Buf)[3] = (((V)>>24)&0xFF); \
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char *State;
|
||||
unsigned int StateSize;
|
||||
unsigned int JoyState[RPL_RECSIZE];
|
||||
unsigned int Count[RPL_RECSIZE];
|
||||
unsigned char KeyState[RPL_RECSIZE][16];
|
||||
} RPLState;
|
||||
|
||||
static RPLState RPLData[RPL_BUFSIZE] = {0};
|
||||
static unsigned int StateSize = 0;
|
||||
static int RPLRCount = -1;
|
||||
static int RPLWCount = -1;
|
||||
static int RPtr1,RPtr2;
|
||||
static int WPtr1,WPtr2;
|
||||
|
||||
static unsigned int (*SaveState)(unsigned char *,unsigned int) = 0;
|
||||
static unsigned int (*LoadState)(unsigned char *,unsigned int) = 0;
|
||||
|
||||
/** RPLInit() ************************************************/
|
||||
/** Initialize record/relay subsystem. **/
|
||||
/*************************************************************/
|
||||
void RPLInit(unsigned int (*SaveHandler)(unsigned char *,unsigned int),unsigned int (*LoadHandler)(unsigned char *,unsigned int),unsigned int MaxSize)
|
||||
{
|
||||
RPLTrash();
|
||||
SaveState = SaveHandler;
|
||||
LoadState = LoadHandler;
|
||||
StateSize = MaxSize;
|
||||
}
|
||||
|
||||
/** RPLTrash() ***********************************************/
|
||||
/** Free all record/replay resources. **/
|
||||
/*************************************************************/
|
||||
void RPLTrash(void)
|
||||
{
|
||||
/* Free recording buffers */
|
||||
RPLRecord(RPL_RESET);
|
||||
/* Disable both recording and playback */
|
||||
RPLRecord(RPL_OFF);
|
||||
RPLPlay(RPL_OFF);
|
||||
}
|
||||
|
||||
/** RPLRecord() **********************************************/
|
||||
/** Record emulation state and joystick input for replaying **/
|
||||
/** it back later. **/
|
||||
/*************************************************************/
|
||||
int RPLRecord(unsigned int Cmd) { return(RPLRecordKeys(Cmd,0,0)); }
|
||||
|
||||
/** RPLRecordKeys() ******************************************/
|
||||
/** Record emulation state, keys, and joystick input for **/
|
||||
/** replaying them back later. **/
|
||||
/*************************************************************/
|
||||
int RPLRecordKeys(unsigned int Cmd,const unsigned char *Keys,unsigned int KeySize)
|
||||
{
|
||||
int J;
|
||||
|
||||
/* Insure that recording is initialized */
|
||||
if(!SaveState || !LoadState || !StateSize) return(0);
|
||||
|
||||
/* Toggle recording as necessary */
|
||||
if(Cmd==RPL_TOGGLE) Cmd=RPLWCount<0? RPL_ON:RPL_OFF;
|
||||
|
||||
/* Reset recording as necessary */
|
||||
if(Cmd==RPL_RESET) { RPLWCount=-1;Cmd=RPL_ON; }
|
||||
|
||||
/* Act on recording command */
|
||||
switch(Cmd)
|
||||
{
|
||||
case RPL_ON:
|
||||
/* If recording already on, do nothing */
|
||||
if(RPLWCount>=0) return(1);
|
||||
/* Clear current records */
|
||||
for(J=0;J<RPL_BUFSIZE;++J)
|
||||
{
|
||||
if(RPLData[J].State) { free(RPLData[J].State);RPLData[J].State=0; }
|
||||
RPLData[J].StateSize = 0;
|
||||
RPLData[J].Count[0] = 0;
|
||||
}
|
||||
/* Reset recording and replay */
|
||||
RPLRCount = -1;
|
||||
RPLWCount = 0;
|
||||
RPtr1 = 0;
|
||||
WPtr1 = 0;
|
||||
RPtr2 = -1;
|
||||
WPtr2 = 0;
|
||||
/* Done */
|
||||
return(1);
|
||||
|
||||
case RPL_OFF:
|
||||
/* Stop recording */
|
||||
RPLWCount=-1;
|
||||
return(0);
|
||||
|
||||
case RPL_QUERY:
|
||||
/* Return current recording state */
|
||||
return(RPLWCount>=0);
|
||||
}
|
||||
|
||||
/* If not recording or replaying, return immediately */
|
||||
if((RPLWCount<0) || (RPLRCount>=0)) return(0);
|
||||
|
||||
/* If not creating a new state record yet... */
|
||||
if((++RPLWCount<RPL_STEP) && RPLData[WPtr1].Count[WPtr2])
|
||||
{
|
||||
/* If no keys, no changes to them */
|
||||
if(!Keys) J=0;
|
||||
else
|
||||
{
|
||||
/* Make sure we do not exceed KeyState[] size */
|
||||
if(KeySize>sizeof(RPLData[0].KeyState[0]))
|
||||
KeySize = sizeof(RPLData[0].KeyState[0]);
|
||||
/* Detect changes in keyboard state */
|
||||
J = memcmp(Keys,RPLData[WPtr1].KeyState[WPtr2],KeySize);
|
||||
}
|
||||
|
||||
/* If same joystick and keyboard states, just increment counter */
|
||||
if(!J && (RPLData[WPtr1].JoyState[WPtr2]==Cmd))
|
||||
{
|
||||
++RPLData[WPtr1].Count[WPtr2];
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* If empty input record or created new record... */
|
||||
if(!RPLData[WPtr1].Count[WPtr2] || (++WPtr2<RPL_RECSIZE))
|
||||
{
|
||||
/* Start filling up the new input record */
|
||||
RPLData[WPtr1].JoyState[WPtr2] = Cmd;
|
||||
RPLData[WPtr1].Count[WPtr2] = 1;
|
||||
|
||||
/* Save keyboard state if supplied */
|
||||
if(Keys) memcpy(RPLData[WPtr1].KeyState[WPtr2],Keys,KeySize);
|
||||
|
||||
/* Terminate new input record */
|
||||
if(WPtr2<RPL_RECSIZE-1) RPLData[WPtr1].Count[WPtr2+1]=0;
|
||||
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creating a new state record
|
||||
*/
|
||||
|
||||
/* Go to the next state slot */
|
||||
if(WPtr2 || RPLData[WPtr1].Count[WPtr2])
|
||||
{
|
||||
WPtr1 = (WPtr1+1)&(RPL_BUFSIZE-1);
|
||||
WPtr2 = 0;
|
||||
|
||||
/* Bump the replay position */
|
||||
if(RPtr1==WPtr1)
|
||||
{
|
||||
RPtr1 = ((RPtr1+1)&(RPL_BUFSIZE-1));
|
||||
RPtr2 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for the state buffer, if needed */
|
||||
if(!RPLData[WPtr1].State)
|
||||
RPLData[WPtr1].State = malloc(StateSize);
|
||||
|
||||
/* If there is a state buffer, save emulation state */
|
||||
RPLData[WPtr1].StateSize =
|
||||
RPLData[WPtr1].State? SaveState(RPLData[WPtr1].State,StateSize):0;
|
||||
|
||||
/* Start a new input record */
|
||||
RPLData[WPtr1].JoyState[WPtr2] = Cmd;
|
||||
RPLData[WPtr1].Count[WPtr2] = 1;
|
||||
|
||||
/* Save keyboard state if supplied */
|
||||
if(Keys) memcpy(RPLData[WPtr1].KeyState[WPtr2],Keys,KeySize);
|
||||
|
||||
/* Terminate new input record */
|
||||
if(WPtr2<RPL_RECSIZE-1) RPLData[WPtr1].Count[WPtr2+1]=0;
|
||||
|
||||
/* Start counting until the next SaveState() */
|
||||
RPLWCount = 0;
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** RPLPlay() ************************************************/
|
||||
/** Replay gameplay saved with RPLRecord(). **/
|
||||
/*************************************************************/
|
||||
unsigned int RPLPlay(int Cmd) { return(RPLPlayKeys(Cmd,0,0)); }
|
||||
|
||||
/** RPLPlayKeys() ********************************************/
|
||||
/** Replay gameplay saved with RPLRecordKeys(). **/
|
||||
/*************************************************************/
|
||||
unsigned int RPLPlayKeys(int Cmd,unsigned char *Keys,unsigned int KeySize)
|
||||
{
|
||||
/* Insure that recording is initialized */
|
||||
if(!SaveState || !LoadState || !StateSize) return(0);
|
||||
|
||||
/* Toggle replay as necessary */
|
||||
if(Cmd==RPL_TOGGLE) Cmd=RPLRCount<0? RPL_ON:RPL_OFF;
|
||||
|
||||
/* Reset replay as necessary */
|
||||
if(Cmd==RPL_RESET) { RPLRCount=-1;Cmd=RPL_ON; }
|
||||
|
||||
/* Act on replay command */
|
||||
switch(Cmd)
|
||||
{
|
||||
case RPL_ON:
|
||||
/* If replay already on, do nothing */
|
||||
if(RPLRCount>=0) return(1);
|
||||
/* Look for the oldest valid state to replay */
|
||||
for(RPtr1=(WPtr1+1)%(RPL_BUFSIZE-1);RPtr1!=WPtr1;RPtr1=(RPtr1+1)%(RPL_BUFSIZE-1))
|
||||
if(RPLData[RPtr1].State && RPLData[RPtr1].StateSize && RPLData[RPtr1].Count[0])
|
||||
{
|
||||
/* State found, replay from that state */
|
||||
RPLRCount = 0;
|
||||
RPtr2 = -1;
|
||||
return(1);
|
||||
}
|
||||
/* State not found */
|
||||
return(0);
|
||||
|
||||
case RPL_NEXT:
|
||||
/* This will play the next record */
|
||||
if(RPLRCount<0) return(0);
|
||||
break;
|
||||
|
||||
case RPL_OFF:
|
||||
/* If terminating playback while recording... */
|
||||
if((RPLRCount>=0) && (RPLWCount>=0))
|
||||
{
|
||||
/* Set recording to the spot where playback ends */
|
||||
WPtr1 = RPtr1;
|
||||
WPtr2 = RPtr2;
|
||||
|
||||
/* Truncate last input record */
|
||||
RPLData[WPtr1].Count[WPtr2]-=RPLRCount;
|
||||
|
||||
/* Terminate truncated input record */
|
||||
if(WPtr2<RPL_RECSIZE-1) RPLData[WPtr1].Count[WPtr2+1]=0;
|
||||
}
|
||||
/* Playback now off */
|
||||
RPLRCount = -1;
|
||||
return(0);
|
||||
|
||||
case RPL_QUERY:
|
||||
default:
|
||||
/* Return current replay state */
|
||||
return(RPLRCount>=0);
|
||||
}
|
||||
|
||||
/* If finished repeating previous joystick state... */
|
||||
if(!RPLRCount)
|
||||
{
|
||||
/* Stop at the current recording position */
|
||||
if((RPtr1==WPtr1) && (RPtr2==WPtr2)) { RPLPlay(RPL_OFF);return(RPL_ENDED); }
|
||||
|
||||
/* Go to the next input record inside a state slot */
|
||||
if((RPtr2<0) || (++RPtr2>=RPL_RECSIZE) || !RPLData[RPtr1].Count[RPtr2])
|
||||
{
|
||||
/* Go to the next state slot */
|
||||
RPtr1 = RPtr2>=0? ((RPtr1+1)&(RPL_BUFSIZE-1)) : RPtr1;
|
||||
|
||||
/* Exit when done with replay */
|
||||
if(!RPLData[RPtr1].Count[0]) { RPLPlay(RPL_OFF);return(RPL_ENDED); }
|
||||
|
||||
/* Load next emulation state, if present */
|
||||
if(RPLData[RPtr1].State && RPLData[RPtr1].StateSize)
|
||||
if(!LoadState(RPLData[RPtr1].State,RPLData[RPtr1].StateSize))
|
||||
{ RPLPlay(RPL_OFF);return(RPL_ENDED); }
|
||||
|
||||
/* Go to the first record */
|
||||
RPtr2 = 0;
|
||||
}
|
||||
|
||||
/* New joystick state will be valid for this many frames */
|
||||
RPLRCount = RPLData[RPtr1].Count[RPtr2];
|
||||
if(!RPLRCount) { RPLPlay(RPL_OFF);return(RPL_ENDED); }
|
||||
}
|
||||
|
||||
/* Load keyboard state if supplied */
|
||||
if(Keys)
|
||||
{
|
||||
if(KeySize>sizeof(RPLData[0].KeyState[0]))
|
||||
KeySize = sizeof(RPLData[0].KeyState[0]);
|
||||
memcpy(Keys,RPLData[RPtr1].KeyState[RPtr2],KeySize);
|
||||
}
|
||||
|
||||
/* Return joystick state */
|
||||
--RPLRCount;
|
||||
return(RPLData[RPtr1].JoyState[RPtr2]);
|
||||
}
|
||||
|
||||
/** SaveRPL() ************************************************/
|
||||
/** Save gameplay recording into given file. **/
|
||||
/*************************************************************/
|
||||
int SaveRPL(const char *FileName)
|
||||
{
|
||||
static unsigned char Header[16] = "RPL\032\001\0\0\0\0\0\0\0\0\0\0\0";
|
||||
unsigned char Buf[16];
|
||||
FILE *F;
|
||||
int J,K;
|
||||
|
||||
/* Look for the oldest valid state to replay */
|
||||
for(J=(WPtr1+1)%(RPL_BUFSIZE-1);J!=WPtr1;J=(J+1)%(RPL_BUFSIZE-1))
|
||||
if(RPLData[J].State && RPLData[J].StateSize && RPLData[J].Count[0]) break;
|
||||
|
||||
/* If state not found, drop out */
|
||||
if(J==WPtr1) return(0);
|
||||
|
||||
/* Open file */
|
||||
F = fopen(FileName,"wb");
|
||||
if(!F) return(0);
|
||||
|
||||
/* Fill and write header */
|
||||
WRITE_INT(Header+5,RPLData[J].StateSize);
|
||||
if(fwrite(Header,1,sizeof(Header),F)!=sizeof(Header))
|
||||
{ fclose(F);unlink(FileName);return(0); }
|
||||
|
||||
/* Write initial state */
|
||||
if(fwrite(RPLData[J].State,1,RPLData[J].StateSize,F)!=RPLData[J].StateSize)
|
||||
{ fclose(F);unlink(FileName);return(0); }
|
||||
|
||||
/* Write input records */
|
||||
for(;J!=WPtr1;J=(J+1)&(RPL_BUFSIZE-1))
|
||||
for(K=0;(K<RPL_RECSIZE)&&RPLData[J].Count[K];++K)
|
||||
{
|
||||
WRITE_INT(Buf, RPLData[J].Count[K]);
|
||||
WRITE_INT(Buf+4,RPLData[J].JoyState[K]);
|
||||
|
||||
if(fwrite(Buf,1,8,F)!=8)
|
||||
{ fclose(F);unlink(FileName);return(0); }
|
||||
}
|
||||
|
||||
/* Write terminating record */
|
||||
memset(Buf,0x00,8);
|
||||
if(fwrite(Buf,1,8,F)!=8)
|
||||
{ fclose(F);unlink(FileName);return(0); }
|
||||
|
||||
/* Done */
|
||||
fclose(F);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** LoadRPL() ************************************************/
|
||||
/** Load gameplay recording from given file. **/
|
||||
/*************************************************************/
|
||||
int LoadRPL(const char *FileName)
|
||||
{
|
||||
unsigned char Header[16];
|
||||
unsigned char Buf[16],*P;
|
||||
int J,K;
|
||||
FILE *F;
|
||||
|
||||
/* Open file */
|
||||
F = fopen(FileName,"rb");
|
||||
if(!F) return(0);
|
||||
|
||||
/* Read and verify header */
|
||||
if(fread(Header,1,sizeof(Header),F)!=sizeof(Header)) { fclose(F);return(0); }
|
||||
if(memcmp(Header,"RPL\032\001",5)) { fclose(F);return(0); }
|
||||
|
||||
/* Allocate state buffer */
|
||||
J = READ_INT(Header+5);
|
||||
P = malloc(J);
|
||||
if(!P) { fclose(F);return(0); }
|
||||
|
||||
/* Read state */
|
||||
if(fread(P,1,J,F)!=J) { fclose(F);free(P);return(0); }
|
||||
|
||||
/* State loaded, move it in */
|
||||
RPLTrash();
|
||||
RPLData[0].State = P;
|
||||
RPLData[0].StateSize = J;
|
||||
|
||||
/* Read input records */
|
||||
for(RPtr1=J=K=0;(K>=0)&&(J<RPL_BUFSIZE);J=(J+1)&(RPL_BUFSIZE-1))
|
||||
for(K=0;K<RPL_RECSIZE;++K)
|
||||
{
|
||||
/* Read next input record from file */
|
||||
if(fread(Buf,1,8,F)!=8)
|
||||
{
|
||||
RPLData[J].Count[K] = 0;
|
||||
RPLData[J].JoyState[K] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
RPLData[J].Count[K] = READ_INT(Buf);
|
||||
RPLData[J].JoyState[K] = READ_INT(Buf+4);
|
||||
}
|
||||
|
||||
/* If read null-record, or incomplete record, finish */
|
||||
if(!RPLData[J].Count[K]) { K=-1;break; }
|
||||
}
|
||||
|
||||
/* Done */
|
||||
WPtr1 = J;
|
||||
fclose(F);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#endif /* DEFINE_ONCE */
|
||||
|
||||
#if defined(BPP8) || defined(BPP16) || defined(BPP24) || defined(BPP32)
|
||||
#define CLR_FG PIXEL(255,255,255)
|
||||
#define CLR_BG PIXEL(0,0,0)
|
||||
|
||||
/** RPLShow() ************************************************/
|
||||
/** Draw replay icon when active. **/
|
||||
/*************************************************************/
|
||||
void RPLShow(Image *Img,int X,int Y)
|
||||
{
|
||||
pixel *P;
|
||||
int J,I;
|
||||
|
||||
/* Draw nothing when record/replay is inactive */
|
||||
if((RPLWCount<0) && (RPLRCount<0)) return;
|
||||
|
||||
/* Starting address to draw the arrow */
|
||||
P = (pixel *)Img->Data + Img->L*Y + X;
|
||||
|
||||
/* If replay active... */
|
||||
if(RPLRCount>=0)
|
||||
{
|
||||
/* Replay is active */
|
||||
for(J=1;J<=RPL_SIGNSIZE/2;++J,P+=Img->L)
|
||||
{
|
||||
P[0] = CLR_BG;
|
||||
for(I=1;I<J;++I) P[I]=CLR_FG;
|
||||
P[J] = CLR_BG;
|
||||
}
|
||||
|
||||
for(J-=2;J;--J,P+=Img->L)
|
||||
{
|
||||
P[0] = CLR_BG;
|
||||
for(I=1;I<J;++I) P[I]=CLR_FG;
|
||||
P[J] = CLR_BG;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Recording is active */
|
||||
for(J=0;J<=RPL_SIGNSIZE/2;++J,P+=Img->L)
|
||||
{
|
||||
I = RPL_SIGNSIZE/2-J;
|
||||
P[I] = CLR_BG;
|
||||
while(I<RPL_SIGNSIZE/2+J) P[++I]=CLR_FG;
|
||||
P[I] = CLR_BG;
|
||||
}
|
||||
|
||||
for(J-=2;J>=0;--J,P+=Img->L)
|
||||
{
|
||||
I = RPL_SIGNSIZE/2-J;
|
||||
P[I] = CLR_BG;
|
||||
while(I<RPL_SIGNSIZE/2+J) P[++I]=CLR_FG;
|
||||
P[I] = CLR_BG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef CLR_FG
|
||||
#undef CLR_BG
|
||||
#else /* !BPP8 && !BPP16 && !BPP24 && !BPP32 */
|
||||
|
||||
#define BPP8
|
||||
#define pixel unsigned char
|
||||
#define RPLShow RPLShow_8
|
||||
#include "Record.c"
|
||||
#undef pixel
|
||||
#undef RPLShow
|
||||
#undef BPP8
|
||||
|
||||
#define BPP16
|
||||
#define pixel unsigned short
|
||||
#define RPLShow RPLShow_16
|
||||
#include "Record.c"
|
||||
#undef pixel
|
||||
#undef RPLShow
|
||||
#undef BPP16
|
||||
|
||||
#define BPP32
|
||||
#define pixel unsigned int
|
||||
#define RPLShow RPLShow_32
|
||||
#include "Record.c"
|
||||
#undef pixel
|
||||
#undef RPLShow
|
||||
#undef BPP32
|
||||
|
||||
void RPLShow(Image *Img,int X,int Y)
|
||||
{
|
||||
switch(Img->D)
|
||||
{
|
||||
case 8: RPLShow_8(Img,X,Y);break;
|
||||
case 16: RPLShow_16(Img,X,Y);break;
|
||||
case 24:
|
||||
case 32: RPLShow_32(Img,X,Y);break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !BPP8 && !BPP16 && !BPP24 && !BPP32 */
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** Record.h **/
|
||||
/** **/
|
||||
/** This file contains routines for gameplay recording and **/
|
||||
/** replay. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2013-2016 **/
|
||||
/** The contents of this file are property of Marat **/
|
||||
/** Fayzullin and should only be used as agreed with **/
|
||||
/** him. The file is confidential. Absolutely no **/
|
||||
/** distribution allowed. **/
|
||||
/*************************************************************/
|
||||
#ifndef RECORD_H
|
||||
#define RECORD_H
|
||||
|
||||
#include "EMULib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** RPLPlay()/RPLRecord() arguments **************************/
|
||||
#define RPL_OFF 0xFFFFFFFF /* Disable */
|
||||
#define RPL_ON 0xFFFFFFFE /* Enable */
|
||||
#define RPL_TOGGLE 0xFFFFFFFD /* Toggle */
|
||||
#define RPL_RESET 0xFFFFFFFC /* Reset and enable */
|
||||
#define RPL_NEXT 0xFFFFFFFB /* Play the next record */
|
||||
#define RPL_QUERY 0xFFFFFFFA /* Query state */
|
||||
|
||||
/** RPLPlay(RPL_NEXT) results ********************************/
|
||||
#define RPL_ENDED 0xFFFFFFFF /* Finished or stopped */
|
||||
|
||||
/** RPLInit() ************************************************/
|
||||
/** Initialize record/relay subsystem. **/
|
||||
/*************************************************************/
|
||||
void RPLInit(unsigned int (*SaveHandler)(unsigned char *,unsigned int),unsigned int (*LoadHandler)(unsigned char *,unsigned int),unsigned int MaxSize);
|
||||
|
||||
/** RPLTrash() ***********************************************/
|
||||
/** Free all record/replay resources. **/
|
||||
/*************************************************************/
|
||||
void RPLTrash(void);
|
||||
|
||||
/** RPLRecord() **********************************************/
|
||||
/** Record emulation state and joystick input for replaying **/
|
||||
/** it back later. **/
|
||||
/*************************************************************/
|
||||
int RPLRecord(unsigned int JoyState);
|
||||
|
||||
/** RPLRecordKeys() ******************************************/
|
||||
/** Record emulation state, keys, and joystick input for **/
|
||||
/** replaying them back later. **/
|
||||
/*************************************************************/
|
||||
int RPLRecordKeys(unsigned int JoyState,const unsigned char *Keys,unsigned int KeySize);
|
||||
|
||||
/** RPLPlay() ************************************************/
|
||||
/** Replay gameplay saved with RPLRecord(). **/
|
||||
/*************************************************************/
|
||||
unsigned int RPLPlay(int Cmd);
|
||||
|
||||
/** RPLPlayKeys() ********************************************/
|
||||
/** Replay gameplay saved with RPLRecordKeys(). **/
|
||||
/*************************************************************/
|
||||
unsigned int RPLPlayKeys(int Cmd,unsigned char *Keys,unsigned int KeySize);
|
||||
|
||||
/** RPLShow() ************************************************/
|
||||
/** Draw replay icon when active. **/
|
||||
/*************************************************************/
|
||||
void RPLShow(Image *Img,int X,int Y);
|
||||
|
||||
/** SaveRPL() ************************************************/
|
||||
/** Save gameplay recording into given file. **/
|
||||
/*************************************************************/
|
||||
int SaveRPL(const char *FileName);
|
||||
|
||||
/** LoadRPL() ************************************************/
|
||||
/** Load gameplay recording from given file. **/
|
||||
/*************************************************************/
|
||||
int LoadRPL(const char *FileName);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* RECORD_H */
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
###
|
||||
### Include this file in the first line of your Makefile when compiling
|
||||
### EMULib application for FreeBSD, NetBSD, OpenBSD, Linux, or any other
|
||||
### generic Unix flavor.
|
||||
###
|
||||
|
||||
include ../../EMULib/Rules.gcc
|
||||
|
||||
CFLAGS += -I$(EMULIB)/Unix -I/usr/X11R6/include
|
||||
DEFINES+= -DUNIX -DMITSHM -DBPS16
|
||||
LIBS += -lX11 -lXext
|
||||
OBJECTS+= $(EMUUNIX)
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
BASEDIR = ../..
|
||||
EMULIB = $(BASEDIR)/EMULib
|
||||
LIBARM = $(BASEDIR)/ARM
|
||||
LIBZ80 = $(BASEDIR)/Z80
|
||||
LIB6502 = $(BASEDIR)/M6502
|
||||
LIB68K = $(BASEDIR)/M68000
|
||||
LIBGBZ = $(BASEDIR)/GBZ80
|
||||
PRIVATE = $(BASEDIR)/Private
|
||||
|
||||
CXX = g++
|
||||
CC = gcc
|
||||
CPP = cpp
|
||||
MOC = moc
|
||||
SDT2GAS = perl $(EMULIB)/Tools/sdt2gas.pl
|
||||
CFLAGS = -O2 -pthread -I. -I.. -I$(EMULIB)
|
||||
DEFINES = -DZLIB
|
||||
LIBS = -lz -lpthread
|
||||
|
||||
# EMULib sound, console, and other utility functions
|
||||
OBJECTS = $(EMULIB)/EMULib.o $(EMULIB)/Sound.o \
|
||||
$(EMULIB)/Image.o $(EMULIB)/Console.o \
|
||||
$(EMULIB)/Record.o $(EMULIB)/NetPlay.o \
|
||||
$(EMULIB)/Touch.o
|
||||
|
||||
# Platform-specific EMULib files
|
||||
EMUUNIX = $(EMULIB)/Unix/LibUnix.o $(EMULIB)/Unix/SndUnix.o \
|
||||
$(EMULIB)/Unix/NetUnix.o
|
||||
EMUMAEMO= $(EMULIB)/Maemo/LibMaemo.o $(EMULIB)/Unix/GConf.o \
|
||||
$(EMULIB)/Unix/NetUnix.o $(EMULIB)/LibARM-BPP16.o
|
||||
EMUMEEGO= $(EMULIB)/Meego/LibMeego.o $(EMULIB)/Unix/GConf.o \
|
||||
$(EMULIB)/Unix/NetUnix.o $(EMULIB)/LibARM-BPP16.o
|
||||
EMUSTMP = $(EMULIB)/STMP3700/LibSTMP3700.o $(EMULIB)/Unix/SndALSA.o \
|
||||
$(EMULIB)/LibARM-BPP16.o $(EMULIB)/LibARM-BPP32.o
|
||||
EMUNXC = $(EMULIB)/NXC2600/LibNXC2600.o $(EMULIB)/Unix/SndSDL.o
|
||||
|
||||
# SHA1 computation library
|
||||
SHA1 = $(EMULIB)/SHA1.o
|
||||
|
||||
# CRC32 computation library
|
||||
CRC32 = $(EMULIB)/CRC32.o
|
||||
|
||||
# .IPS file patch library
|
||||
IPS = $(EMULIB)/IPS.o
|
||||
|
||||
# .INI file access library
|
||||
INIFILE = $(EMULIB)/INIFile.o
|
||||
|
||||
# Record/replay library
|
||||
RECORD = $(EMULIB)/Record.o
|
||||
|
||||
# Cheat code hunting library
|
||||
HUNT = $(EMULIB)/Hunt.o
|
||||
|
||||
# 720kB floppy utility library
|
||||
FLOPPY = $(EMULIB)/Floppy.o
|
||||
|
||||
# Disk image utility library
|
||||
FDIDISK = $(EMULIB)/FDIDisk.o
|
||||
|
||||
# CPU emulation libraries
|
||||
ARM = $(LIBARM)/ARM.o $(LIBARM)/ConDebug.o
|
||||
Z80 = $(LIBZ80)/Z80.o $(LIBZ80)/ConDebug.o
|
||||
GBZ80 = $(LIBGBZ)/Z80.o $(LIBGBZ)/ConDebug.o
|
||||
M6502 = $(LIB6502)/M6502.o $(LIB6502)/ConDebug.o
|
||||
M68000 = $(LIB68K)/M68000.o $(LIB68K)/ConDebug.o
|
||||
|
||||
# Optimized CPU emulation
|
||||
ARMONARM = $(ARM) \
|
||||
$(LIBARM)/ARMonARM/OptARM16.o \
|
||||
$(LIBARM)/ARMonARM/OptARM32.o
|
||||
M6502ONARM = $(M6502) $(LIB6502)/M6502-ARM.o
|
||||
|
||||
# TMS9918/9928/9929 VDP emulation
|
||||
TMS9918 = $(EMULIB)/TMS9918.o $(EMULIB)/DRV9918.o
|
||||
|
||||
# Disk controller emulation libraries
|
||||
WD1793 = $(EMULIB)/WD1793.o
|
||||
UPD765 = $(EMULIB)/uPD765.o
|
||||
WD2793 = $(WD1793)
|
||||
I8272 = $(UPD765)
|
||||
|
||||
# C93xx/C94xx EEPROM chips
|
||||
C93XX = $(EMULIB)/C93XX.o
|
||||
|
||||
# Intel 8255 PPI chip
|
||||
I8255 = $(EMULIB)/I8255.o
|
||||
|
||||
# Sound chip emulation libraries
|
||||
AY8910 = $(EMULIB)/AY8910.o
|
||||
SN76489 = $(EMULIB)/SN76489.o
|
||||
SAA1099 = $(EMULIB)/SAA1099.o
|
||||
YM2413 = $(EMULIB)/YM2413.o
|
||||
SCC = $(EMULIB)/SCC.o
|
||||
GBSND = $(PRIVATE)/GBSND.o
|
||||
NESSND = $(PRIVATE)/NESSND.o
|
||||
|
||||
# Cartridge parsing utilities
|
||||
NESCART = $(EMULIB)/NESCarts.o
|
||||
GBCART = $(EMULIB)/GBCarts.o
|
||||
GBACART = $(EMULIB)/GBACarts.o
|
||||
DSCART = $(EMULIB)/DSCarts.o
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
%.o: %.cc
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
%.o: %.s
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
%.s: %.asm
|
||||
$(SDT2GAS) $< >$@
|
||||
%.moc: %.h
|
||||
$(MOC) $(DEFINES) $< >$@
|
||||
Executable
+876
@@ -0,0 +1,876 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** LibUnix.c **/
|
||||
/** **/
|
||||
/** This file contains Unix-dependent implementation **/
|
||||
/** parts of the emulation library. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "EMULib.h"
|
||||
#include "Sound.h"
|
||||
#include "Console.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef MITSHM
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
#define FPS_COLOR PIXEL(255,0,255)
|
||||
|
||||
extern int MasterSwitch; /* Switches to turn channels on/off */
|
||||
extern int MasterVolume; /* Master volume */
|
||||
|
||||
static volatile int TimerReady = 0; /* 1: Sync timer ready */
|
||||
static volatile unsigned int JoyState = 0; /* Joystick state */
|
||||
static volatile unsigned int LastKey = 0; /* Last key prsd */
|
||||
static volatile unsigned int KeyModes = 0; /* SHIFT/CTRL/ALT */
|
||||
|
||||
static int Effects = EFF_SCALE|EFF_SAVECPU; /* EFF_* bits */
|
||||
static int TimerON = 0; /* 1: sync timer is running */
|
||||
static Display *Dsp = 0; /* X11 display */
|
||||
static Screen *Scr = 0; /* X11 screen */
|
||||
static Window Wnd = 0; /* X11 window */
|
||||
static Colormap CMap; /* X11 color map */
|
||||
static Image OutImg; /* Scaled output image buffer */
|
||||
static const char *AppTitle; /* Current window title */
|
||||
static int XSize,YSize; /* Current window dimensions */
|
||||
|
||||
static int FrameCount; /* Frame counter for EFF_SHOWFPS */
|
||||
static int FrameRate; /* Last frame rate value */
|
||||
static struct timeval TimeStamp; /* Last timestamp */
|
||||
|
||||
/** TimerHandler() *******************************************/
|
||||
/** The main timer handler used by SetSyncTimer(). **/
|
||||
/*************************************************************/
|
||||
static void TimerHandler(int Arg)
|
||||
{
|
||||
/* Mark sync timer as "ready" */
|
||||
TimerReady=1;
|
||||
/* Repeat signal next time */
|
||||
signal(Arg,TimerHandler);
|
||||
}
|
||||
|
||||
/** InitUnix() ***********************************************/
|
||||
/** Initialize Unix/X11 resources and set initial window **/
|
||||
/** title and dimensions. **/
|
||||
/*************************************************************/
|
||||
int InitUnix(const char *Title,int Width,int Height)
|
||||
{
|
||||
/* Initialize variables */
|
||||
AppTitle = Title;
|
||||
XSize = Width;
|
||||
YSize = Height;
|
||||
TimerON = 0;
|
||||
TimerReady = 0;
|
||||
JoyState = 0;
|
||||
LastKey = 0;
|
||||
KeyModes = 0;
|
||||
Wnd = 0;
|
||||
Dsp = 0;
|
||||
Scr = 0;
|
||||
CMap = 0;
|
||||
FrameCount = 0;
|
||||
FrameRate = 0;
|
||||
|
||||
/* Get initial timestamp */
|
||||
gettimeofday(&TimeStamp,0);
|
||||
|
||||
/* No output image yet */
|
||||
OutImg.XImg = 0;
|
||||
#ifdef MITSHM
|
||||
OutImg.SHMInfo.shmaddr = 0;
|
||||
#endif
|
||||
|
||||
/* Open X11 display */
|
||||
if(!(Dsp=XOpenDisplay(0))) return(0);
|
||||
|
||||
/* Get default screen and color map */
|
||||
Scr = DefaultScreenOfDisplay(Dsp);
|
||||
CMap = DefaultColormapOfScreen(Scr);
|
||||
|
||||
/* Done */
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** TrashUnix() **********************************************/
|
||||
/** Free resources allocated in InitUnix() **/
|
||||
/*************************************************************/
|
||||
void TrashUnix(void)
|
||||
{
|
||||
/* Remove sync timer */
|
||||
SetSyncTimer(0);
|
||||
/* Shut down audio */
|
||||
TrashAudio();
|
||||
/* Free output image buffer */
|
||||
FreeImage(&OutImg);
|
||||
|
||||
/* If X11 display open... */
|
||||
if(Dsp)
|
||||
{
|
||||
/* Close the window */
|
||||
if(Wnd) { XDestroyWindow(Dsp,Wnd);Wnd=0; }
|
||||
/* Done with display */
|
||||
XCloseDisplay(Dsp);
|
||||
/* Display now closed */
|
||||
Dsp=0;
|
||||
}
|
||||
}
|
||||
|
||||
/** ShowVideo() **********************************************/
|
||||
/** Show "active" image at the actual screen or window. **/
|
||||
/*************************************************************/
|
||||
int ShowVideo(void)
|
||||
{
|
||||
Image *Output;
|
||||
int SX,SY,SW,SH,J;
|
||||
|
||||
/* Must have active video image, X11 display */
|
||||
if(!Dsp||!VideoImg||!VideoImg->Data) return(0);
|
||||
|
||||
/* If no window yet... */
|
||||
if(!Wnd)
|
||||
{
|
||||
/* Create new window */
|
||||
Wnd=X11Window(AppTitle? AppTitle:"EMULib",Effects&EFF_4X3? 4*YSize/3:XSize,YSize);
|
||||
if(!Wnd) return(0);
|
||||
}
|
||||
|
||||
/* Allocate image buffer if none */
|
||||
if(!OutImg.Data&&!NewImage(&OutImg,Effects&EFF_4X3? 4*YSize/3:XSize,YSize)) return(0);
|
||||
|
||||
/* Wait for all X11 requests to complete, to avoid flicker */
|
||||
XSync(Dsp,False);
|
||||
|
||||
/* If not scaling or post-processing image, avoid extra work */
|
||||
if(!(Effects&(EFF_RASTER_ALL|EFF_MASK_ALL|EFF_SOFTEN_ALL|EFF_VIGNETTE|EFF_SCALE|EFF_4X3)))
|
||||
{
|
||||
#ifdef MITSHM
|
||||
if(VideoImg->Attrs&EFF_MITSHM)
|
||||
XShmPutImage(Dsp,Wnd,DefaultGCOfScreen(Scr),VideoImg->XImg,VideoX,VideoY,(XSize-VideoW)>>1,(YSize-VideoH)>>1,VideoW,VideoH,False);
|
||||
else
|
||||
#endif
|
||||
XPutImage(Dsp,Wnd,DefaultGCOfScreen(Scr),VideoImg->XImg,VideoX,VideoY,(XSize-VideoW)>>1,(YSize-VideoH)>>1,VideoW,VideoH);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* By default, we will be showing OutImg */
|
||||
Output = &OutImg;
|
||||
SX = 0;
|
||||
SY = 0;
|
||||
SW = OutImg.W;
|
||||
SH = OutImg.H;
|
||||
|
||||
/* Interpolate image if required */
|
||||
J = Effects&EFF_SOFTEN_ALL;
|
||||
if((J==EFF_2XSAI) || (J==EFF_HQ4X))
|
||||
SoftenImage(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
else if(J==EFF_EPX)
|
||||
SoftenEPX(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
else if(J==EFF_EAGLE)
|
||||
SoftenEAGLE(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
else if(J==EFF_SCALE2X)
|
||||
SoftenSCALE2X(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
else if(J || (J==EFF_NEAREST))
|
||||
ScaleImage(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
else if((OutImg.W==VideoW)&&(OutImg.H==VideoH))
|
||||
{
|
||||
if(Effects&(EFF_RASTER_ALL|EFF_MASK_ALL))
|
||||
IMGCopy(&OutImg,0,0,VideoImg,VideoX,VideoY,VideoW,VideoH,-1);
|
||||
else
|
||||
{
|
||||
/* Use VideoImg directly */
|
||||
Output = VideoImg;
|
||||
SX = VideoX;
|
||||
SY = VideoY;
|
||||
}
|
||||
}
|
||||
else if(Effects&(EFF_SCALE|EFF_4X3))
|
||||
{
|
||||
/* Scale VideoImg to OutImg */
|
||||
ScaleImage(&OutImg,VideoImg,VideoX,VideoY,VideoW,VideoH);
|
||||
}
|
||||
else if((OutImg.W<=VideoW)&&(OutImg.H<=VideoH))
|
||||
{
|
||||
if(Effects&(EFF_RASTER_ALL|EFF_MASK_ALL))
|
||||
IMGCopy(&OutImg,0,0,VideoImg,VideoX+((VideoW-OutImg.W)>>1),VideoY+((VideoH-OutImg.H)>>1),OutImg.W,OutImg.H,-1);
|
||||
else
|
||||
{
|
||||
/* Use VideoImg directly */
|
||||
Output = VideoImg;
|
||||
SX = VideoX+((VideoW-OutImg.W)>>1);
|
||||
SY = VideoY+((VideoH-OutImg.H)>>1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use rectangle at the center of OutImg */
|
||||
SX = (OutImg.W-VideoW)>>1;
|
||||
SY = (OutImg.H-VideoH)>>1;
|
||||
SW = VideoW;
|
||||
SH = VideoH;
|
||||
/* Center VideoImg in OutImg */
|
||||
IMGCopy(&OutImg,SX,SY,VideoImg,VideoX,VideoY,VideoW,VideoH,-1);
|
||||
}
|
||||
|
||||
/* Apply color mask to the pixels */
|
||||
switch(Effects&EFF_MASK_ALL)
|
||||
{
|
||||
case EFF_CMYMASK: CMYizeImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_RGBMASK: RGBizeImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_MONO: MonoImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_GREEN: GreenImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_AMBER: AmberImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_SEPIA: SepiaImage(&OutImg,SX,SY,SW,SH);break;
|
||||
}
|
||||
|
||||
/* Apply scanlines or raster */
|
||||
switch(Effects&EFF_RASTER_ALL)
|
||||
{
|
||||
case EFF_TVLINES: TelevizeImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_LCDLINES: LcdizeImage(&OutImg,SX,SY,SW,SH);break;
|
||||
case EFF_RASTER: RasterizeImage(&OutImg,SX,SY,SW,SH);break;
|
||||
}
|
||||
|
||||
/* Show framerate if requested */
|
||||
if((Effects&EFF_SHOWFPS)&&(FrameRate>0))
|
||||
{
|
||||
char S[8];
|
||||
sprintf(S,"%dfps",FrameRate);
|
||||
PrintXY(
|
||||
&OutImg,S,
|
||||
((OutImg.W-VideoW)>>1)+8,((OutImg.H-VideoH)>>1)+8,
|
||||
FPS_COLOR,-1
|
||||
);
|
||||
}
|
||||
|
||||
/* Wait for sync timer if requested */
|
||||
if(Effects&EFF_SYNC) WaitSyncTimer();
|
||||
|
||||
/* Copy image to the window, either using SHM or not */
|
||||
#ifdef MITSHM
|
||||
if(VideoImg->Attrs&EFF_MITSHM)
|
||||
XShmPutImage(Dsp,Wnd,DefaultGCOfScreen(Scr),Output->XImg,SX,SY,0,0,OutImg.W,OutImg.H,False);
|
||||
else
|
||||
#endif
|
||||
XPutImage(Dsp,Wnd,DefaultGCOfScreen(Scr),Output->XImg,SX,SY,0,0,OutImg.W,OutImg.H);
|
||||
|
||||
/* Done */
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** GetJoystick() ********************************************/
|
||||
/** Get the state of joypad buttons (1="pressed"). Refer to **/
|
||||
/** the BTN_* #defines for the button mappings. **/
|
||||
/*************************************************************/
|
||||
unsigned int GetJoystick(void)
|
||||
{
|
||||
/* Count framerate */
|
||||
if((Effects&EFF_SHOWFPS)&&(++FrameCount>=300))
|
||||
{
|
||||
struct timeval NewTS;
|
||||
int Time;
|
||||
|
||||
gettimeofday(&NewTS,0);
|
||||
Time = (NewTS.tv_sec-TimeStamp.tv_sec)*1000
|
||||
+ (NewTS.tv_usec-TimeStamp.tv_usec)/1000;
|
||||
FrameRate = 1000*FrameCount/(Time>0? Time:1);
|
||||
TimeStamp = NewTS;
|
||||
FrameCount = 0;
|
||||
FrameRate = FrameRate>999? 999:FrameRate;
|
||||
}
|
||||
|
||||
/* Process any pending events */
|
||||
ProcessEvents(0);
|
||||
|
||||
/* Return current joystick state */
|
||||
return(JoyState|KeyModes);
|
||||
}
|
||||
|
||||
/** GetMouse() ***********************************************/
|
||||
/** Get mouse position and button states in the following **/
|
||||
/** format: RMB.LMB.Y[29-16].X[15-0]. **/
|
||||
/*************************************************************/
|
||||
unsigned int GetMouse(void)
|
||||
{
|
||||
int X,Y,J,Mask;
|
||||
Window W;
|
||||
|
||||
/* Need to have a display and a window */
|
||||
if(!Dsp||!Wnd) return(0);
|
||||
|
||||
/* Query mouse pointer */
|
||||
if(!XQueryPointer(Dsp,Wnd,&W,&W,&J,&J,&X,&Y,&Mask)) return(0);
|
||||
|
||||
/* If scaling video... */
|
||||
if(Effects&(EFF_SOFTEN_ALL|EFF_SCALE|EFF_RASTER_ALL))
|
||||
{
|
||||
/* Scale mouse position */
|
||||
X = VideoW*(X<0? 0:X>=XSize? XSize-1:X)/XSize;
|
||||
Y = VideoH*(Y<0? 0:Y>=YSize? YSize-1:Y)/YSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Translate mouse position */
|
||||
X-= ((XSize-VideoW)>>1);
|
||||
Y-= ((YSize-VideoH)>>1);
|
||||
X = X<0? 0:X>=XSize? XSize-1:X;
|
||||
Y = Y<0? 0:Y>=YSize? YSize-1:Y;
|
||||
}
|
||||
|
||||
/* Return mouse position and buttons */
|
||||
return(
|
||||
(X&MSE_XPOS)
|
||||
| ((Y<<16)&MSE_YPOS)
|
||||
| (Mask&Button1Mask? MSE_LEFT:0)
|
||||
| (Mask&Button3Mask? MSE_RIGHT:0)
|
||||
);
|
||||
}
|
||||
|
||||
/** GetKey() *************************************************/
|
||||
/** Get currently pressed key or 0 if none pressed. Returns **/
|
||||
/** CON_* definitions for arrows and special keys. **/
|
||||
/*************************************************************/
|
||||
unsigned int GetKey(void)
|
||||
{
|
||||
unsigned int J;
|
||||
|
||||
ProcessEvents(0);
|
||||
J=LastKey;
|
||||
LastKey=0;
|
||||
return(J);
|
||||
}
|
||||
|
||||
/** WaitKey() ************************************************/
|
||||
/** Wait for a key to be pressed. Returns CON_* definitions **/
|
||||
/** for arrows and special keys. **/
|
||||
/*************************************************************/
|
||||
unsigned int WaitKey(void)
|
||||
{
|
||||
unsigned int J;
|
||||
|
||||
/* Swallow current keypress */
|
||||
GetKey();
|
||||
/* Wait in 100ms increments for a new keypress */
|
||||
while(!(J=GetKey())&&VideoImg) usleep(100000);
|
||||
/* Return key code */
|
||||
return(J);
|
||||
}
|
||||
|
||||
/** WaitKeyOrMouse() *****************************************/
|
||||
/** Wait for a key or a mouse button to be pressed. Returns **/
|
||||
/** the same result as GetMouse(). If no mouse buttons **/
|
||||
/** reported to be pressed, do GetKey() to fetch a key. **/
|
||||
/*************************************************************/
|
||||
unsigned int WaitKeyOrMouse(void)
|
||||
{
|
||||
unsigned int J;
|
||||
|
||||
/* Swallow current keypress */
|
||||
GetKey();
|
||||
/* Make sure mouse keys are not pressed */
|
||||
while(GetMouse()&MSE_BUTTONS) usleep(100000);
|
||||
/* Wait in 100ms increments for a key or mouse click */
|
||||
while(!(J=GetKey())&&!(GetMouse()&MSE_BUTTONS)&&VideoImg) usleep(100000);
|
||||
/* Place key back into the buffer and return mouse state */
|
||||
LastKey=J;
|
||||
return(GetMouse());
|
||||
}
|
||||
|
||||
/** WaitSyncTimer() ******************************************/
|
||||
/** Wait for the timer to become ready. Returns number of **/
|
||||
/** times timer has been triggered after the last call to **/
|
||||
/** WaitSyncTimer(). **/
|
||||
/*************************************************************/
|
||||
int WaitSyncTimer(void)
|
||||
{
|
||||
int J;
|
||||
|
||||
/* Wait in 1ms increments until timer becomes ready */
|
||||
while(!TimerReady&&TimerON&&VideoImg) usleep(1000);
|
||||
/* Warn of missed timer events */
|
||||
if((TimerReady>1)&&(Effects&EFF_VERBOSE))
|
||||
printf("WaitSyncTimer(): Missed %d timer events.\n",TimerReady-1);
|
||||
/* Reset timer */
|
||||
J=TimerReady;
|
||||
TimerReady=0;
|
||||
return(J);
|
||||
}
|
||||
|
||||
/** SyncTimerReady() *****************************************/
|
||||
/** Return 1 if sync timer ready, 0 otherwise. **/
|
||||
/*************************************************************/
|
||||
int SyncTimerReady(void)
|
||||
{
|
||||
/* Return whether timer is ready or not */
|
||||
return(TimerReady||!TimerON||!VideoImg);
|
||||
}
|
||||
|
||||
/** SetSyncTimer() *******************************************/
|
||||
/** Set synchronization timer to a given frequency in Hz. **/
|
||||
/*************************************************************/
|
||||
int SetSyncTimer(int Hz)
|
||||
{
|
||||
struct itimerval TimerValue;
|
||||
|
||||
/* Compute and set timer period */
|
||||
TimerValue.it_interval.tv_sec =
|
||||
TimerValue.it_value.tv_sec = 0;
|
||||
TimerValue.it_interval.tv_usec =
|
||||
TimerValue.it_value.tv_usec = Hz? 1000000L/Hz:0;
|
||||
|
||||
/* Set timer */
|
||||
if(setitimer(ITIMER_REAL,&TimerValue,NULL)) return(0);
|
||||
|
||||
/* Set timer signal */
|
||||
signal(SIGALRM,Hz? TimerHandler:SIG_DFL);
|
||||
|
||||
/* Done */
|
||||
TimerON=Hz;
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** ChangeDir() **********************************************/
|
||||
/** This function is a wrapper for chdir(). **/
|
||||
/*************************************************************/
|
||||
int ChangeDir(const char *Name) { return(chdir(Name)); }
|
||||
|
||||
/** MicroSleep() *********************************************/
|
||||
/** Wait for a given number of microseconds. **/
|
||||
/*************************************************************/
|
||||
void MicroSleep(unsigned int uS) { usleep(uS); }
|
||||
|
||||
/** NewImage() ***********************************************/
|
||||
/** Create a new image of the given size. Returns pointer **/
|
||||
/** to the image data on success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
pixel *NewImage(Image *Img,int Width,int Height)
|
||||
{
|
||||
XVisualInfo VInfo;
|
||||
int Depth,J,I;
|
||||
|
||||
/* Set data fields to ther defaults */
|
||||
Img->Data = 0;
|
||||
Img->W = 0;
|
||||
Img->H = 0;
|
||||
Img->L = 0;
|
||||
Img->D = 0;
|
||||
Img->Attrs = 0;
|
||||
Img->Cropped = 0;
|
||||
|
||||
/* Need to initalize library first */
|
||||
if(!Dsp) return(0);
|
||||
|
||||
/* Image depth we are going to use */
|
||||
Depth = Effects&EFF_VARBPP? DefaultDepthOfScreen(Scr):(sizeof(pixel)<<3);
|
||||
|
||||
/* Get appropriate Visual for this depth */
|
||||
I=XScreenNumberOfScreen(Scr);
|
||||
for(J=7;J>=0;J--)
|
||||
if(XMatchVisualInfo(Dsp,I,Depth,J,&VInfo)) break;
|
||||
if(J<0) return(0);
|
||||
|
||||
#ifdef MITSHM
|
||||
if(Effects&EFF_MITSHM)
|
||||
{
|
||||
/* Create shared XImage */
|
||||
Img->XImg = XShmCreateImage(Dsp,VInfo.visual,Depth,ZPixmap,0,&Img->SHMInfo,Width,Height);
|
||||
if(!Img->XImg) return(0);
|
||||
|
||||
/* Get ID for shared segment */
|
||||
Img->SHMInfo.shmid = shmget(IPC_PRIVATE,Img->XImg->bytes_per_line*Img->XImg->height,IPC_CREAT|0777);
|
||||
if(Img->SHMInfo.shmid==-1) { XDestroyImage(Img->XImg);return(0); }
|
||||
|
||||
/* Attach to shared segment by ID */
|
||||
Img->XImg->data = Img->SHMInfo.shmaddr = shmat(Img->SHMInfo.shmid,0,0);
|
||||
if(!Img->XImg->data)
|
||||
{
|
||||
shmctl(Img->SHMInfo.shmid,IPC_RMID,0);
|
||||
XDestroyImage(Img->XImg);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Can write into shared segment */
|
||||
Img->SHMInfo.readOnly = False;
|
||||
|
||||
/* Attach segment to X display and make sure it is done */
|
||||
J=XShmAttach(Dsp,&Img->SHMInfo);
|
||||
XSync(Dsp,False);
|
||||
|
||||
/* We do not need an ID any longer */
|
||||
shmctl(Img->SHMInfo.shmid,IPC_RMID,0);
|
||||
|
||||
/* If attachment failed, break out */
|
||||
if(!J)
|
||||
{
|
||||
shmdt(Img->SHMInfo.shmaddr);
|
||||
XDestroyImage(Img->XImg);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Create normal XImage */
|
||||
Img->XImg = XCreateImage(Dsp,VInfo.visual,Depth,ZPixmap,0,0,Width,Height,Depth,0);
|
||||
if(!Img->XImg) return(0);
|
||||
|
||||
/* Allocate data */
|
||||
Img->XImg->data = (char *)malloc(Img->XImg->bytes_per_line*Img->XImg->height);
|
||||
if(!Img->XImg->data) { XDestroyImage(Img->XImg);return(0); }
|
||||
}
|
||||
|
||||
/* Done */
|
||||
Depth = Depth==24? 32:Depth;
|
||||
Img->Data = (pixel *)Img->XImg->data;
|
||||
Img->W = Img->XImg->width;
|
||||
Img->H = Img->XImg->height;
|
||||
Img->L = Img->XImg->bytes_per_line/(Depth>>3);
|
||||
Img->D = Depth;
|
||||
Img->Attrs = Effects&(EFF_MITSHM|EFF_VARBPP);
|
||||
return(Img->Data);
|
||||
}
|
||||
|
||||
/** FreeImage() **********************************************/
|
||||
/** Free previously allocated image. **/
|
||||
/*************************************************************/
|
||||
void FreeImage(Image *Img)
|
||||
{
|
||||
/* Need to initalize library first */
|
||||
if(!Dsp||!Img->Data) return;
|
||||
|
||||
#ifdef MITSHM
|
||||
/* Detach shared memory segment */
|
||||
if((Img->Attrs&EFF_MITSHM)&&Img->SHMInfo.shmaddr)
|
||||
{ XShmDetach(Dsp,&Img->SHMInfo);shmdt(Img->SHMInfo.shmaddr); }
|
||||
Img->SHMInfo.shmaddr = 0;
|
||||
#endif
|
||||
|
||||
/* Get rid of the image */
|
||||
if(Img->XImg) { XDestroyImage(Img->XImg);Img->XImg=0; }
|
||||
|
||||
/* Image freed */
|
||||
Img->Data = 0;
|
||||
Img->W = 0;
|
||||
Img->H = 0;
|
||||
Img->L = 0;
|
||||
}
|
||||
|
||||
/** CropImage() **********************************************/
|
||||
/** Create a subimage Dst of the image Src. Returns Dst. **/
|
||||
/*************************************************************/
|
||||
Image *CropImage(Image *Dst,const Image *Src,int X,int Y,int W,int H)
|
||||
{
|
||||
Dst->Data = (pixel *)((char *)Src->Data+(Src->L*Y+X)*(Src->D>>3));
|
||||
Dst->Cropped = 1;
|
||||
Dst->W = W;
|
||||
Dst->H = H;
|
||||
Dst->L = Src->L;
|
||||
Dst->D = Src->D;
|
||||
Dst->XImg = 0;
|
||||
Dst->Attrs = 0;
|
||||
return(Dst);
|
||||
}
|
||||
|
||||
/** SetVideo() ***********************************************/
|
||||
/** Set part of the image as "active" for display. **/
|
||||
/*************************************************************/
|
||||
void SetVideo(Image *Img,int X,int Y,int W,int H)
|
||||
{
|
||||
/* Save current dimensions */
|
||||
int OldW = VideoW;
|
||||
int OldH = VideoH;
|
||||
|
||||
/* Call default SetVideo() function */
|
||||
GenericSetVideo(Img,X,Y,W,H);
|
||||
|
||||
/* If video exists, modify its size */
|
||||
if(Dsp&&VideoW&&VideoH&&((VideoW!=OldW)||(VideoH!=OldH)))
|
||||
{
|
||||
int DW,DH,SW,SH,OldXS,OldYS;
|
||||
|
||||
/* Make sure window dimensions stay at ~1:1 ratio */
|
||||
DW = W/H>1? W/(W/H):W;
|
||||
DH = H/W>1? H/(H/W):H;
|
||||
SW = VideoW/VideoH>1? VideoW/(VideoW/VideoH):VideoW;
|
||||
SH = VideoH/VideoW>1? VideoH/(VideoH/VideoW):VideoH;
|
||||
OldXS = XSize;
|
||||
OldYS = YSize;
|
||||
XSize = XSize*DW/SW;
|
||||
YSize = YSize*DH/SH;
|
||||
XSize = Effects&EFF_4X3? 4*YSize/3:XSize;
|
||||
|
||||
if(Wnd) XResizeWindow(Dsp,Wnd,XSize,YSize);
|
||||
FreeImage(&OutImg);
|
||||
}
|
||||
}
|
||||
|
||||
/** SetEffects() *********************************************/
|
||||
/** Set visual effects applied to video in ShowVideo(). **/
|
||||
/*************************************************************/
|
||||
void SetEffects(unsigned int NewEffects)
|
||||
{
|
||||
/* Set new effects */
|
||||
Effects=NewEffects;
|
||||
}
|
||||
|
||||
/** ProcessEvents() ******************************************/
|
||||
/** Process X11 event messages. **/
|
||||
/*************************************************************/
|
||||
int ProcessEvents(int Wait)
|
||||
{
|
||||
XEvent E;
|
||||
int J,Count;
|
||||
|
||||
/* Need to have display and a window */
|
||||
if(!Dsp||!Wnd) return(0);
|
||||
|
||||
do
|
||||
{
|
||||
/* Check for keypresses/keyreleases */
|
||||
for(Count=0;XCheckWindowEvent(Dsp,Wnd,KeyPressMask|KeyReleaseMask,&E);++Count)
|
||||
{
|
||||
/* Get key code */
|
||||
J=XLookupKeysym((XKeyEvent *)&E,0);
|
||||
|
||||
/* If key pressed... */
|
||||
if(E.type==KeyPress)
|
||||
{
|
||||
/* Process ASCII keys */
|
||||
if((J>=' ')&&(J<0x7F)) LastKey=toupper(J);
|
||||
|
||||
/* Special keys pressed... */
|
||||
switch(J)
|
||||
{
|
||||
case XK_Left: JoyState|=BTN_LEFT;LastKey=CON_LEFT;break;
|
||||
case XK_Right: JoyState|=BTN_RIGHT;LastKey=CON_RIGHT;break;
|
||||
case XK_Up: JoyState|=BTN_UP;LastKey=CON_UP;break;
|
||||
case XK_Down: JoyState|=BTN_DOWN;LastKey=CON_DOWN;break;
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R: KeyModes|=CON_SHIFT;break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R: KeyModes|=CON_ALT;break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R: KeyModes|=CON_CONTROL;break;
|
||||
case XK_Caps_Lock: KeyModes|=CON_CAPS;break;
|
||||
case XK_Escape: JoyState|=BTN_EXIT;LastKey=CON_EXIT;break;
|
||||
case XK_Tab: JoyState|=BTN_SELECT;break;
|
||||
case XK_Return: JoyState|=BTN_START;LastKey=CON_OK;break;
|
||||
case XK_BackSpace: LastKey=8;break;
|
||||
|
||||
case 'q': case 'e': case 't': case 'u': case 'o':
|
||||
JoyState|=BTN_FIREL;break;
|
||||
case 'w': case 'r': case 'y': case 'i': case 'p':
|
||||
JoyState|=BTN_FIRER;break;
|
||||
case 'a': case 's': case 'd': case 'f': case 'g':
|
||||
case 'h': case 'j': case 'k': case 'l': case ' ':
|
||||
JoyState|=BTN_FIREA;break;
|
||||
case 'z': case 'x': case 'c': case 'v': case 'b':
|
||||
case 'n': case 'm':
|
||||
JoyState|=BTN_FIREB;break;
|
||||
|
||||
case XK_Page_Up:
|
||||
if(KeyModes&CON_ALT)
|
||||
{
|
||||
/* Volume up */
|
||||
SetChannels(MasterVolume<247? MasterVolume+8:255,MasterSwitch);
|
||||
/* Key swallowed */
|
||||
J=0;
|
||||
}
|
||||
break;
|
||||
|
||||
case XK_Page_Down:
|
||||
if(KeyModes&CON_ALT)
|
||||
{
|
||||
/* Volume down */
|
||||
SetChannels(MasterVolume>8? MasterVolume-8:0,MasterSwitch);
|
||||
/* Key swallowed */
|
||||
J=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Call user handler */
|
||||
if(J&&KeyHandler) (*KeyHandler)(J|KeyModes);
|
||||
}
|
||||
|
||||
/* If key released... */
|
||||
if(E.type==KeyRelease)
|
||||
{
|
||||
/* Special keys released... */
|
||||
switch(J)
|
||||
{
|
||||
case XK_Left: JoyState&=~BTN_LEFT;break;
|
||||
case XK_Right: JoyState&=~BTN_RIGHT;break;
|
||||
case XK_Up: JoyState&=~BTN_UP;break;
|
||||
case XK_Down: JoyState&=~BTN_DOWN;break;
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R: KeyModes&=~CON_SHIFT;break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R: KeyModes&=~CON_ALT;break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R: KeyModes&=~CON_CONTROL;break;
|
||||
case XK_Caps_Lock: KeyModes&=~CON_CAPS;break;
|
||||
case XK_Escape: JoyState&=~BTN_EXIT;break;
|
||||
case XK_Tab: JoyState&=~BTN_SELECT;break;
|
||||
case XK_Return: JoyState&=~BTN_START;break;
|
||||
|
||||
case 'q': case 'e': case 't': case 'u': case 'o':
|
||||
JoyState&=~BTN_FIREL;break;
|
||||
case 'w': case 'r': case 'y': case 'i': case 'p':
|
||||
JoyState&=~BTN_FIRER;break;
|
||||
case 'a': case 's': case 'd': case 'f': case 'g':
|
||||
case 'h': case 'j': case 'k': case 'l': case ' ':
|
||||
JoyState&=~BTN_FIREA;break;
|
||||
case 'z': case 'x': case 'c': case 'v': case 'b':
|
||||
case 'n': case 'm':
|
||||
JoyState&=~BTN_FIREB;break;
|
||||
}
|
||||
|
||||
/* Call user handler */
|
||||
if(J&&KeyHandler) (*KeyHandler)(J|CON_RELEASE|KeyModes);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for focus change events */
|
||||
for(E.type=0;XCheckWindowEvent(Dsp,Wnd,FocusChangeMask,&E);++Count);
|
||||
/* If saving CPU and focus is out... */
|
||||
if((Effects&EFF_SAVECPU)&&(E.type==FocusOut))
|
||||
{
|
||||
/* Pause audio */
|
||||
J=MasterSwitch;
|
||||
SetChannels(MasterVolume,0);
|
||||
PauseAudio(1);
|
||||
/* Wait for focus-in event */
|
||||
do
|
||||
while(!XCheckWindowEvent(Dsp,Wnd,FocusChangeMask,&E)&&VideoImg) sleep(1);
|
||||
while((E.type!=FocusIn)&&VideoImg);
|
||||
/* Resume audio */
|
||||
PauseAudio(0);
|
||||
SetChannels(MasterVolume,J);
|
||||
}
|
||||
|
||||
/* If window has been resized, remove current output buffer */
|
||||
for(E.type=0;XCheckWindowEvent(Dsp,Wnd,StructureNotifyMask,&E);++Count)
|
||||
if((E.type==ConfigureNotify)&&!E.xconfigure.send_event)
|
||||
if((XSize!=E.xconfigure.width)||(YSize!=E.xconfigure.height))
|
||||
{
|
||||
FreeImage(&OutImg);
|
||||
XSize=E.xconfigure.width;
|
||||
YSize=E.xconfigure.height;
|
||||
}
|
||||
|
||||
/* X11 does not let us wait for event, so we sleep for 100ms instead */
|
||||
if(!Wait||Count||!VideoImg) break; else usleep(100000);
|
||||
}
|
||||
while(1);
|
||||
|
||||
/* Returning 0 when application quits */
|
||||
return(!!VideoImg);
|
||||
}
|
||||
|
||||
/** X11GetColor **********************************************/
|
||||
/** Get pixel for the current screen depth based on the RGB **/
|
||||
/** values. **/
|
||||
/*************************************************************/
|
||||
unsigned int X11GetColor(unsigned char R,unsigned char G,unsigned char B)
|
||||
{
|
||||
int J;
|
||||
|
||||
/* If using constant BPP, just return a pixel */
|
||||
if(!Dsp||!(Effects&EFF_VARBPP)) return(PIXEL(R,G,B));
|
||||
|
||||
/* If variable BPP, compute pixel based on the screen depth */
|
||||
J=DefaultDepthOfScreen(Scr);
|
||||
return(
|
||||
J<=8? (((7*(R)/255)<<5)|((7*(G)/255)<<2)|(3*(B)/255))
|
||||
: J<=16? (((31*(R)/255)<<11)|((63*(G)/255)<<5)|(31*(B)/255))
|
||||
: J<=32? (((R)<<16)|((G)<<8)|B)
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
/** X11Window() **********************************************/
|
||||
/** Open a window of a given size with a given title. **/
|
||||
/*************************************************************/
|
||||
Window X11Window(const char *Title,int Width,int Height)
|
||||
{
|
||||
XSetWindowAttributes Attrs;
|
||||
XClassHint ClassHint;
|
||||
XSizeHints Hints;
|
||||
XWMHints WMHints;
|
||||
Window Wnd;
|
||||
char *P;
|
||||
int Q;
|
||||
|
||||
/* Need to initalize library first */
|
||||
if(!Dsp) return(0);
|
||||
|
||||
/* Set necessary attributes */
|
||||
Attrs.event_mask =
|
||||
FocusChangeMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask;
|
||||
Attrs.background_pixel=BlackPixelOfScreen(Scr);
|
||||
Attrs.backing_store=Always;
|
||||
|
||||
/* Create a window */
|
||||
Wnd=XCreateWindow
|
||||
(
|
||||
Dsp,RootWindowOfScreen(Scr),0,0,Width,Height,0,
|
||||
CopyFromParent,CopyFromParent,CopyFromParent,
|
||||
CWBackPixel|CWEventMask|CWBackingStore,&Attrs
|
||||
);
|
||||
if(!Wnd) return(0);
|
||||
|
||||
/* Set application class hint */
|
||||
if(ARGC&&ARGV)
|
||||
{
|
||||
P=strrchr(ARGV[0],'/');
|
||||
ClassHint.res_name = P? P+1:ARGV[0];
|
||||
ClassHint.res_class = P? P+1:ARGV[0];
|
||||
XSetClassHint(Dsp,Wnd,&ClassHint);
|
||||
XSetCommand(Dsp,Wnd,ARGV,ARGC);
|
||||
}
|
||||
|
||||
/* Set hints */
|
||||
Q=sizeof(long);
|
||||
Hints.flags = PSize|PMinSize|PMaxSize|PResizeInc;
|
||||
Hints.min_width = ((Width/4)/Q)*Q;
|
||||
Hints.max_width = ((Width*4)/Q)*Q;
|
||||
Hints.base_width = (Width/Q)*Q;
|
||||
Hints.width_inc = Q;
|
||||
Hints.min_height = ((Height/4)/Q)*Q;
|
||||
Hints.max_height = ((Height*4)/Q)*Q;
|
||||
Hints.base_height = (Height/Q)*Q;
|
||||
Hints.height_inc = Q;
|
||||
WMHints.input = True;
|
||||
WMHints.flags = InputHint;
|
||||
|
||||
if(ARGC&&ARGV)
|
||||
{
|
||||
WMHints.window_group=Wnd;
|
||||
WMHints.flags|=WindowGroupHint;
|
||||
}
|
||||
|
||||
/* Set hints, title, size */
|
||||
XSetWMHints(Dsp,Wnd,&WMHints);
|
||||
XSetWMNormalHints(Dsp,Wnd,&Hints);
|
||||
XStoreName(Dsp,Wnd,Title);
|
||||
|
||||
/* Do additional housekeeping and return */
|
||||
XMapRaised(Dsp,Wnd);
|
||||
XClearWindow(Dsp,Wnd);
|
||||
|
||||
/* Done */
|
||||
return(Wnd);
|
||||
}
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** LibUnix.h **/
|
||||
/** **/
|
||||
/** This file contains Unix-dependent definitions and **/
|
||||
/** declarations for the emulation library. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#ifndef LIBUNIX_H
|
||||
#define LIBUNIX_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
|
||||
#ifdef MITSHM
|
||||
#include <X11/extensions/XShm.h>
|
||||
#endif
|
||||
|
||||
/* X11 defines "Status" to be "int" but this may shadow some */
|
||||
/* of our application variables! */
|
||||
#undef Status
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SND_CHANNELS 16 /* Number of sound channels */
|
||||
#define SND_BITS 8
|
||||
#define SND_BUFSIZE (1<<SND_BITS)
|
||||
|
||||
/** PIXEL() **************************************************/
|
||||
/** Unix may use multiple pixel formats. **/
|
||||
/*************************************************************/
|
||||
#if defined(BPP32) || defined(BPP24)
|
||||
#define PIXEL(R,G,B) (pixel)(((int)R<<16)|((int)G<<8)|B)
|
||||
#define PIXEL2MONO(P) (((P>>16)&0xFF)+((P>>8)&0xFF)+(P&0xFF))/3)
|
||||
#define RMASK 0xFF0000
|
||||
#define GMASK 0x00FF00
|
||||
#define BMASK 0x0000FF
|
||||
|
||||
#elif defined(BPP16)
|
||||
#define PIXEL(R,G,B) (pixel)(((31*(R)/255)<<11)|((63*(G)/255)<<5)|(31*(B)/255))
|
||||
#define PIXEL2MONO(P) (522*(((P)&31)+(((P)>>5)&63)+(((P)>>11)&31))>>8)
|
||||
#define RMASK 0xF800
|
||||
#define GMASK 0x07E0
|
||||
#define BMASK 0x001F
|
||||
|
||||
#elif defined(BPP8)
|
||||
#define PIXEL(R,G,B) (pixel)(((7*(R)/255)<<5)|((7*(G)/255)<<2)|(3*(B)/255))
|
||||
#define PIXEL2MONO(P) (3264*((((P)<<1)&7)+(((P)>>2)&7)+(((P)>>5)&7))>>8)
|
||||
#define RMASK 0xE0
|
||||
#define GMASK 0x1C
|
||||
#define BMASK 0x03
|
||||
#endif
|
||||
|
||||
int ARGC;
|
||||
char **ARGV;
|
||||
|
||||
/** InitUnix() ***********************************************/
|
||||
/** Initialize Unix/X11 resources and set initial window. **/
|
||||
/** title and dimensions. **/
|
||||
/*************************************************************/
|
||||
int InitUnix(const char *Title,int Width,int Height);
|
||||
|
||||
/** TrashUnix() **********************************************/
|
||||
/** Free resources allocated in InitUnix() **/
|
||||
/*************************************************************/
|
||||
void TrashUnix(void);
|
||||
|
||||
/** InitAudio() **********************************************/
|
||||
/** Initialize sound. Returns rate (Hz) on success, else 0. **/
|
||||
/** Rate=0 to skip initialization (will be silent). **/
|
||||
/*************************************************************/
|
||||
unsigned int InitAudio(unsigned int Rate,unsigned int Latency);
|
||||
|
||||
/** TrashAudio() *********************************************/
|
||||
/** Free resources allocated by InitAudio(). **/
|
||||
/*************************************************************/
|
||||
void TrashAudio(void);
|
||||
|
||||
/** PauseAudio() *********************************************/
|
||||
/** Pause/resume audio playback. **/
|
||||
/*************************************************************/
|
||||
int PauseAudio(int Switch);
|
||||
|
||||
/** X11Window() **********************************************/
|
||||
/** Open a window of a given size with a given title. **/
|
||||
/*************************************************************/
|
||||
Window X11Window(const char *Title,int Width,int Height);
|
||||
|
||||
/** X11GetColor **********************************************/
|
||||
/** Get pixel for the current screen depth based on the RGB **/
|
||||
/** values. **/
|
||||
/*************************************************************/
|
||||
unsigned int X11GetColor(unsigned char R,unsigned char G,unsigned char B);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* LIBUNIX_H */
|
||||
Executable
+440
@@ -0,0 +1,440 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** NetUnix.c **/
|
||||
/** **/
|
||||
/** This file contains standard communication routines for **/
|
||||
/** Unix using TCP/IP via sockets. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1997-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "EMULib.h"
|
||||
#include "NetPlay.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#define puts LOGI
|
||||
#define printf LOGI
|
||||
#endif
|
||||
|
||||
#ifndef SOL_TCP
|
||||
#define SOL_TCP IPPROTO_TCP
|
||||
#endif
|
||||
|
||||
static volatile int IsServer = 0;
|
||||
static volatile int Socket = -1;
|
||||
static volatile int Blocking = 1;
|
||||
static volatile int UseUDP = 0;
|
||||
static volatile pthread_t Thr = 0;
|
||||
static struct sockaddr_in PeerAddr;
|
||||
|
||||
/** ThrHandler() *********************************************/
|
||||
/** This is the thread function responsible for asyncronous **/
|
||||
/** connection process. **/
|
||||
/*************************************************************/
|
||||
static void *ThrHandler(void *Arg)
|
||||
{
|
||||
void **Args = (void **)Arg;
|
||||
char *Server = (char *)Args[0];
|
||||
unsigned int Port = (unsigned int)Args[1];
|
||||
|
||||
/* Try connecting */
|
||||
NETConnect(Server,Port);
|
||||
|
||||
/* No longer need strdup()ed server name */
|
||||
if(Server) free(Server);
|
||||
|
||||
/* Thread done */
|
||||
Thr = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** NETConnected() *******************************************/
|
||||
/** Returns NET_SERVER, NET_CLIENT, or NET_OFF. **/
|
||||
/*************************************************************/
|
||||
int NETConnected(void)
|
||||
{ return(Socket<0? NET_OFF:IsServer? NET_SERVER:NET_CLIENT); }
|
||||
|
||||
/** NETMyName() **********************************************/
|
||||
/** Returns local hostname/address or 0 on failure. **/
|
||||
/*************************************************************/
|
||||
const char *NETMyName(char *Buffer,int MaxChars)
|
||||
{
|
||||
struct hostent *Host;
|
||||
|
||||
/* Have to have enough characters */
|
||||
if(MaxChars<16) return(0);
|
||||
/* Get local hostname */
|
||||
gethostname(Buffer,MaxChars);
|
||||
/* Look up address */
|
||||
if(!(Host=gethostbyname(Buffer))) return(0);
|
||||
/* Must have an address */
|
||||
if(!Host->h_addr_list||!Host->h_addr_list[0]) return(0);
|
||||
/* Copy address */
|
||||
sprintf(Buffer,"%d.%d.%d.%d",
|
||||
Host->h_addr_list[0][0],
|
||||
Host->h_addr_list[0][1],
|
||||
Host->h_addr_list[0][2],
|
||||
Host->h_addr_list[0][3]
|
||||
);
|
||||
return(Buffer);
|
||||
}
|
||||
|
||||
/** NETConnectAsync() ****************************************/
|
||||
/** Asynchronous version of NETConnect(). **/
|
||||
/*************************************************************/
|
||||
int NETConnectAsync(const char *Server,unsigned short Port)
|
||||
{
|
||||
static void *Args[2];
|
||||
|
||||
/* Thread already exists, nothing to do */
|
||||
if(Thr) return(1);
|
||||
|
||||
/* Close existing network connection */
|
||||
NETClose();
|
||||
|
||||
/* Set up arguments */
|
||||
Args[0] = (void *)(Server? strdup(Server):0);
|
||||
Args[1] = (void *)(unsigned int)Port;
|
||||
if(!Args[0]&&Server) return(0);
|
||||
|
||||
/* Create connection thread */
|
||||
return(!!pthread_create((pthread_t *)&Thr,0,ThrHandler,Args));
|
||||
}
|
||||
|
||||
/** UDPConnect() *********************************************/
|
||||
/** Connects to Server:Port. When Server=0, becomes server, **/
|
||||
/** waits at for an incoming request, and connects. Returns **/
|
||||
/** the NetPlay connection status, like NETConnected(). **/
|
||||
/*************************************************************/
|
||||
int UDPConnect(const char *Server,unsigned short Port)
|
||||
{
|
||||
struct sockaddr_in MyAddr;
|
||||
struct hostent *Host;
|
||||
int SSocket,J;
|
||||
pthread_t T;
|
||||
|
||||
/* Store current thread ID (or 0 if called synchronously) */
|
||||
T = Thr;
|
||||
|
||||
/* Close existing network connection */
|
||||
if(!T) NETClose();
|
||||
|
||||
/* Create UDP socket */
|
||||
if((SSocket=socket(AF_INET,SOCK_DGRAM,0))<0) return(NET_OFF);
|
||||
|
||||
/* Set fields of the address structure */
|
||||
memset(&MyAddr,0,sizeof(MyAddr));
|
||||
MyAddr.sin_family = AF_INET;
|
||||
MyAddr.sin_port = htons(Port);
|
||||
MyAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
memcpy(&PeerAddr,&MyAddr,sizeof(PeerAddr));
|
||||
|
||||
/* If the server name is given, we first try to */
|
||||
/* connect as a client. */
|
||||
if(Server)
|
||||
{
|
||||
printf("UDP-CLIENT: Looking up '%s'...\n",Server);
|
||||
|
||||
/* Look up server address */
|
||||
if(!(Host=gethostbyname(Server))) { close(SSocket);return(NET_OFF); }
|
||||
|
||||
/* Set server address */
|
||||
memcpy(&PeerAddr.sin_addr,Host->h_addr,Host->h_length);
|
||||
|
||||
/* Bind socket */
|
||||
if(bind(SSocket,(struct sockaddr *)&MyAddr,sizeof(MyAddr))<0)
|
||||
{ close(SSocket);return(NET_OFF); }
|
||||
|
||||
printf("UDP-CLIENT: Client established.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("UDP-SERVER: Becoming server...\n");
|
||||
|
||||
/* Accepting messages from any address */
|
||||
PeerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
/* Bind socket */
|
||||
if(bind(SSocket,(struct sockaddr *)&MyAddr,sizeof(MyAddr))<0)
|
||||
{ close(SSocket);return(NET_OFF); }
|
||||
|
||||
printf("UDP-SERVER: Server established.\n");
|
||||
}
|
||||
|
||||
/* Make communication socket blocking/non-blocking */
|
||||
J=!Blocking;
|
||||
if(ioctl(SSocket,FIONBIO,&J)<0) { close(SSocket);return(NET_OFF); }
|
||||
|
||||
/* Success */
|
||||
IsServer = !Server;
|
||||
UseUDP = 1;
|
||||
Socket = SSocket;
|
||||
|
||||
return(Server? NET_SERVER:NET_CLIENT);
|
||||
}
|
||||
|
||||
/** NETConnect() *********************************************/
|
||||
/** Connects to Server:Port. When Server=0, becomes server, **/
|
||||
/** waits at for an incoming request, and connects. Returns **/
|
||||
/** the NetPlay connection status, like NETConnected(). **/
|
||||
/*************************************************************/
|
||||
int NETConnect(const char *Server,unsigned short Port)
|
||||
{
|
||||
struct sockaddr_in Addr;
|
||||
struct hostent *Host;
|
||||
struct timeval TV;
|
||||
int AddrLength,LSocket,SSocket;
|
||||
unsigned long J;
|
||||
pthread_t T;
|
||||
fd_set FDs;
|
||||
|
||||
/* Store current thread ID (or 0 if called synchronously) */
|
||||
T = Thr;
|
||||
|
||||
/* Close existing network connection */
|
||||
if(!T) NETClose();
|
||||
|
||||
/* Clear the address structure */
|
||||
memset(&Addr,0,sizeof(Addr));
|
||||
|
||||
/* If the server name is given, we first try to */
|
||||
/* connect as a client. */
|
||||
if(Server)
|
||||
{
|
||||
printf("NET-CLIENT: Connecting to '%s'...\n",Server);
|
||||
|
||||
/* Look up server address */
|
||||
if(!(Host=gethostbyname(Server))) return(NET_OFF);
|
||||
|
||||
printf("NET-CLIENT: Got server's IP address...\n");
|
||||
|
||||
/* Set fields of the address structure */
|
||||
memcpy(&Addr.sin_addr,Host->h_addr,Host->h_length);
|
||||
Addr.sin_family = AF_INET;
|
||||
Addr.sin_port = htons(Port);
|
||||
|
||||
/* Create a socket */
|
||||
if((SSocket=socket(AF_INET,SOCK_STREAM,0))<0) return(NET_OFF);
|
||||
|
||||
printf("NET-CLIENT: Created socket...\n");
|
||||
|
||||
/* Connecting... */
|
||||
if(connect(SSocket,(struct sockaddr *)&Addr,sizeof(Addr))>=0)
|
||||
{
|
||||
printf("NET-CLIENT: Connected to the server...\n");
|
||||
|
||||
/* Make communication socket blocking/non-blocking */
|
||||
J=!Blocking;
|
||||
if(ioctl(SSocket,FIONBIO,&J)<0)
|
||||
{ close(SSocket);return(NET_OFF); }
|
||||
|
||||
/* Disable Nagle algorithm */
|
||||
J=1;
|
||||
setsockopt(SSocket,SOL_TCP,TCP_NODELAY,&J,sizeof(J));
|
||||
|
||||
/* Succesfully connected as client */
|
||||
IsServer = 0;
|
||||
UseUDP = 0;
|
||||
Socket = SSocket;
|
||||
|
||||
printf("NET-CLIENT: Connected to '%s'.\n",Server);
|
||||
|
||||
return(NET_CLIENT);
|
||||
}
|
||||
|
||||
printf("NET-CLIENT: Failed connecting to '%s'.\n",Server);
|
||||
|
||||
/* Failed to connect as a client */
|
||||
close(SSocket);
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Do not try becoming server! */
|
||||
return(NET_OFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Connection as client either failed or hasn't */
|
||||
/* been attempted at all. Becoming a server and */
|
||||
/* waiting for connection request. */
|
||||
|
||||
printf("NET-SERVER: Becoming server...\n");
|
||||
|
||||
/* Set fields of the address structure */
|
||||
Addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
Addr.sin_family = AF_INET;
|
||||
Addr.sin_port = htons(Port);
|
||||
|
||||
/* Create a listening socket */
|
||||
if((LSocket=socket(AF_INET,SOCK_STREAM,0))<0) return(NET_OFF);
|
||||
|
||||
printf("NET-SERVER: Created socket...\n");
|
||||
|
||||
/* Bind listening socket */
|
||||
if(bind(LSocket,(struct sockaddr *)&Addr,sizeof(Addr))<0)
|
||||
{ close(LSocket);return(NET_OFF); }
|
||||
|
||||
printf("NET-SERVER: Bound socket...\n");
|
||||
|
||||
/* Listen for one client */
|
||||
if(listen(LSocket,1)<0)
|
||||
{ close(LSocket);return(NET_OFF); }
|
||||
|
||||
/* We will need address length */
|
||||
AddrLength=sizeof(Addr);
|
||||
|
||||
printf("NET-SERVER: Accepting calls...\n");
|
||||
|
||||
/* No sockets yet */
|
||||
FD_ZERO(&FDs);
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Accepting calls... */
|
||||
for(SSocket=-1;(SSocket<0)&&VideoImg&&(T==Thr);)
|
||||
{
|
||||
/* Prepare data for select() */
|
||||
FD_SET(LSocket,&FDs);
|
||||
TV.tv_sec = 1;
|
||||
TV.tv_usec = 0;
|
||||
/* Listen and accept connection */
|
||||
if(select(LSocket+1,&FDs,0,0,&TV)>0)
|
||||
SSocket=accept(LSocket,(struct sockaddr *)&Addr,&AddrLength);
|
||||
}
|
||||
#else
|
||||
/* Accepting calls... */
|
||||
for(SSocket=-1,GetKey();(SSocket<0)&&VideoImg&&!GetKey()&&(T==Thr);)
|
||||
{
|
||||
/* Prepare data for select() */
|
||||
FD_SET(LSocket,&FDs);
|
||||
TV.tv_sec = 0;
|
||||
TV.tv_usec = 100000;
|
||||
/* Make sure UI is still running */
|
||||
ProcessEvents(0);
|
||||
/* Listen and accept connection */
|
||||
if(select(LSocket+1,&FDs,0,0,&TV)>0)
|
||||
SSocket=accept(LSocket,(struct sockaddr *)&Addr,&AddrLength);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("NET-SERVER: Client %s...\n",SSocket>=0? "connected":"failed to connect");
|
||||
|
||||
/* Done listening */
|
||||
close(LSocket);
|
||||
|
||||
/* Client failed to connect */
|
||||
if(SSocket<0) return(NET_OFF);
|
||||
|
||||
/* Make communication socket blocking/non-blocking */
|
||||
J=!Blocking;
|
||||
if(ioctl(SSocket,FIONBIO,&J)<0)
|
||||
{ close(SSocket);return(NET_OFF); }
|
||||
|
||||
/* Disable Nagle algorithm */
|
||||
J=1;
|
||||
setsockopt(SSocket,SOL_TCP,TCP_NODELAY,&J,sizeof(J));
|
||||
|
||||
/* Client connected succesfully */
|
||||
IsServer = 1;
|
||||
UseUDP = 0;
|
||||
Socket = SSocket;
|
||||
|
||||
printf("NET-SERVER: Client connected.\n");
|
||||
|
||||
return(NET_SERVER);
|
||||
}
|
||||
|
||||
/** NETClose() ***********************************************/
|
||||
/** Closes connection open with NETConnect(). **/
|
||||
/*************************************************************/
|
||||
void NETClose(void)
|
||||
{
|
||||
pthread_t T = Thr;
|
||||
|
||||
/* If there is a connection thread running, stop it */
|
||||
if(T) { Thr=0;pthread_join(T,0); }
|
||||
|
||||
if(Socket>=0) close(Socket);
|
||||
Socket = -1;
|
||||
IsServer = 0;
|
||||
}
|
||||
|
||||
/** NETBlock() ***********************************************/
|
||||
/** Makes NETSend()/NETRecv() blocking or not blocking. **/
|
||||
/*************************************************************/
|
||||
int NETBlock(int Switch)
|
||||
{
|
||||
unsigned long J;
|
||||
|
||||
/* Toggle blocking if requested */
|
||||
if(Switch==NET_TOGGLE) Switch=!Blocking;
|
||||
|
||||
/* If switching blocking... */
|
||||
if((Switch==NET_OFF)||(Switch==NET_ON))
|
||||
{
|
||||
J=!Switch;
|
||||
if((Socket<0)||(ioctl(Socket,FIONBIO,&J)>=0)) Blocking=Switch;
|
||||
}
|
||||
|
||||
/* Return blocking state */
|
||||
return(Blocking);
|
||||
}
|
||||
|
||||
/** NETSend() ************************************************/
|
||||
/** Send N bytes. Returns number of bytes sent or 0. **/
|
||||
/*************************************************************/
|
||||
int NETSend(const char *Out,int N)
|
||||
{
|
||||
int J,I;
|
||||
|
||||
/* Have to have a socket and an address */
|
||||
if((Socket<0)||(UseUDP&&(PeerAddr.sin_addr.s_addr==INADDR_ANY))) return(0);
|
||||
|
||||
/* Send data */
|
||||
for(I=J=N;(J>=0)&&I;)
|
||||
{
|
||||
J = UseUDP? sendto(Socket,Out,I,0,(struct sockaddr *)&PeerAddr,sizeof(PeerAddr)):send(Socket,Out,I,0);
|
||||
if(J>0) { Out+=J;I-=J; }
|
||||
}
|
||||
|
||||
/* Return number of bytes sent */
|
||||
return(N-I);
|
||||
}
|
||||
|
||||
/** NETRecv() ************************************************/
|
||||
/** Receive N bytes. Returns number of bytes received or 0. **/
|
||||
/*************************************************************/
|
||||
int NETRecv(char *In,int N)
|
||||
{
|
||||
socklen_t AddrLen;
|
||||
int J,I;
|
||||
|
||||
/* Have to have a socket */
|
||||
if(Socket<0) return(0);
|
||||
|
||||
/* This is needed for recvfrom() */
|
||||
AddrLen = sizeof(PeerAddr);
|
||||
|
||||
/* Receive data */
|
||||
for(I=J=N;(J>=0)&&I;)
|
||||
{
|
||||
J = UseUDP? recvfrom(Socket,In,I,0,(struct sockaddr *)&PeerAddr,&AddrLen):recv(Socket,In,I,0);
|
||||
if(J>0) { In+=J;I-=J; }
|
||||
}
|
||||
|
||||
/* Return number of bytes received */
|
||||
return(N-I);
|
||||
}
|
||||
Executable
+362
@@ -0,0 +1,362 @@
|
||||
/** EMULib Emulation Library *********************************/
|
||||
/** **/
|
||||
/** SndUnix.c **/
|
||||
/** **/
|
||||
/** This file contains Unix-dependent sound implementation **/
|
||||
/** for the emulation library. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1996-2016 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "EMULib.h"
|
||||
#include "Sound.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(PULSE_AUDIO)
|
||||
|
||||
#include <pulse/simple.h>
|
||||
|
||||
#elif defined(ESD_AUDIO)
|
||||
|
||||
#include "esd.h"
|
||||
|
||||
#elif defined(SUN_AUDIO)
|
||||
|
||||
#include <sys/audioio.h>
|
||||
#include <sys/conf.h>
|
||||
#include <stropts.h>
|
||||
|
||||
static const unsigned char ULAW[256] =
|
||||
{
|
||||
31, 31, 31, 32, 32, 32, 32, 33,
|
||||
33, 33, 33, 34, 34, 34, 34, 35,
|
||||
35, 35, 35, 36, 36, 36, 36, 37,
|
||||
37, 37, 37, 38, 38, 38, 38, 39,
|
||||
39, 39, 39, 40, 40, 40, 40, 41,
|
||||
41, 41, 41, 42, 42, 42, 42, 43,
|
||||
43, 43, 43, 44, 44, 44, 44, 45,
|
||||
45, 45, 45, 46, 46, 46, 46, 47,
|
||||
47, 47, 47, 48, 48, 49, 49, 50,
|
||||
50, 51, 51, 52, 52, 53, 53, 54,
|
||||
54, 55, 55, 56, 56, 57, 57, 58,
|
||||
58, 59, 59, 60, 60, 61, 61, 62,
|
||||
62, 63, 63, 64, 65, 66, 67, 68,
|
||||
69, 70, 71, 72, 73, 74, 75, 76,
|
||||
77, 78, 79, 81, 83, 85, 87, 89,
|
||||
91, 93, 95, 99, 103, 107, 111, 119,
|
||||
255, 247, 239, 235, 231, 227, 223, 221,
|
||||
219, 217, 215, 213, 211, 209, 207, 206,
|
||||
205, 204, 203, 202, 201, 200, 199, 198,
|
||||
219, 217, 215, 213, 211, 209, 207, 206,
|
||||
205, 204, 203, 202, 201, 200, 199, 198,
|
||||
197, 196, 195, 194, 193, 192, 191, 191,
|
||||
190, 190, 189, 189, 188, 188, 187, 187,
|
||||
186, 186, 185, 185, 184, 184, 183, 183,
|
||||
182, 182, 181, 181, 180, 180, 179, 179,
|
||||
178, 178, 177, 177, 176, 176, 175, 175,
|
||||
175, 175, 174, 174, 174, 174, 173, 173,
|
||||
173, 173, 172, 172, 172, 172, 171, 171,
|
||||
171, 171, 170, 170, 170, 170, 169, 169,
|
||||
169, 169, 168, 168, 168, 168, 167, 167,
|
||||
167, 167, 166, 166, 166, 166, 165, 165,
|
||||
165, 165, 164, 164, 164, 164, 163, 163
|
||||
};
|
||||
|
||||
#else /* !SUN_AUDIO && !ESD_AUDIO && !PULSE_AUDIO */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
|
||||
#endif /* !SUN_AUDIO && !ESD_AUDIO && !PULSE_AUDIO */
|
||||
|
||||
#if defined(SUN_AUDIO)
|
||||
#define AUDIO_CONV(A) (ULAW[0xFF&(128+(A))])
|
||||
#elif defined(BPS16)
|
||||
#define AUDIO_CONV(A) (A)
|
||||
#else
|
||||
#define AUDIO_CONV(A) (128+(A))
|
||||
#endif
|
||||
|
||||
static int SoundFD = -1; /* Audio device descriptor */
|
||||
static int SndRate = 0; /* Audio sampling rate */
|
||||
static int SndSize = 0; /* SndData[] size */
|
||||
static sample *SndData = 0; /* Audio buffers */
|
||||
static int RPtr = 0; /* Read pointer into Bufs */
|
||||
static int WPtr = 0; /* Write pointer into Bufs */
|
||||
static pthread_t Thr = 0; /* Audio thread */
|
||||
static volatile int AudioPaused = 0; /* 1: Audio paused */
|
||||
|
||||
/** ThrHandler() *********************************************/
|
||||
/** This is the thread function responsible for sending **/
|
||||
/** buffers to the audio device. **/
|
||||
/*************************************************************/
|
||||
static void *ThrHandler(void *Arg)
|
||||
{
|
||||
int J;
|
||||
|
||||
/* Spin until audio has been trashed */
|
||||
for(RPtr=WPtr=0;SndRate&&SndData&&(SoundFD>=0);)
|
||||
{
|
||||
#if defined(PULSE_AUDIO)
|
||||
if(SoundFD)
|
||||
pa_simple_write(SoundFD,SndData+RPtr,SND_BUFSIZE*sizeof(sample),0);
|
||||
#elif defined(SUN_AUDIO)
|
||||
/* Flush output first, don't care about return status. After this
|
||||
** write next buffer of audio data. This method produces a horrible
|
||||
** click on each buffer :( Any ideas, how to fix this?
|
||||
*/
|
||||
J = SND_BUFSIZE*sizeof(sample);
|
||||
ioctl(SoundFD,AUDIO_DRAIN);
|
||||
if(write(SoundFD,SndData+RPtr,J)!=J) { /* Something went wrong */ }
|
||||
#else
|
||||
/* We'll block here until next DMA buffer becomes free. It happens
|
||||
** once per SND_BUFSIZE/SndRate seconds.
|
||||
*/
|
||||
J = SND_BUFSIZE*sizeof(sample);
|
||||
if(write(SoundFD,SndData+RPtr,J)!=J) { /* Something went wrong */ }
|
||||
#endif
|
||||
|
||||
/* Advance buffer pointer, clearing the buffer */
|
||||
for(J=0;J<SND_BUFSIZE;++J) SndData[RPtr++]=AUDIO_CONV(0);
|
||||
if(RPtr>=SndSize) RPtr=0;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/** InitAudio() **********************************************/
|
||||
/** Initialize sound. Returns rate (Hz) on success, else 0. **/
|
||||
/** Rate=0 to skip initialization (will be silent). **/
|
||||
/*************************************************************/
|
||||
unsigned int InitAudio(unsigned int Rate,unsigned int Latency)
|
||||
{
|
||||
int I,J,K;
|
||||
|
||||
/* Shut down audio, just to be sure */
|
||||
TrashAudio();
|
||||
SndRate = 0;
|
||||
SoundFD = -1;
|
||||
SndSize = 0;
|
||||
SndData = 0;
|
||||
RPtr = 0;
|
||||
WPtr = 0;
|
||||
Thr = 0;
|
||||
AudioPaused = 0;
|
||||
|
||||
/* Have to have at least 8kHz sampling rate and 1ms buffer */
|
||||
if((Rate<8000)||!Latency) return(0);
|
||||
|
||||
/* Compute number of sound buffers */
|
||||
SndSize=(Rate*Latency/1000+SND_BUFSIZE-1)/SND_BUFSIZE;
|
||||
|
||||
#if defined(PULSE_AUDIO)
|
||||
|
||||
{
|
||||
/* Configure PulseAudio sound */
|
||||
pa_sample_spec PASpec;
|
||||
PASpec.format = sizeof(sample)>1? PA_SAMPLE_S16LE:PA_SAMPLE_U8;
|
||||
PASpec.rate = Rate;
|
||||
PASpec.channels = 1;
|
||||
/* Try opening PulseAudio */
|
||||
if(!(SoundFD=pa_simple_new(0,"EMULib",PA_STREAM_PLAYBACK,0,"playback",&PASpec,0,0,0)))
|
||||
{ SoundFD=-1;return(0); }
|
||||
}
|
||||
|
||||
#elif defined(ESD_AUDIO)
|
||||
|
||||
/* ESD options for playing wave audio */
|
||||
J=ESD_MONO|ESD_STREAM|ESD_PLAY|(sizeof(sample)>1? ESD_BITS16:ESD_BITS8);
|
||||
/* Open ESD socket, fall back to /dev/dsp is no ESD */
|
||||
if((SoundFD=esd_play_stream_fallback(J,Rate,0,0))<0) return(0);
|
||||
|
||||
#elif defined(SUN_AUDIO)
|
||||
|
||||
/* Open Sun's audio device */
|
||||
if((SoundFD=open("/dev/audio",O_WRONLY|O_NONBLOCK))<0) return(0);
|
||||
|
||||
/*
|
||||
** Sun's specific initialization should be here...
|
||||
** We assume, that it's set to 8000Hz u-law mono right now.
|
||||
*/
|
||||
|
||||
#else /* !SUN_AUDIO */
|
||||
|
||||
/* Open /dev/dsp audio device */
|
||||
if((SoundFD=open("/dev/dsp",O_WRONLY))<0) return(0);
|
||||
/* Set sound format */
|
||||
J=sizeof(sample)>1? AFMT_S16_NE:AFMT_U8;
|
||||
I=ioctl(SoundFD,SNDCTL_DSP_SETFMT,&J)<0;
|
||||
/* Set mono sound */
|
||||
J=0;
|
||||
I|=ioctl(SoundFD,SNDCTL_DSP_STEREO,&J)<0;
|
||||
/* Set sampling rate */
|
||||
I|=ioctl(SoundFD,SNDCTL_DSP_SPEED,&Rate)<0;
|
||||
|
||||
/* Set buffer length and number of buffers */
|
||||
J=K=SND_BITS|(SndSize<<16);
|
||||
I|=ioctl(SoundFD,SNDCTL_DSP_SETFRAGMENT,&J)<0;
|
||||
|
||||
/* Buffer length as n, not 2^n! */
|
||||
if((J&0xFFFF)<=16) J=(J&0xFFFF0000)|(1<<(J&0xFFFF));
|
||||
K=SND_BUFSIZE|(SndSize<<16);
|
||||
|
||||
/* Check audio parameters */
|
||||
I|=(J!=K)&&(((J>>16)<SndSize)||((J&0xFFFF)!=SND_BUFSIZE));
|
||||
|
||||
/* If something went wrong, drop out */
|
||||
if(I) { TrashSound();return(0); }
|
||||
|
||||
#endif /* !SUN_AUDIO */
|
||||
|
||||
/* SndSize now means the total buffer size */
|
||||
SndSize*=SND_BUFSIZE;
|
||||
|
||||
/* Allocate audio buffers */
|
||||
SndData=(sample *)malloc(SndSize*sizeof(sample));
|
||||
if(!SndData) { TrashSound();return(0); }
|
||||
|
||||
/* Clear audio buffers */
|
||||
for(J=0;J<SndSize;++J) SndData[J]=AUDIO_CONV(0);
|
||||
|
||||
/* Thread expects valid SndRate!=0 at the start */
|
||||
SndRate=Rate;
|
||||
|
||||
/* Create audio thread */
|
||||
if(pthread_create(&Thr,0,ThrHandler,0)) { TrashSound();SndRate=0;return(0); }
|
||||
|
||||
/* Done, return effective audio rate */
|
||||
return(SndRate);
|
||||
}
|
||||
|
||||
/** TrashAudio() *********************************************/
|
||||
/** Free resources allocated by InitAudio(). **/
|
||||
/*************************************************************/
|
||||
void TrashAudio(void)
|
||||
{
|
||||
int Error;
|
||||
|
||||
/* Sound off, pause off */
|
||||
SndRate = 0;
|
||||
AudioPaused = 0;
|
||||
|
||||
/* Wait for audio thread to finish */
|
||||
if(Thr) pthread_join(Thr,0);
|
||||
|
||||
/* If audio was initialized... */
|
||||
if(SoundFD>=0)
|
||||
{
|
||||
#if defined(PULSE_AUDIO)
|
||||
if(SoundFD) pa_simple_free(SoundFD);
|
||||
#elif defined(ESD_AUDIO)
|
||||
esd_close(SoundFD);
|
||||
#elif defined(SUN_AUDIO)
|
||||
close(SoundFD);
|
||||
#else
|
||||
ioctl(SoundFD,SNDCTL_DSP_RESET);
|
||||
close(SoundFD);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* If buffers were allocated... */
|
||||
if(SndData) free(SndData);
|
||||
|
||||
/* Sound trashed */
|
||||
SoundFD = -1;
|
||||
SndData = 0;
|
||||
SndSize = 0;
|
||||
RPtr = 0;
|
||||
WPtr = 0;
|
||||
Thr = 0;
|
||||
}
|
||||
|
||||
/** PauseAudio() *********************************************/
|
||||
/** Pause/resume audio playback. Returns current playback **/
|
||||
/** state. **/
|
||||
/*************************************************************/
|
||||
int PauseAudio(int Switch)
|
||||
{
|
||||
static int Rate,Latency;
|
||||
|
||||
/* If audio not initialized, return "off" */
|
||||
if(!SndRate&&!AudioPaused) return(0);
|
||||
|
||||
/* Toggle audio status if requested */
|
||||
if(Switch==2) Switch=AudioPaused? 0:1;
|
||||
|
||||
/* When switching audio state... */
|
||||
if((Switch>=0)&&(Switch<=1)&&(Switch!=AudioPaused))
|
||||
{
|
||||
if(Switch)
|
||||
{
|
||||
/* Memorize audio parameters and kill audio */
|
||||
Rate = SndRate;
|
||||
Latency = 1000*SndSize/SndRate;
|
||||
TrashAudio();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Start audio using memorized parameters */
|
||||
if(!InitAudio(Rate,Latency)) Switch=0;
|
||||
}
|
||||
|
||||
/* Audio switched */
|
||||
AudioPaused=Switch;
|
||||
}
|
||||
|
||||
/* Return current status */
|
||||
return(AudioPaused);
|
||||
}
|
||||
|
||||
/** GetFreeAudio() *******************************************/
|
||||
/** Get the amount of free samples in the audio buffer. **/
|
||||
/*************************************************************/
|
||||
unsigned int GetFreeAudio(void)
|
||||
{
|
||||
return(!SndRate? 0:RPtr>=WPtr? RPtr-WPtr:RPtr-WPtr+SndSize);
|
||||
}
|
||||
|
||||
/** WriteAudio() *********************************************/
|
||||
/** Write up to a given number of samples to audio buffer. **/
|
||||
/** Returns the number of samples written. **/
|
||||
/*************************************************************/
|
||||
unsigned int WriteAudio(sample *Data,unsigned int Length)
|
||||
{
|
||||
unsigned int J;
|
||||
|
||||
/* Require audio to be initialized */
|
||||
if(!SndRate) return(0);
|
||||
|
||||
/* Copy audio samples */
|
||||
for(J=0;(J<Length)&&(RPtr!=WPtr);++J)
|
||||
{
|
||||
SndData[WPtr++]=AUDIO_CONV(Data[J]);
|
||||
if(WPtr>=SndSize) WPtr=0;
|
||||
}
|
||||
|
||||
/* Return number of samples copied */
|
||||
return(J);
|
||||
}
|
||||
|
||||
Regular → Executable
+2
-12
@@ -5,7 +5,7 @@
|
||||
/** This file contains implementation for the ED table of **/
|
||||
/** Z80 commands. It is included from Z80.c. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2014 **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2017 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
@@ -96,22 +96,12 @@ case LD_A_I:
|
||||
break;
|
||||
|
||||
case LD_A_R:
|
||||
#ifdef REAL_REG_R
|
||||
R->AF.B.h=R->R;
|
||||
#else
|
||||
++R->R;
|
||||
R->AF.B.h=(byte)(R->R-R->ICount);
|
||||
#endif
|
||||
R->AF.B.l=(R->AF.B.l&C_FLAG)|(R->IFF&IFF_2? P_FLAG:0)|ZSTable[R->AF.B.h];
|
||||
break;
|
||||
|
||||
case LD_I_A: R->I=R->AF.B.h;break;
|
||||
|
||||
#ifdef REAL_REG_R
|
||||
case LD_R_A: R->R=R->AF.B.h;break;
|
||||
#else
|
||||
case LD_R_A: break;
|
||||
#endif
|
||||
|
||||
case IM_0: R->IFF&=~(IFF_IM1|IFF_IM2);break;
|
||||
case IM_1: R->IFF=(R->IFF&~IFF_IM2)|IFF_IM1;break;
|
||||
@@ -272,7 +262,7 @@ case CPIR:
|
||||
R->AF.B.l =
|
||||
N_FLAG|(R->AF.B.l&C_FLAG)|ZSTable[J.B.l]|
|
||||
((R->AF.B.h^I^J.B.l)&H_FLAG)|(R->BC.W? P_FLAG:0);
|
||||
break;
|
||||
break;
|
||||
|
||||
case CPD:
|
||||
I=RdZ80(R->HL.W--);
|
||||
|
||||
Regular → Executable
+10
-1
@@ -7,7 +7,7 @@
|
||||
/** ommitted, ConDebug.c just includes the default command **/
|
||||
/** line based debugger (Debug.c). **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 2005-2014 **/
|
||||
/** Copyright (C) Marat Fayzullin 2005-2017 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
@@ -33,6 +33,10 @@
|
||||
#include "Debug.c"
|
||||
#undef DebugZ80
|
||||
|
||||
#ifdef SPECCY
|
||||
#include "Spectrum.h"
|
||||
#endif
|
||||
|
||||
#define CLR_BACK PIXEL(255,255,255)
|
||||
#define CLR_TEXT PIXEL(0,0,0)
|
||||
#define CLR_DIALOG PIXEL(0,100,0)
|
||||
@@ -68,6 +72,11 @@ byte DebugZ80(Z80 *R)
|
||||
return(1);
|
||||
}
|
||||
|
||||
#ifdef SPECCY
|
||||
/* Show currently refreshed scanline on Speccy */
|
||||
RefreshScreen();
|
||||
#endif
|
||||
|
||||
X = ((VideoW>>3)-32)>>1;
|
||||
Y = ((VideoH>>3)-23)>>1;
|
||||
Addr = R->PC.W;
|
||||
|
||||
Regular → Executable
+21
-23
@@ -6,7 +6,7 @@
|
||||
/** the Z80 emulator which is called on each Z80 step when **/
|
||||
/** Trap!=0. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1995-2014 **/
|
||||
/** Copyright (C) Marat Fayzullin 1995-2017 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
@@ -270,40 +270,38 @@ static int DAsm(char *S,word A)
|
||||
default: T=Mnemonics[RdZ80(B++)];
|
||||
}
|
||||
|
||||
if(P=strchr(T,'^'))
|
||||
if((P=strchr(T,'^')))
|
||||
{
|
||||
strncpy(R,T,P-T);R[P-T]='\0';
|
||||
sprintf(H,"%02X",RdZ80(B++));
|
||||
strcat(R,H);strcat(R,P+1);
|
||||
}
|
||||
else strcpy(R,T);
|
||||
if(P=strchr(R,'%')) *P=C;
|
||||
if((P=strchr(R,'%'))) *P=C;
|
||||
|
||||
if(P=strchr(R,'*'))
|
||||
if((P=strchr(R,'*')))
|
||||
{
|
||||
strncpy(S,R,P-R);S[P-R]='\0';
|
||||
sprintf(H,"%02X",RdZ80(B++));
|
||||
strcat(S,H);strcat(S,P+1);
|
||||
}
|
||||
else
|
||||
if(P=strchr(R,'@'))
|
||||
{
|
||||
strncpy(S,R,P-R);S[P-R]='\0';
|
||||
if(!J) Offset=RdZ80(B++);
|
||||
strcat(S,Offset&0x80? "-":"+");
|
||||
J=Offset&0x80? 256-Offset:Offset;
|
||||
sprintf(H,"%02X",J);
|
||||
strcat(S,H);strcat(S,P+1);
|
||||
}
|
||||
else
|
||||
if(P=strchr(R,'#'))
|
||||
{
|
||||
strncpy(S,R,P-R);S[P-R]='\0';
|
||||
sprintf(H,"%04X",RdZ80(B)+256*RdZ80(B+1));
|
||||
strcat(S,H);strcat(S,P+1);
|
||||
B+=2;
|
||||
}
|
||||
else strcpy(S,R);
|
||||
else if((P=strchr(R,'@')))
|
||||
{
|
||||
strncpy(S,R,P-R);S[P-R]='\0';
|
||||
if(!J) Offset=RdZ80(B++);
|
||||
strcat(S,Offset&0x80? "-":"+");
|
||||
J=Offset&0x80? 256-Offset:Offset;
|
||||
sprintf(H,"%02X",J);
|
||||
strcat(S,H);strcat(S,P+1);
|
||||
}
|
||||
else if((P=strchr(R,'#')))
|
||||
{
|
||||
strncpy(S,R,P-R);S[P-R]='\0';
|
||||
sprintf(H,"%04X",RdZ80(B)+256*RdZ80(B+1));
|
||||
strcat(S,H);strcat(S,P+1);
|
||||
B+=2;
|
||||
}
|
||||
else strcpy(S,R);
|
||||
|
||||
return(B-A);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/** LoopZ80(), and PatchZ80() functions to accomodate the **/
|
||||
/** emulated machine's architecture. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2014 **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2017 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
@@ -32,9 +32,9 @@
|
||||
/** up. It has to stay inlined to be fast. **/
|
||||
/*************************************************************/
|
||||
#ifdef COLEM
|
||||
#define RdZ80 RDZ80
|
||||
#define FAST_RDOP
|
||||
extern byte *ROMPage[];
|
||||
INLINE byte RdZ80(word A) { return(ROMPage[A>>13][A&0x1FFF]); }
|
||||
INLINE byte OpZ80(word A) { return(ROMPage[A>>13][A&0x1FFF]); }
|
||||
#endif
|
||||
|
||||
#ifdef SPECCY
|
||||
@@ -78,12 +78,7 @@ INLINE void WrZ80(word A,byte V) { if(Page[A>>14]<ROM) Page[A>>14][A&0x3FFF]=V;
|
||||
#define S(Fl) R->AF.B.l|=Fl
|
||||
#define R(Fl) R->AF.B.l&=~(Fl)
|
||||
#define FLAGS(Rg,Fl) R->AF.B.l=Fl|ZSTable[Rg]
|
||||
|
||||
#ifdef REAL_REG_R
|
||||
#define INCR(N) R->R=((R->R+(N))&0x7F)|(R->R&0x80)
|
||||
#else
|
||||
#define INCR(N)
|
||||
#endif
|
||||
|
||||
#define M_RLC(Rg) \
|
||||
R->AF.B.l=Rg>>7;Rg=(Rg<<1)|R->AF.B.l;R->AF.B.l|=PZSTable[Rg]
|
||||
@@ -111,7 +106,7 @@ INLINE void WrZ80(word A,byte V) { if(Page[A>>14]<ROM) Page[A>>14][A&0x3FFF]=V;
|
||||
Rg=(Rg>>1)|(R->AF.B.l<<7); \
|
||||
R->AF.B.l=PZSTable[Rg]; \
|
||||
}
|
||||
|
||||
|
||||
#define M_SLA(Rg) \
|
||||
R->AF.B.l=Rg>>7;Rg<<=1;R->AF.B.l|=PZSTable[Rg]
|
||||
#define M_SRA(Rg) \
|
||||
@@ -155,7 +150,7 @@ INLINE void WrZ80(word A,byte V) { if(Page[A>>14]<ROM) Page[A>>14][A&0x3FFF]=V;
|
||||
(~(R->AF.B.h^Rg)&(Rg^J.B.l)&0x80? V_FLAG:0)| \
|
||||
J.B.h|ZSTable[J.B.l]| \
|
||||
((R->AF.B.h^Rg^J.B.l)&H_FLAG); \
|
||||
R->AF.B.h=J.B.l
|
||||
R->AF.B.h=J.B.l
|
||||
|
||||
#define M_SUB(Rg) \
|
||||
J.W=R->AF.B.h-Rg; \
|
||||
@@ -224,7 +219,7 @@ INLINE void WrZ80(word A,byte V) { if(Page[A>>14]<ROM) Page[A>>14][A&0x3FFF]=V;
|
||||
((R->HL.W^R->Rg.W^J.W)&0x1000? H_FLAG:0)| \
|
||||
(J.W? 0:Z_FLAG)|(J.B.h&S_FLAG); \
|
||||
R->HL.W=J.W
|
||||
|
||||
|
||||
#define M_SBCW(Rg) \
|
||||
I=R->AF.B.l&C_FLAG;J.W=(R->HL.W-R->Rg.W-I)&0xFFFF; \
|
||||
R->AF.B.l= \
|
||||
@@ -296,7 +291,7 @@ enum CodesCB
|
||||
RES4_B,RES4_C,RES4_D,RES4_E,RES4_H,RES4_L,RES4_xHL,RES4_A,
|
||||
RES5_B,RES5_C,RES5_D,RES5_E,RES5_H,RES5_L,RES5_xHL,RES5_A,
|
||||
RES6_B,RES6_C,RES6_D,RES6_E,RES6_H,RES6_L,RES6_xHL,RES6_A,
|
||||
RES7_B,RES7_C,RES7_D,RES7_E,RES7_H,RES7_L,RES7_xHL,RES7_A,
|
||||
RES7_B,RES7_C,RES7_D,RES7_E,RES7_H,RES7_L,RES7_xHL,RES7_A,
|
||||
SET0_B,SET0_C,SET0_D,SET0_E,SET0_H,SET0_L,SET0_xHL,SET0_A,
|
||||
SET1_B,SET1_C,SET1_D,SET1_E,SET1_H,SET1_L,SET1_xHL,SET1_A,
|
||||
SET2_B,SET2_C,SET2_D,SET2_E,SET2_H,SET2_L,SET2_xHL,SET2_A,
|
||||
@@ -306,7 +301,7 @@ enum CodesCB
|
||||
SET6_B,SET6_C,SET6_D,SET6_E,SET6_H,SET6_L,SET6_xHL,SET6_A,
|
||||
SET7_B,SET7_C,SET7_D,SET7_E,SET7_H,SET7_L,SET7_xHL,SET7_A
|
||||
};
|
||||
|
||||
|
||||
enum CodesED
|
||||
{
|
||||
DB_00,DB_01,DB_02,DB_03,DB_04,DB_05,DB_06,DB_07,
|
||||
@@ -360,7 +355,7 @@ static void CodesCB(register Z80 *R)
|
||||
default:
|
||||
if(R->TrapBadOps)
|
||||
printf
|
||||
(
|
||||
(
|
||||
"[Z80 %lX] Unrecognized instruction: CB %02X at PC=%04X\n",
|
||||
(long)(R->User),OpZ80(R->PC.W-1),R->PC.W-2
|
||||
);
|
||||
@@ -372,7 +367,7 @@ static void CodesDDCB(register Z80 *R)
|
||||
register pair J;
|
||||
register byte I;
|
||||
|
||||
#define XX IX
|
||||
#define XX IX
|
||||
/* Get offset, read opcode and count cycles */
|
||||
J.W=R->XX.W+(offset)OpZ80(R->PC.W++);
|
||||
I=OpZ80(R->PC.W++);
|
||||
@@ -692,7 +687,7 @@ word RunZ80(Z80 *R)
|
||||
case PFX_FD: CodesFD(R);break;
|
||||
case PFX_DD: CodesDD(R);break;
|
||||
}
|
||||
|
||||
|
||||
/* If cycle counter expired... */
|
||||
if(R->ICount<=0)
|
||||
{
|
||||
|
||||
+26
-26
@@ -220,8 +220,8 @@ static const struct { byte R2,R3,R4,R5,M2,M3,M4,M5; } MSK[MAXSCREEN+2] =
|
||||
};
|
||||
|
||||
/** MegaROM Mapper Names *************************************/
|
||||
static const char *ROMNames[MAXMAPPERS+1] =
|
||||
{
|
||||
static const char *ROMNames[MAXMAPPERS+1] =
|
||||
{
|
||||
"GENERIC/8kB","GENERIC/16kB","KONAMI5/8kB",
|
||||
"KONAMI4/8kB","ASCII/8kB","ASCII/16kB",
|
||||
"GMASTER2/SRAM","FMPAC/SRAM","UNKNOWN"
|
||||
@@ -392,7 +392,7 @@ int StartMSX(int NewMode,int NewRAMPages,int NewVRAMPages)
|
||||
/*** STARTUP CODE starts here: ***/
|
||||
|
||||
T=(int *)"\01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
||||
#ifdef MSB_FIRST
|
||||
#ifdef MSB_FIRST
|
||||
if(*T==1)
|
||||
{
|
||||
printf("********* This machine is little-endian. **********\n");
|
||||
@@ -428,7 +428,7 @@ int StartMSX(int NewMode,int NewRAMPages,int NewVRAMPages)
|
||||
ROMType[J] = 0;
|
||||
SRAMData[J] = 0;
|
||||
SRAMName[J] = 0;
|
||||
SaveSRAM[J] = 0;
|
||||
SaveSRAM[J] = 0;
|
||||
}
|
||||
|
||||
/* UPeriod has ot be in 1%..100% range */
|
||||
@@ -552,7 +552,7 @@ int StartMSX(int NewMode,int NewRAMPages,int NewVRAMPages)
|
||||
{
|
||||
FDD[J].Verbose=Verbose&0x04;
|
||||
if(ChangeDisk(J,DSKName[J]))
|
||||
if(Verbose) printf("Inserting %s into drive %c\n",DSKName[J],J+'A');
|
||||
if(Verbose) printf("Inserting %s into drive %c\n",DSKName[J],J+'A');
|
||||
}
|
||||
|
||||
/* Initialize sound logging */
|
||||
@@ -616,7 +616,7 @@ void TrashMSX(void)
|
||||
|
||||
/* Close tape */
|
||||
ChangeTape(0);
|
||||
|
||||
|
||||
/* Close all IO streams */
|
||||
if(ComOStream&&(ComOStream!=stdout)) fclose(ComOStream);
|
||||
if(ComIStream&&(ComIStream!=stdin)) fclose(ComIStream);
|
||||
@@ -697,7 +697,7 @@ int ResetMSX(int NewMode,int NewRAMPages,int NewVRAMPages)
|
||||
if(Verbose) printf(" Opening MSX2EXT.ROM...");
|
||||
P2=LoadROM("MSX2EXT.ROM",0x4000,0);
|
||||
PRINTRESULT(P2);
|
||||
if(!P1||!P2)
|
||||
if(!P1||!P2)
|
||||
{
|
||||
NewMode=(NewMode&~MSX_MODEL)|(Mode&MSX_MODEL);
|
||||
FreeMemory(P1);
|
||||
@@ -723,7 +723,7 @@ int ResetMSX(int NewMode,int NewRAMPages,int NewVRAMPages)
|
||||
if(Verbose) printf(" Opening MSX2PEXT.ROM...");
|
||||
P2=LoadROM("MSX2PEXT.ROM",0x4000,0);
|
||||
PRINTRESULT(P2);
|
||||
if(!P1||!P2)
|
||||
if(!P1||!P2)
|
||||
{
|
||||
NewMode=(NewMode&~MSX_MODEL)|(Mode&MSX_MODEL);
|
||||
FreeMemory(P1);
|
||||
@@ -1104,7 +1104,7 @@ case 0x99: /* VDP status registers */
|
||||
/* Read an appropriate status register */
|
||||
Port=VDPStatus[VDP[15]];
|
||||
/* Reset VAddr latch sequencer */
|
||||
// @@@ This breaks Sir Lancelot on ColecoVision, so it must be wrong!
|
||||
// @@@ This breaks Sir Lancelot on ColecoVision, so it must be wrong!
|
||||
// VKey=1;
|
||||
/* Update status register's contents */
|
||||
switch(VDP[15])
|
||||
@@ -1206,7 +1206,7 @@ case 0x7C: WrCtrl2413(&OPLL,Value);return; /* OPLL Register# */
|
||||
case 0x7D: WrData2413(&OPLL,Value);return; /* OPLL Data */
|
||||
case 0x91: Printer(Value);return; /* Printer Data */
|
||||
case 0xA0: WrCtrl8910(&PSG,Value);return; /* PSG Register# */
|
||||
case 0xB4: RTCReg=Value&0x0F;return; /* RTC Register# */
|
||||
case 0xB4: RTCReg=Value&0x0F;return; /* RTC Register# */
|
||||
|
||||
case 0xD8: /* Upper bits of Kanji ROM address */
|
||||
KanLetter=(KanLetter&0x1F800)|((int)(Value&0x3F)<<5);
|
||||
@@ -1246,7 +1246,7 @@ case 0x98: /* VDP Data */
|
||||
VPAGE[VAddr]=Value;
|
||||
}
|
||||
/* If VAddr rolled over, modify VRAM page# */
|
||||
if(!VAddr&&(ScrMode>3))
|
||||
if(!VAddr&&(ScrMode>3))
|
||||
{
|
||||
VDP[14]=(VDP[14]+1)&(VRAMPages-1);
|
||||
VPAGE=VRAM+((int)VDP[14]<<14);
|
||||
@@ -1346,7 +1346,7 @@ case 0xAB: /* PPI control register */
|
||||
if(PPI.Rout[2]!=IOReg) { PPIOut(PPI.Rout[2],IOReg);IOReg=PPI.Rout[2]; }
|
||||
/* If primary slot state has changed... */
|
||||
if(PPI.Rout[0]!=PSLReg) PSlot(PPI.Rout[0]);
|
||||
/* Done */
|
||||
/* Done */
|
||||
return;
|
||||
|
||||
case 0xB5: /* RTC Data */
|
||||
@@ -1714,7 +1714,7 @@ printf("(%04Xh) = %02Xh at PC=%04Xh\n",A,V,CPU.PC.W);
|
||||
break;
|
||||
}
|
||||
|
||||
/* No MegaROM mapper or there is an incorrect write */
|
||||
/* No MegaROM mapper or there is an incorrect write */
|
||||
if(Verbose&0x08) printf("MEMORY: Bad write (%d:%d:%04Xh) = %02Xh\n",PS,SS,A,V);
|
||||
}
|
||||
|
||||
@@ -1725,7 +1725,7 @@ printf("(%04Xh) = %02Xh at PC=%04Xh\n",A,V,CPU.PC.W);
|
||||
void PSlot(register byte V)
|
||||
{
|
||||
register byte J,I;
|
||||
|
||||
|
||||
if(PSLReg!=V)
|
||||
for(PSLReg=V,J=0;J<4;++J,V>>=2)
|
||||
{
|
||||
@@ -1858,10 +1858,10 @@ void SetMegaROM(int Slot,byte P0,byte P1,byte P2,byte P3)
|
||||
/** Write value into a given VDP register. **/
|
||||
/*************************************************************/
|
||||
void VDPOut(register byte R,register byte V)
|
||||
{
|
||||
{
|
||||
register byte J;
|
||||
|
||||
switch(R)
|
||||
switch(R)
|
||||
{
|
||||
case 0: /* Reset HBlank interrupt if disabled */
|
||||
if((VDPStatus[1]&0x01)&&!(V&0x10))
|
||||
@@ -1912,7 +1912,7 @@ void VDPOut(register byte R,register byte V)
|
||||
|
||||
/* Write value into a register */
|
||||
VDP[R]=V;
|
||||
}
|
||||
}
|
||||
|
||||
/** Printer() ************************************************/
|
||||
/** Send a character to the printer. **/
|
||||
@@ -1985,7 +1985,7 @@ byte RTCIn(register byte R)
|
||||
case 11: J=(TM.tm_year-80)%10;break;
|
||||
case 12: J=((TM.tm_year-80)/10)%10;break;
|
||||
default: J=0x0F;break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Four upper bits are always high */
|
||||
@@ -2230,7 +2230,7 @@ void CheckSprites(void)
|
||||
for(J=0,S=SprTab;J<N;++J,S+=4)
|
||||
if((S[3]&0x0F)||M)
|
||||
for(I=J+1,D=S+4;I<N;++I,D+=4)
|
||||
if((D[3]&0x0F)||M)
|
||||
if((D[3]&0x0F)||M)
|
||||
{
|
||||
DV=S[0]-D[0];
|
||||
if((DV<16)||(DV>240))
|
||||
@@ -2539,7 +2539,7 @@ byte LoadFNT(const char *FileName)
|
||||
fread(FontBuf,1,256*8,F);
|
||||
/* Done */
|
||||
fclose(F);
|
||||
return(1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** LoadROM() ************************************************/
|
||||
@@ -2740,7 +2740,7 @@ int LoadCart(const char *FileName,int Slot,int Type)
|
||||
C2=fgetc(F);
|
||||
}
|
||||
|
||||
/* If we can't find "AB" signature, drop out */
|
||||
/* If we can't find "AB" signature, drop out */
|
||||
if((C1!='A')||(C2!='B'))
|
||||
{
|
||||
if(Verbose) puts(" Not a valid cartridge ROM");
|
||||
@@ -2777,7 +2777,7 @@ int LoadCart(const char *FileName,int Slot,int Type)
|
||||
ROMData[Slot]+Len*0x2000,
|
||||
ROMData[Slot]+(Len-Pages/2)*0x2000,
|
||||
(Pages-Len)*0x2000
|
||||
);
|
||||
);
|
||||
|
||||
/* Set memory map depending on the ROM size */
|
||||
switch(Len)
|
||||
@@ -2882,7 +2882,7 @@ int LoadCart(const char *FileName,int Slot,int Type)
|
||||
if(SRAMName[Slot]=GetMemory(strlen(FileName)+5))
|
||||
{
|
||||
/* Compose SRAM file name */
|
||||
strcpy(SRAMName[Slot],FileName);
|
||||
strcpy(SRAMName[Slot],FileName);
|
||||
P=strrchr(SRAMName[Slot],'.');
|
||||
if(P) strcpy(P,".sav"); else strcat(SRAMName[Slot],".sav");
|
||||
/* Try opening file... */
|
||||
@@ -2918,7 +2918,7 @@ int LoadCart(const char *FileName,int Slot,int Type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Done setting up cartridge */
|
||||
@@ -3004,7 +3004,7 @@ unsigned int SaveState(unsigned char *Buf,unsigned int MaxSize)
|
||||
State[J++] = SSL[I];
|
||||
State[J++] = EnWrite[I];
|
||||
State[J++] = RAMMapper[I];
|
||||
}
|
||||
}
|
||||
|
||||
/* Cartridge setup */
|
||||
for(I=0;I<MAXSLOTS;++I)
|
||||
@@ -3082,7 +3082,7 @@ unsigned int LoadState(unsigned char *Buf,unsigned int MaxSize)
|
||||
SSL[I] = State[J++];
|
||||
EnWrite[I] = State[J++];
|
||||
RAMMapper[I] = State[J++];
|
||||
}
|
||||
}
|
||||
|
||||
/* Cartridge setup */
|
||||
for(I=0;I<MAXSLOTS;++I)
|
||||
|
||||
Executable
+322
@@ -0,0 +1,322 @@
|
||||
/** fMSX: portable MSX emulator ******************************/
|
||||
/** **/
|
||||
/** State.h **/
|
||||
/** **/
|
||||
/** This file contains routines to save and load emulation **/
|
||||
/** state. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2017 **/
|
||||
/** The contents of this file are property of Marat **/
|
||||
/** Fayzullin and should only be used as agreed with **/
|
||||
/** him. The file is confidential. Absolutely no **/
|
||||
/** distribution allowed. **/
|
||||
/*************************************************************/
|
||||
#ifndef STATE_H
|
||||
#define STATE_H
|
||||
|
||||
#define SaveSTRUCT(Name) \
|
||||
if(Size+sizeof(Name)>MaxSize) return(0); \
|
||||
else { memcpy(Buf+Size,&(Name),sizeof(Name));Size+=sizeof(Name); }
|
||||
|
||||
#define SaveARRAY(Name) \
|
||||
if(Size+sizeof(Name)>MaxSize) return(0); \
|
||||
else { memcpy(Buf+Size,(Name),sizeof(Name));Size+=sizeof(Name); }
|
||||
|
||||
#define SaveDATA(Name,DataSize) \
|
||||
if(Size+(DataSize)>MaxSize) return(0); \
|
||||
else { memcpy(Buf+Size,(Name),(DataSize));Size+=(DataSize); }
|
||||
|
||||
#define LoadSTRUCT(Name) \
|
||||
if(Size+sizeof(Name)>MaxSize) return(0); \
|
||||
else { memcpy(&(Name),Buf+Size,sizeof(Name));Size+=sizeof(Name); }
|
||||
|
||||
#define SkipSTRUCT(Name) \
|
||||
if(Size+sizeof(Name)>MaxSize) return(0); \
|
||||
else Size+=sizeof(Name)
|
||||
|
||||
#define LoadARRAY(Name) \
|
||||
if(Size+sizeof(Name)>MaxSize) return(0); \
|
||||
else { memcpy((Name),Buf+Size,sizeof(Name));Size+=sizeof(Name); }
|
||||
|
||||
#define LoadDATA(Name,DataSize) \
|
||||
if(Size+(DataSize)>MaxSize) return(0); \
|
||||
else { memcpy((Name),Buf+Size,(DataSize));Size+=(DataSize); }
|
||||
|
||||
#define SkipDATA(DataSize) \
|
||||
if(Size+(DataSize)>MaxSize) return(0); \
|
||||
else Size+=(DataSize)
|
||||
|
||||
/** SaveState() **********************************************/
|
||||
/** Save emulation state to a memory buffer. Returns size **/
|
||||
/** on success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
unsigned int SaveState(unsigned char *Buf,unsigned int MaxSize)
|
||||
{
|
||||
unsigned int State[256],Size;
|
||||
int J,I,K;
|
||||
|
||||
/* No data written yet */
|
||||
Size = 0;
|
||||
|
||||
/* Fill out hardware state */
|
||||
J=0;
|
||||
memset(State,0,sizeof(State));
|
||||
State[J++] = VDPData;
|
||||
State[J++] = PLatch;
|
||||
State[J++] = ALatch;
|
||||
State[J++] = VAddr;
|
||||
State[J++] = VKey;
|
||||
State[J++] = PKey;
|
||||
State[J++] = 0; /* was WKey (deprecated) */
|
||||
State[J++] = IRQPending;
|
||||
State[J++] = ScanLine;
|
||||
State[J++] = RTCReg;
|
||||
State[J++] = RTCMode;
|
||||
State[J++] = KanLetter;
|
||||
State[J++] = KanCount;
|
||||
State[J++] = IOReg;
|
||||
State[J++] = PSLReg;
|
||||
State[J++] = FMPACKey;
|
||||
|
||||
/* Memory setup */
|
||||
for(I=0;I<4;++I)
|
||||
{
|
||||
State[J++] = SSLReg[I];
|
||||
State[J++] = PSL[I];
|
||||
State[J++] = SSL[I];
|
||||
State[J++] = EnWrite[I];
|
||||
State[J++] = RAMMapper[I];
|
||||
}
|
||||
|
||||
/* Cartridge setup */
|
||||
for(I=0;I<MAXSLOTS;++I)
|
||||
{
|
||||
State[J++] = ROMType[I];
|
||||
for(K=0;K<4;++K) State[J++]=ROMMapper[I][K];
|
||||
}
|
||||
|
||||
/* Write out data structures */
|
||||
SaveSTRUCT(CPU);
|
||||
SaveSTRUCT(PPI);
|
||||
SaveSTRUCT(VDP);
|
||||
SaveARRAY(VDPStatus);
|
||||
SaveARRAY(Palette);
|
||||
SaveSTRUCT(PSG);
|
||||
SaveSTRUCT(OPLL);
|
||||
SaveSTRUCT(SCChip);
|
||||
SaveARRAY(State);
|
||||
SaveDATA(RAMData,RAMPages*0x4000);
|
||||
SaveDATA(VRAM,VRAMPages*0x4000);
|
||||
|
||||
/* Return amount of data written */
|
||||
return(Size);
|
||||
}
|
||||
|
||||
/** LoadState() **********************************************/
|
||||
/** Load emulation state from a memory buffer. Returns size **/
|
||||
/** on success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
unsigned int LoadState(unsigned char *Buf,unsigned int MaxSize)
|
||||
{
|
||||
int State[256],J,I,K;
|
||||
unsigned int Size;
|
||||
|
||||
/* No data read yet */
|
||||
Size = 0;
|
||||
|
||||
/* Load hardware state */
|
||||
LoadSTRUCT(CPU);
|
||||
LoadSTRUCT(PPI);
|
||||
LoadSTRUCT(VDP);
|
||||
LoadARRAY(VDPStatus);
|
||||
LoadARRAY(Palette);
|
||||
LoadSTRUCT(PSG);
|
||||
LoadSTRUCT(OPLL);
|
||||
LoadSTRUCT(SCChip);
|
||||
LoadARRAY(State);
|
||||
LoadDATA(RAMData,RAMPages*0x4000);
|
||||
LoadDATA(VRAM,VRAMPages*0x4000);
|
||||
|
||||
/* Parse hardware state */
|
||||
J=0;
|
||||
VDPData = State[J++];
|
||||
PLatch = State[J++];
|
||||
ALatch = State[J++];
|
||||
VAddr = State[J++];
|
||||
VKey = State[J++];
|
||||
PKey = State[J++];
|
||||
J++; /* was WKey = State[J++]; */
|
||||
IRQPending = State[J++];
|
||||
ScanLine = State[J++];
|
||||
RTCReg = State[J++];
|
||||
RTCMode = State[J++];
|
||||
KanLetter = State[J++];
|
||||
KanCount = State[J++];
|
||||
IOReg = State[J++];
|
||||
PSLReg = State[J++];
|
||||
FMPACKey = State[J++];
|
||||
|
||||
/* Memory setup */
|
||||
for(I=0;I<4;++I)
|
||||
{
|
||||
SSLReg[I] = State[J++];
|
||||
PSL[I] = State[J++];
|
||||
SSL[I] = State[J++];
|
||||
EnWrite[I] = State[J++];
|
||||
RAMMapper[I] = State[J++];
|
||||
}
|
||||
|
||||
/* Cartridge setup */
|
||||
for(I=0;I<MAXSLOTS;++I)
|
||||
{
|
||||
ROMType[I] = State[J++];
|
||||
for(K=0;K<4;++K) ROMMapper[I][K]=State[J++];
|
||||
|
||||
/* Correction for older states */
|
||||
if(ROMType[I]==MAP_FMPAC)
|
||||
ROMMapper[I][1]=ROMMapper[I][0]|1;
|
||||
else if((ROMType[I]==MAP_ASCII16)||(ROMType[I]==MAP_GEN16))
|
||||
{
|
||||
ROMMapper[I][1]=ROMMapper[I][0]|1;
|
||||
ROMMapper[I][3]=ROMMapper[I][2]|1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RAM mapper pages */
|
||||
if(RAMMask)
|
||||
for(I=0;I<4;++I)
|
||||
{
|
||||
RAMMapper[I] &= RAMMask;
|
||||
MemMap[3][2][I*2] = RAMData+RAMMapper[I]*0x4000;
|
||||
MemMap[3][2][I*2+1] = MemMap[3][2][I*2]+0x2000;
|
||||
}
|
||||
|
||||
/* Set ROM mapper pages */
|
||||
for(I=0;I<MAXSLOTS;++I)
|
||||
if(ROMData[I]&&ROMMask[I])
|
||||
SetMegaROM(I,ROMMapper[I][0],ROMMapper[I][1],ROMMapper[I][2],ROMMapper[I][3]);
|
||||
|
||||
/* Set main address space pages */
|
||||
for(I=0;I<4;++I)
|
||||
{
|
||||
RAM[2*I] = MemMap[PSL[I]][SSL[I]][2*I];
|
||||
RAM[2*I+1] = MemMap[PSL[I]][SSL[I]][2*I+1];
|
||||
}
|
||||
|
||||
/* Set palette */
|
||||
for(I=0;I<16;++I)
|
||||
SetColor(I,(Palette[I]>>16)&0xFF,(Palette[I]>>8)&0xFF,Palette[I]&0xFF);
|
||||
|
||||
/* Set screen mode and VRAM table addresses */
|
||||
SetScreen();
|
||||
|
||||
/* Set some other variables */
|
||||
VPAGE = VRAM+((int)VDP[14]<<14);
|
||||
FGColor = VDP[7]>>4;
|
||||
BGColor = VDP[7]&0x0F;
|
||||
XFGColor = FGColor;
|
||||
XBGColor = BGColor;
|
||||
|
||||
/* All sound channels could have been changed */
|
||||
PSG.Changed = (1<<AY8910_CHANNELS)-1;
|
||||
SCChip.Changed = (1<<SCC_CHANNELS)-1;
|
||||
SCChip.WChanged = (1<<SCC_CHANNELS)-1;
|
||||
OPLL.Changed = (1<<YM2413_CHANNELS)-1;
|
||||
OPLL.PChanged = (1<<YM2413_CHANNELS)-1;
|
||||
OPLL.DChanged = (1<<YM2413_CHANNELS)-1;
|
||||
|
||||
/* Return amount of data read */
|
||||
return(Size);
|
||||
}
|
||||
|
||||
/** SaveSTA() ************************************************/
|
||||
/** Save emulation state into a .STA file. Returns 1 on **/
|
||||
/** success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
int SaveSTA(const char *Name)
|
||||
{
|
||||
static byte Header[16] = "STE\032\003\0\0\0\0\0\0\0\0\0\0\0";
|
||||
unsigned int J,Size;
|
||||
byte *Buf;
|
||||
FILE *F;
|
||||
|
||||
/* Fail if no state file */
|
||||
if(!Name) return(0);
|
||||
|
||||
/* Allocate temporary buffer */
|
||||
Buf = malloc(MAX_STASIZE);
|
||||
if(!Buf) return(0);
|
||||
|
||||
/* Try saving state */
|
||||
Size = SaveState(Buf,MAX_STASIZE);
|
||||
if(!Size) { free(Buf);return(0); }
|
||||
|
||||
/* Open new state file */
|
||||
F = fopen(Name,"wb");
|
||||
if(!F) { free(Buf);return(0); }
|
||||
|
||||
/* Prepare the header */
|
||||
J=StateID();
|
||||
Header[5] = RAMPages;
|
||||
Header[6] = VRAMPages;
|
||||
Header[7] = J&0x00FF;
|
||||
Header[8] = J>>8;
|
||||
|
||||
/* Write out the header and the data */
|
||||
if(F && (fwrite(Header,1,16,F)!=16)) { fclose(F);F=0; }
|
||||
if(F && (fwrite(Buf,1,Size,F)!=Size)) { fclose(F);F=0; }
|
||||
|
||||
/* If failed writing state, delete open file */
|
||||
if(F) fclose(F); else unlink(Name);
|
||||
|
||||
/* Done */
|
||||
free(Buf);
|
||||
return(!!F);
|
||||
}
|
||||
|
||||
/** LoadSTA() ************************************************/
|
||||
/** Load emulation state from a .STA file. Returns 1 on **/
|
||||
/** success, 0 on failure. **/
|
||||
/*************************************************************/
|
||||
int LoadSTA(const char *Name)
|
||||
{
|
||||
int Size,OldMode,OldRAMPages,OldVRAMPages;
|
||||
byte Header[16],*Buf;
|
||||
FILE *F;
|
||||
|
||||
/* Fail if no state file */
|
||||
if(!Name) return(0);
|
||||
|
||||
/* Open saved state file */
|
||||
if(!(F=fopen(Name,"rb"))) return(0);
|
||||
|
||||
/* Read and check the header */
|
||||
if(fread(Header,1,16,F)!=16) { fclose(F);return(0); }
|
||||
if(memcmp(Header,"STE\032\003",5)) { fclose(F);return(0); }
|
||||
if(Header[7]+Header[8]*256!=StateID()) { fclose(F);return(0); }
|
||||
if((Header[5]!=(RAMPages&0xFF))||(Header[6]!=(VRAMPages&0xFF)))
|
||||
{ fclose(F);return(0); }
|
||||
|
||||
/* Allocate temporary buffer */
|
||||
Buf = malloc(MAX_STASIZE);
|
||||
if(!Buf) { fclose(F);return(0); }
|
||||
|
||||
/* Save current configuration */
|
||||
OldMode = Mode;
|
||||
OldRAMPages = RAMPages;
|
||||
OldVRAMPages = VRAMPages;
|
||||
|
||||
/* Read state into temporary buffer, then load it */
|
||||
Size = fread(Buf,1,MAX_STASIZE,F);
|
||||
Size = Size>0? LoadState(Buf,Size):0;
|
||||
|
||||
/* If failed loading state, reset hardware */
|
||||
if(!Size) ResetMSX(OldMode,OldRAMPages,OldVRAMPages);
|
||||
|
||||
/* Done */
|
||||
free(Buf);
|
||||
fclose(F);
|
||||
return(!!Size);
|
||||
}
|
||||
|
||||
#endif /* STATE_H */
|
||||
Executable
+754
@@ -0,0 +1,754 @@
|
||||
0733cd627467a866846e15caf1770a5594eaf4cc 4
|
||||
da397e783d677d1a78fff222d9d6cb48b915dada 4
|
||||
ba07b1b585386f887d4c7e457210b3fce819709a 3
|
||||
dd1e87a16e5fb38d9d729ef7edc6da21146a99fe 3
|
||||
9c544426a02312b7148249ef20ae6e2021b45db4 3
|
||||
937464eb371c68add2236bcef91d24a8ce7c4ed1 2
|
||||
d76c7a5c2d28684f0d67114cc7b9707b296e68a2 4
|
||||
f9e8cc6e47d5632e3b28500197f8e9187295c52b 4
|
||||
91d3f1463dac4d5fed8d4ff34bed0d388c61f164 2
|
||||
5380e913d8dac23470446844cab21f6921101af8 5
|
||||
0d9c472cf7687b86f3fe2e5af6545a26a0efd5fc 5
|
||||
2639792df6f7c7cfaffc2616b0e1849f18897ace 5
|
||||
1e7ac21796642c3ccb66b0ef0f00ba4752428aca 5
|
||||
6bde4e6761286a2909858ecef04155e17072996e 4
|
||||
495876c504bdc4de24860ea15b25dda8f3b06c49 4
|
||||
db33011d006201b3bd3bbc4c7c952da2990f36e4 3
|
||||
72815a7213f899a454bcf76733834ba499d35cd8 5
|
||||
f0fee046198a076e664811f4e3a788d5f0b47183 2
|
||||
709fb35338f21897e275237cc4c5615d0a5c2753 4
|
||||
3739d841abfef971db76ba10915b19b9df833476 4
|
||||
908bb09ba2883c3ecdec96ed7e0211ccb05c5018 2
|
||||
2588b9ade775b93f03fd4b17fd3f78ba70b556d6 5
|
||||
482cd650220e6931f85ee8532c61dac561365e30 4
|
||||
16c3ced0fb2e360bc7c43d372a0a30eb6bd3963d 5
|
||||
855cabd1ad1abae3a9d26999d48c66de8096d7c5 5
|
||||
c1219e0735d31f1c41995795e58b04b97bf1b71a 2
|
||||
e32d7334ace26a570a08fe7c01ad01a2c08b1991 4
|
||||
10907d8e9845d8f9d8b5283affd7bb824963194f 4
|
||||
9e0312e72f30a20f556b64fe37dbbfe0d4471823 5
|
||||
a731d3d3b5badf33c7602febd32cc4e6ec98c646 3
|
||||
25b28cfe8d6d51f619d182c774f6ceb05b577eeb 5
|
||||
bb902e82a2bdda61101a9b3646462adecdd18c8d 7
|
||||
2418c0302abbce8b0f8556b63169c60a849f60ee 4
|
||||
6159cdfc79c68bf7dfe2653fc0b5893ae913c72b 4
|
||||
1833ffc252d43d3d8239e57d5ac2c015b4367988 3
|
||||
e6419519c2d3247ea395e4feaa494a2e23e469ce 4
|
||||
d82135a5e28b750c44995af116db890a15f6428a 4
|
||||
d5b164797bc969b55c1a6f4006a4535c3fb03cf0 3
|
||||
03b42b77b1a7412f1d7bd0998cf8f2f003f77d0a 3
|
||||
86fdfe9e26d6e77f41cbcb47e10e2f32e5518549 3
|
||||
7b94a728a5945a53d518c18994e1e09a09ec3c1b 4
|
||||
3df7c19f739d74d6efdfd8151343e5a55d4ac842 4
|
||||
d7b46aece68c924e09f07e3df45711f337d35d6a 4
|
||||
68691348a29ce59046f993e9abaf3c8651bdda3c 3
|
||||
6c1814c70d69a50ec60e39ef281f0b8cd7bf8598 4
|
||||
88cd90595fbb7dbabd73ac9c0985c0a013992dc6 4
|
||||
fcdbc5e15dd6b973e0f1112f4599dad985f48042 3
|
||||
2f0db48fbcf3444f52b9c7c76ba9c4bd38bc2a15 5
|
||||
a52c37c1f16ba13d3f39bb5403c82c0187cbff51 5
|
||||
f100a76117e95ab0335e89a901e47d844bbc0ab6 4
|
||||
52a9173b22c8a72376003764d73e07579dc2015d 2
|
||||
d1fbdbdf2e830139584d7dc796806aa3327720dd 5
|
||||
2799d221d5486d48226bbbd3941207e1fc7c985e 5
|
||||
d7109cf20a22558f923c833ff0b4e2311340acb1 5
|
||||
3880b064dcb851ca221ff67e435137a7cf1141f8 4
|
||||
6e5acdfb1c1610257a7aabf3d5aa858866dbcf2e 2
|
||||
ff72a1788d47f9876d9fabd720f6a289fb409090 2
|
||||
42fbb18722df3e34e5b0f935a2dc0ce0d85099e9 2
|
||||
8b252fe784692fc15290a04fa59848f609216f16 2
|
||||
f0be97ceca47b65b46c9518e6157b295f8c99c38 2
|
||||
e11afc03db4e1d03976d02796b29da9c65d4ff3d 4
|
||||
2bb837a9051277ba574d8351a9f91f9e57033074 4
|
||||
84566b5f37ab4f04a2e5b950c5beecbd27b88ea0 3
|
||||
21380bee0748625e9951a7a924016cc6cec46fb8 3
|
||||
2b10234debd2a6a9a02e0750ba6563768bc4a2f3 4
|
||||
dccdb2d18c70a94e48b3ec5e0cb986c5d708bbc9 3
|
||||
048737f995eecb1dd8dd341d750efd005267796f 4
|
||||
6868e7050d989d1ecbd13393ed360addefa4bcd3 4
|
||||
442a39b196f19a22fc7fb8f14bf17386a292b60e 3
|
||||
6d800787f5f5d63827b841aa29fe26ed89ea2cef 4
|
||||
75eb441c8298b7fd3982999f772e4c8b983ef17f 2
|
||||
59e35d24ab5f8e3b812ba4a1a4feb5be1ab269fe 2
|
||||
a553c3f204c105c23b227a1e5aeb290671ccdbeb 4
|
||||
90ea059c57f011a4fb33a558e868ee639882fe5e 3
|
||||
50422ba24fd158ca5f0b9728b8e41829048cfdfd 5
|
||||
a3fc0a55a91ed0041221f8da788d824d9d795913 3
|
||||
de95b99dffeab5c2b453778dbdc8723dc15cbfd7 3
|
||||
453eac7568d5d04c8cf7da86f2e8dc79777343da 4
|
||||
2bd311a4baf59cb85b839cca1f55b7462aa96952 3
|
||||
e8ab46785e75e19dac497c4a82ac2f5b37ac0580 5
|
||||
3425eea336140da03d7d7f09a94fd928d70e2212 5
|
||||
abe52920e895c148851649ecb9c029fdc41a275f 5
|
||||
2117a3375684fa3c5bedebced4d7c1019a1ccdca 5
|
||||
c3c67787e2a69e2fdc739d8d1542726ec4ee7c47 5
|
||||
89073c052b0fe29b6de077c8bdf5373474081edf 4
|
||||
b2cca92b7a51a43c310e58e011f3ede1e7125a96 5
|
||||
3f0a7b0cbaa3d4c3c6ce744708c68c89eff82289 7
|
||||
2de7891988a868f89f0c02fc84f762597d542d6f 7
|
||||
5f912637565932c2bd7c0d7b9be6ad3dc971f96f 7
|
||||
30b41d0e9b3c59e8826112c618206e12e187fb5d 4
|
||||
a4a75ed32c2af3c5f009661bb76be4f65e2e9a1f 7
|
||||
edd109e4b518c41eb30a2b6f2a492598c9a08008 7
|
||||
12b3c31f0fd10ff5823dcc8bf6dfeb785a8af2f7 7
|
||||
8a25afaed4bf87468ad7a0c5cf12375554d67741 4
|
||||
f416b424fb913ca067fe75279c924a20fac5c6a1 4
|
||||
7393f677e0fae5fc83071c6b74756117b7d75e2d 2
|
||||
0413bb3aeacb0c28429b8c85b42796dbe48bef6d 2
|
||||
40a0f35dccc7572ae53bcd4be70abfe477d49bc9 2
|
||||
5692e41b3a4c5e767cf290fd6c24942d0fd7b2e3 2
|
||||
b4788d85e67950177882ea4cf6a5fa3219f3fbd0 2
|
||||
520739caa1e0aac1b8eabc4305556aa75f3f5a3b 2
|
||||
c84ea9e7a02609c71ff75893cbb948fc1f1cf21c 2
|
||||
edc238c1eb254cbf90f1dfdc276ff7ccc93a940e 2
|
||||
d605458c96bbb538c4624deeeed3294ea489a61e 2
|
||||
7a4126934f9e68c34bf00dd3d9a9e753c05ee73f 5
|
||||
930df58762e7b5bcf2d362462f03335bad732398 5
|
||||
d2ccc4a8de5da21745209d0731671e8f3cbea515 5
|
||||
8b7e4bc408a8c715943bfa00069f2d517b39a748 5
|
||||
05767fec34beaaee390a86be496d98d2b27de641 5
|
||||
678efe599b8085bd27f9d3d42cfbbd7ca74ceb89 5
|
||||
91505fccdcc43230550d101967010bed27f9b573 3
|
||||
959a2ddefc9dc1a751cf30779b1aaac775f1612f 5
|
||||
50efb7040339632cf8bddbc1d3eaae1fb2e2188f 4
|
||||
e96888c96c3044ca7ce57dbdf1744df7469f7465 4
|
||||
e31ac6520e912c27ce96431a1dfb112bf71cb7b9 3
|
||||
f0e4168ea18188fca2581526c2503223b9a28581 3
|
||||
98748c364e7bff50cf073c1a421ebe5b5d8b7025 3
|
||||
910b156b562880ace789fb3f9b11848163c2df20 3
|
||||
f4a1e82c533677ed9923b11a0b970264d9ecf8ca 3
|
||||
30a7f3ea1612f20c0f62b1a121bc7d79ae515e89 3
|
||||
fd7b23a4f1c2058b966b5ddd52cf7ae44a0eebb0 4
|
||||
ab30cdeaacbdf14e6366d43d881338178fc665cb 2
|
||||
d63e20369f98487767810a0c57603bef6a2a07e5 2
|
||||
076c45e152598777cdb1ace82b11994018bfed83 2
|
||||
2ae97f3c8152f56695c3d3a2dedaa781bf0a15f1 2
|
||||
c66483cd0d83292e4f2b54a3e89bd96b8bf9abb2 2
|
||||
4127844955388f812e33437f618936dc98944c0a 2
|
||||
4c15375910461a7a34a2fd54c7f51e712f06bc69 2
|
||||
76666da5870d1901026e3dded3f22ce7a706689d 2
|
||||
d441ccfede2c089fbef54e20b90c0d4b513c5196 2
|
||||
06aa7bdc1d8f01e67d1a1736084384393074e613 2
|
||||
4c2f015685a17db7a8c3893e868e0a84a8dbf1e5 2
|
||||
6844758ff5c2c410115d4d7cf12498c42e931732 2
|
||||
87b7c80069a15fdb90b40dfed736fb8492104cd9 2
|
||||
d09d75c7f242a696931407458e717c9bdaadb7d9 5
|
||||
44b23a175d04ca21236a5fef18600b01b12aaf4d 4
|
||||
10758fb5d42b97a05b537db9b009bd644c153c93 4
|
||||
26a7b0118d158e9bd3ea947fbe68f57b54e0b847 5
|
||||
0dbc7defd96b71c1fe2d63cbc725f5e58aea2db0 7
|
||||
a18b1d49df954a3316ed215b6facfc1ec020ce13 7
|
||||
b40b178c6876cf3dedf4ae48262a5914c5f674fd 7
|
||||
b5bcbe2dfeaf7cc156c0d8bbf4fdcbe97b2007d4 2
|
||||
a3de07612da7986387a4f5c41bbbc7e3b244e077 5
|
||||
3626b5dd3188ec2a16e102d05c79f8f242fbd892 7
|
||||
da4b44c734029f60388b7cea4ab97c3d5c6a09e9 5
|
||||
a3537934a4d9dfbf27aca5aaf42e0f18e4975366 5
|
||||
b18d36cc60d0e3b325138bb98472b685cca89f90 5
|
||||
552a758f77a7c35969523dbaca74587f0b59eb2b 3
|
||||
74e9ea381e2fed07d989d1056002de5737125aaf 4
|
||||
217b21d10d80fe2d5d04636ee8c2f97f6edfe34a 4
|
||||
77f2d9d27724a7c71c688a598d34bd0c8a8e56d0 2
|
||||
c654b842cff7227d9e85fda25279259e837cee9e 2
|
||||
093d5ab39878ed4cdd42fb7c2a1502b7e65b17c0 2
|
||||
46f995308d736da235ba7f17841d8afeff403c99 2
|
||||
32cdc5c98915ba035865fb134e08ce5b75084099 2
|
||||
1aeae1180471e9a6e8e866993031b881a341f921 5
|
||||
6fefbe448674b6ea846d0c6b9c8a0d57a11aa410 5
|
||||
3b6200f88561a59ae5d2b3e94515b89cdb96044b 3
|
||||
842009e0f7d0e977e47be7a56fe60707f477ed93 3
|
||||
4180544158a57c99162269e33e4f2c77c9fce84e 5
|
||||
1c462c3629d43297a006ba9055b39a2dccba9f6c 4
|
||||
122f659250a0ae10ce0be0dde626dd3e384affa7 5
|
||||
a2ca7e6e216f8b450eb8db10a4120f0353275b6b 5
|
||||
46062d3393c49884f84c2dc437ff27854e9d2e49 5
|
||||
438bbb3367db4938b3d90fa9d2cfb1f08c072bb7 3
|
||||
f3306e6f25d111da21ce66db3404f5f48acb25a1 4
|
||||
cfd872d005b7bd4cdd6e06c4c0162191f0b0415d 2
|
||||
0f298581b85e838c1fbaa24273d292217f81662c 2
|
||||
ee60e88ae409ddd93d4259b79586dacb2e5ee372 4
|
||||
4d51d3c5036311392b173a576bc7d91dc9fed6cb 3
|
||||
d94327745bbb865a394e31e150a6c77263ee95da 3
|
||||
7a786959d8fc0b518b35341422f096dd6019468d 3
|
||||
e7273feaa30b676941b25061ef0631ec09ccdb7c 3
|
||||
7d07fdf58c7a86d9f93af35a35acf2d7ded02ff1 3
|
||||
0c425d8fc1ad36c9b8e248e477b1796cd62d9bed 3
|
||||
fb053becf87f12e196e00b3e153ec8029ebf1ff8 3
|
||||
240e15fb5d918aa821f226002772dc800d9f20a4 4
|
||||
d33508c89656b18063893cadb74573e0b656792d 4
|
||||
f999e0187023413d839a67337d0595e150b2398f 4
|
||||
1ff0afe393f89b6517025dc39a282c11c7da87ca 4
|
||||
25f5adeca8a2ddb754d25eb18cff0d84e5b003bc 3
|
||||
3b6f140c99cba5bfa510200df49d1e573d687e4d 3
|
||||
4323eb37b9a795be32a2b64824fc4acd7afe4e9d 3
|
||||
d0dfc1927461d9473d0ed471375dcedddba42279 3
|
||||
8c609b8bee4245a1bb81e37d888ac5efb66533cf 3
|
||||
64321138e03337d0e6178ac30bb98e6623c640ba 5
|
||||
63d4e39c59f24f880809caa534d7a46ae83f4c9f 5
|
||||
728340e95ad58ab989a59f61317a45ab1f6b0bdc 2
|
||||
ee533b8e4bdd6cdf2c273f7c80753cf8db60f545 3
|
||||
f2eef7402d2e6e7f7c15a1f3d8bd251603eabf12 2
|
||||
0099492bd11dfa3ddf87af3aeb4c92b29f78bd82 4
|
||||
fe74b4df9698a61dffd3ac88f47619675514ba1c 6
|
||||
5c00f9e3a48411e08fac89b1dfdd2a6e95853919 6
|
||||
f02281aa13cb34d2f10add301529b95adff7f768 6
|
||||
720b629e2e22e0af15b482b154a1473e8ab6627c 2
|
||||
0a7bed652592ed6325acd037f1f5bbbd1d31b239 4
|
||||
2cea9cdd501d77f2b6bd78ae2ae9a63aba64cfed 4
|
||||
6a98d5787dd0e76f04283ce0aec55d45ba81565d 3
|
||||
598eb258cbe532e98b4a3c8d87ecd9536d09ce56 3
|
||||
e4401a78869ffa879a55f239e5da4990cb6797a6 2
|
||||
0442dd29ea0f7b78c9cd5849ec7ef5bb21ec0bf5 5
|
||||
0f2c5a7c6cc9ff591c911e4f3f204e425bd3cf50 7
|
||||
079bacc9708f711af90310f3e08f2abafa8fc919 7
|
||||
e348e62e3c4c02d87ff2aa4d55ddebb60c3ea507 7
|
||||
145552b3f62885efcfe7484008fa4cebe2feae84 7
|
||||
9c5c1c40ec30c34b1b436cf8cc494c0b509e81fc 5
|
||||
3243a5cc562451de527917e9ca85657286b2852f 5
|
||||
f7dd6841d280cbffa9f0f2da7af3549f23270ddb 4
|
||||
db7e4c8dc56a0e8e0e3df08b14a65030738d5ac4 2
|
||||
7dc7f7e3966943280f34836656a7d1bd3ace67cd 4
|
||||
0cb11c766bd357d203879bd6bee041a4690cc3df 5
|
||||
e92baa5fdfb2715e68700024d964098ef35704d9 5
|
||||
98b7a6ac44b82ccfc45eb51595e2905adabac1c7 5
|
||||
cbe6c0db6201f8ac09310c788adc634873251164 3
|
||||
cf344e0f58fd918c089c4d4575caec8843944ff6 5
|
||||
bf0014ca7dd0815b2385a778c5328ae63c692229 2
|
||||
abeccfe49a6874702d65eb4d06a970d8fcf55123 2
|
||||
7abf89652396a648a84ae06e6dabc09735a75798 4
|
||||
176ec8e65a9fdbf59edc245b9e8388cc94195db9 4
|
||||
7341efc039394ec159feebcfaa9d4a61ebf08a18 3
|
||||
0ec71916791e05d207d7fe0a461a79a76eab52c5 3
|
||||
1c238009e77c5536d0059631954c2c4a52527283 2
|
||||
ca45da2f9cd8edf4ab04ffd542b9c60ef6a9a254 2
|
||||
aa6055ba0e433aa9c93df4444783cacb9628a7e2 2
|
||||
7b8015f919c8dd95db683f3f3d0799cf7ef1bc22 2
|
||||
9f2fb5f31c2bcff949e08449f197b0c31bdebe50 2
|
||||
b493dd7d082e25fc40ad1cccc364e1945590a2f9 2
|
||||
3ff276af654c7dc712abed79d9123317ce79b4e4 2
|
||||
65160f0d59068dbbf76b11bc79e17a9369c8dcee 2
|
||||
72783ba5a0b9f33b4573952a1c721fc5d5025fd5 4
|
||||
168d59fca3170f56858f39d0b53067c0c0d414a8 2
|
||||
473bc0ea85ed1b218974796d819416e711ac193f 4
|
||||
5d55fc272184d160af6318855c9d2f728b3f25c0 3
|
||||
8557dcdb4cf1e15180d17acc8e6d515bf7bf7e7c 4
|
||||
7752b6624fb80d9499aaad28dd5776ec74565576 4
|
||||
c2f4df1bd91f7dee1536774b9d7089086b9bf835 4
|
||||
ec1bb5c36952b12e6c0805e9a8d5bf31c20a68c4 4
|
||||
22f9b0238ff48840fb7d45ac93a7f15495393920 3
|
||||
4b138e041947990309c228890914689908d46685 3
|
||||
76b7a5e75d5091f0482746e5a0c0a71de07ddf83 4
|
||||
ce3f9356eaa5fd6c1b5ff1ade244ebd9130f1ceb 4
|
||||
e6de8bbd60123444de2a90928853985ceb0b4cbf 7
|
||||
66802dd98370da809250367365df234f9a6422b7 5
|
||||
0b02dda5316a318a7f75a811aa54200ddd7abc30 4
|
||||
7c066cb763f7a4fec0474b5a09e3ef43bbf9248b 4
|
||||
55adf3b4576b370dd2680d80c333ebde 4
|
||||
2220363ae56ef707ab2471fcdb36f4816ad1d32c 2
|
||||
75d3b72d9ceeaa55c76223d935629a30ae4124d6 2
|
||||
ee66334fbac1c926ed05c1c3f38df3920f501fe6 2
|
||||
2111cec4b5ea698d772bb80664f6be690b47391c 2
|
||||
04e4eb1cae7cf379977d238b74d727bb929c8d23 2
|
||||
f1de76dfcd8c4e354a8a8058a76191167fd112e3 2
|
||||
9ce36aeaa93f969b6c2ea91598b0b014 2
|
||||
240a23b63e901b988951dda1ded561c281ccbbc1 2
|
||||
8c218c317e1e213e1c5e9439870929009d645a47 4
|
||||
390fb09a9d944d1d17c328ae138325751d1b4203 2
|
||||
5b25d93259a358f2064adc44f6382c91c9394861 4
|
||||
c95f8edb24edca9f5d38c26d0e8a34c6b61efb0c 5
|
||||
ac109dac24df4dae813ca5d9f0938cc48a162bb1 5
|
||||
16c692a2c9babfdadd8408d2f0f8fae3a8d96fd5 4
|
||||
4e864cc0045c85c4f5c5c0efcdf26340a178686a 2
|
||||
37bd4680a36c3a1a078e2bc47b631d858d9296b8 7
|
||||
9b6cb224f2a7a4af69221f1280d3344a5c88450e 7
|
||||
9c886fff02779267041efe45dadefc5fd7f4b9a2 7
|
||||
0b379610cb7085005a56b24a0890b79dd5a7e817 7
|
||||
441dacb74a47ca4b7d1ce47300d182bc7424ffac 2
|
||||
74ae85d44cb8ef1bae428c90200cb74be6d56d3a 4
|
||||
94d7a756e199457ea9958c8f5d6860c9bf334126 2
|
||||
9a611007b58a001639676728614ffea61cd5ff85 2
|
||||
b7f36450d1ac76834046fd582d6e77a6d3881a8c 2
|
||||
c960c1b895557ef1b336035029d5c6d553c64085 2
|
||||
46c98a3143f5a80b2090311a770f9b73000881c0 5
|
||||
f6e0dff9f8674383a866902fddb72a280d331d9d 3
|
||||
64c49fdabbdd5e13c4310b03a183ea1a018154a4 4
|
||||
0d76a069726fec7326541f75b809b8b72148ed3a 4
|
||||
3b1fc45b04bd03f21d5b88330a0c5d16a9bd2d65 4
|
||||
a676173780dc3ef4523ff3123fdf179279d22932 2
|
||||
0d459788b6c464b50cbc2436e67a2cef248e0c4a 2
|
||||
a1830ad66feb55f471d52210c6f07937f38238fe 2
|
||||
c19f67882b2586c4ba577ffc5d04197e757e19a5 2
|
||||
655b15e8fd81866492bcf2b1d6609211b30efce1 2
|
||||
d30c17109fa1c4a81e39dca57b79464b0aa0b7c2 2
|
||||
5261006ca4245653f5153074dfcc8ca27315bb59 2
|
||||
df15daf1e68e9c8cd95c4431803d86fe6c2f985e 2
|
||||
14ff6fe464362c6b7dbb47b2ecda3a8c5f05ef79 4
|
||||
3f741ba2ab08c5e9fb658882b36b8e3d01682f58 4
|
||||
96e2a7163c755fbea77abfd9d09a798687a5a993 3
|
||||
7ad40ae512bbf4ba688467ba23e16354b8421d0a 3
|
||||
fd0e46e4aef2d9713d20b51d2ba57d55bde7dcee 2
|
||||
84831671935bf80c250aff223a99684669a0ce72 2
|
||||
1ec94d049fcbf59c5493d5de76bdfb891d24249e 2
|
||||
54a1d356fd7bc6098f5c3d94f9d8bfcc2c6d5935 2
|
||||
0b3f5dbdbf5636e22b3a6bc12eeb4ac64b0501e5 2
|
||||
3b4143e5769d6235bca8977b41241295493eaf5e 2
|
||||
2b255c3e5615b2f5e2365419a35e4115a060e93c 4
|
||||
7a0a1c5570a3361ad75406eea07c93fdad9fde02 3
|
||||
e6ba7a6ecda80a1c844542be0b2a44a4a33dc113 3
|
||||
e7351ef9606bd6d5f38acb7c17aed8a00170b85d 4
|
||||
6715aea31525869220d7acb638b6a432875e85a1 4
|
||||
5a12439f74ca5d1c2664f01ff6a8302d3ce907a8 4
|
||||
3caeec19423a960d98e4719b301a3d276339e5ae 4
|
||||
d554710317482127f2e1597e91e72be5ee0726ce 4
|
||||
fe39af5eb457bba8c5b96b5b500120cfc05c265e 2
|
||||
0809b47cf385328c3faa6a80f8378fa5c6690829 2
|
||||
1d129bde09c9db2433b334d36762704de94983ba 3
|
||||
72afbebb12098ade1ec26dcd65890b60b2c705d0 2
|
||||
65da0e5c5de057a1ed836ec19b1f07e10f4b738f 4
|
||||
dacc9ed6a80fb15c3e82c4081c07211e033ba820 3
|
||||
a3e8e076b9c8d4060082233a2f16184cf4911a85 3
|
||||
9bafce699964f4aabc6b60c71a71c9ff5b0cc82d 4
|
||||
14faf5da6ab76de0b62f1ede91e27d46b9db77a2 4
|
||||
5d65a308bb9ec8c4b4ce334b18d699b1f53227ef 3
|
||||
2dfbca8f5cc3a9e9d151382ebe0da410f5393eaf 4
|
||||
c69165e84e8350a6726901f2ab6e4688f38f03fc 3
|
||||
244399d67d7851f3daa9bb87a14f5b8ef6d8c160 3
|
||||
cf6fe49b28fcf81511f39fdf68f37af82bd724c0 3
|
||||
81b85b1152a59bb10d0e0118f80f0a4ed363c785 3
|
||||
0d2f86dbb70f4b4a4e4dc1bc95df232f48856037 7
|
||||
cf088b4eefe7f426e438dd2fe7a3433140abba52 4
|
||||
16351e6a7d7fc38c23b54ee15ac6f0275621ba96 4
|
||||
a8ac24a702d2c850c7a15b5196893817b0c93123 4
|
||||
ebceb3de22e4c0444a969d83ee487f8ee34204e4 5
|
||||
16f06109c57de5a39fbe150de9c25754483ee9fb 4
|
||||
fd1eecd9c89f47741276433b99b75eca2930b58d 2
|
||||
d147f2cac0600527ce49bfffc865c54eb783e5e5 5
|
||||
500d7a1d81621adf8c6914c6a42d65aa44ad4588 2
|
||||
bfe8046f8ccc6d6016d7752c04f0654420ef81e7 5
|
||||
22d8ac99ef692675210f101eb4e688cde9b2d7f5 2
|
||||
b550757c8f5b55dbde16b4a7888f10999f01acfd 3
|
||||
4340a2580c949d498d2c8e71699fff860214e9ea 5
|
||||
47de7524c32e72e849daee4d7f3e6cf393e3b7dc 4
|
||||
b188980c998d1dfb5dfbc21837ffbbb5affdbb3c 4
|
||||
badcb43e490e3713bf291e83cff204e1c57ecdfe 4
|
||||
f50d0c66b08c47b59925952276243e2008668185 4
|
||||
818d91505ad39bba2eaf7f4857c7d41e95fcb233 4
|
||||
e19cfcbe92ec3682bee869dfad5f6b4058b1f2ce 4
|
||||
97e173dac64dbde7d6a60de7606cba0c860813db 4
|
||||
b6a5552effcee708b665fa74e5ce7b0fa2541c03 3
|
||||
d7e85888117188a6d6f7914e9649fc4821c594a2 3
|
||||
fa6c059e14092d023b1f9f2df28e482f966287db 4
|
||||
d53e0c8bcd98820afe820f756af35cc97911bfe4 3
|
||||
632bdb164acab52ee715c7eefed60e0b1ae629e0 3
|
||||
d0706fd10e418eba2929d515cc0994f49376a63f 3
|
||||
d3d411c8b7891aef9c59cbc20bb4fa3ff0ca03ea 3
|
||||
898bda19f882c6d1dffdb2173db84a97dc21f7d6 3
|
||||
bae8548faded657cca06c2b02a59e00cf1e55484 3
|
||||
4f35f676d2f382078078343921374c2889d06e11 3
|
||||
05a531043d13ba261b0db37e4ef8b257986ce05f 3
|
||||
ad3d8fc2201a245e352875918e421b42764e4148 4
|
||||
c9135b1e451193bd4c06d8143eaca934cc89fe05 4
|
||||
d9826cb2044ed0224124f2f31d0bdc1fb840d81c 4
|
||||
2fc15ef2c728a2472cfa3a34053e07f821dc18d4 3
|
||||
66508bbdc3b133b9a69ea96789bc134eea46796a 5
|
||||
5fd07ed5b7c0492d42ed91a54a0fe80ce6e4e40d 5
|
||||
1f17e46190635a3214057d33ad4a768939d5a071 5
|
||||
cb544661b6da6a35c20bfe503974f2b79a3c4550 4
|
||||
5ef7d03b138a2023f6def241b671c666f97ed83b 3
|
||||
eb58b57f468e12c4300d3a88337e6c45e532c7d3 3
|
||||
5460a88c25386b1b950b57fc1325fd75587cc825 3
|
||||
b58e77f819dfbde72845801cff4b4e0a2f20ef5f 3
|
||||
e78511a2b8cca37a96aa396c938863c92a20c797 3
|
||||
43084db72dd13112450a7af4b513e13e9266defb 3
|
||||
aa13b346e11644f8426fc546b359bc6fd7c6b357 3
|
||||
90b57b582675360916ad68ba65e9284926d93f4a 3
|
||||
12f6f31f495bfb384c9ca9067bfbf8f98af6adf9 5
|
||||
fda4422b86daa233fa4e6104e45305e7cb383053 5
|
||||
11b712633bd0e44e8d59ceba5a2d6b1c20a43ef9 5
|
||||
2761df1ff6bf826e00dbd4f9a346aa145e91c6c6 5
|
||||
be2d023f5f1ee4cfbdc712c8ef9eda9d07278d88 5
|
||||
f4f7c789dd320192fd544c666ceab720c7f3a747 5
|
||||
4b506234dfd3b6aa1c315b40cd8ddca024dd15c9 3
|
||||
030557706d72199acf17df4480f6b1a8ff798d1e 3
|
||||
54b05b9c064232d75299fd31b53335f530c20aea 3
|
||||
937f8d412e9810c8aeb9d92182cd3b007ace30d2 3
|
||||
07793d57b00ad8927a3c1f0b1ed61c606441dbbb 4
|
||||
1545566bd7decb1612009daa2daa71758fa6e4a1 4
|
||||
4a8eed643993b86e71ea46098a580ec15038cbba 4
|
||||
55183b7b7df66950dbb65ef1065d7d987e0fdf5a 5
|
||||
a8186cd3ef78662c87665df52026ecbae4866bfd 5
|
||||
ae3c3c2c022f566d2e790aba193470d5826f36cf 5
|
||||
875a262be44a27a8357f170080fb8466c9599b62 5
|
||||
1064aa5c8a884dddc0a27147ca70881e04988725 5
|
||||
e8e416977f5dae3635362c513bba004ea89a0bf4 5
|
||||
9c89215dd36eded769691708eb8c82dec1ce5109 5
|
||||
1642891b693df616f27431299352e1d7750ac94b 4
|
||||
452deac5b3341437e70c5b2726aa26cc1d074fba 4
|
||||
9e790499af6916f82809e35d68cc159efe580f99 3
|
||||
c843b8b0e5ed98d3bae68e701fb709ea178ed968 3
|
||||
b210047af5ccc352cc044bf6c1419552223bf8dc 3
|
||||
c4a919f31d20008b5d6540aa5d2be59aa4cef5cf 4
|
||||
1aee947b1ad6d478c0def550868a3851c2910809 4
|
||||
a3fbf7c2392c1f97d3a0946a5d1654bf4f7d9b0a 3
|
||||
e89fc7437d8f9aed1640689a32ebbf047699b147 4
|
||||
ae8172bcf76adfa3d401467cbc89cbec2db86ee2 4
|
||||
5d82713f36e9395092f16663084fbc85f05c664a 4
|
||||
a8059dc1820b461418713acf2af14f3a25734bd3 4
|
||||
e839f3ac7d52c427ecc011d01e6e241f88ca850c 4
|
||||
f57b46154cf0711e3f5218e00f67c375d95d1d5d 4
|
||||
a8eeac428a5992a2390b1827db1358f4c733e200 3
|
||||
bd1435a19ba895149fa5b88425316171d165c323 3
|
||||
efdf63f01293251dc593163a42f31556fd042282 4
|
||||
4edb5ed12c1b9bc7efa571ca67ffc732f53d3a4a 3
|
||||
e58c1dd46067e2abaaf3ee6a70a7e5541a32017e 3
|
||||
32210a9cbbb51e30ff59ed44bf32e628fdf6c42c 3
|
||||
6fd90e7573abdb5a7bd6e4e8dc44db80fc163e30 4
|
||||
bf96a360083c5c26430940546827e91a69ade63e 4
|
||||
2e388978f765bc5fe1fa9a42e1f059de5053721d 3
|
||||
8a65786d9c6b2fe7c1643c27316d6cbb35fbfd24 3
|
||||
022a53d79bb72c736a5fdad6d82434a98f33e6e7 4
|
||||
599c824ec92be0369accaaaf31340df6f471f202 4
|
||||
e73946f1f26589d77926276ca4f9dbee60c53fde 4
|
||||
c5edd1c74e72ddaeba1027da1e848e2c4fda94f5 4
|
||||
a40674b5e0ba449078cbb07406edfd2627306122 3
|
||||
d66068f5a8b6cad09ed57893ceb0f3dd37ce8715 3
|
||||
e36e16acfdfa76fa72b218da2bebc668db39d21e 5
|
||||
1302d258c952e93666ecec12429d6d2c2f841f43 4
|
||||
90003c78975d00b1e5612fd00dffabb70d616ecd 2
|
||||
cc46a737acd729b2839ecd237d38b4a63cfb16cb 2
|
||||
7964ba4c3c27b6a32d397157fd38dd1dc2f1e543 2
|
||||
bc06bd3d6f138da8f5d38b47e459b4d1942e49e4 2
|
||||
424320762bcbbb6081b1e186e21accf758aeb935 2
|
||||
a21adba681956ec35816af673a9d4f6c7743253a 4
|
||||
2a4aef32db28c059c30f5f972f1c09708ef6ce62 7
|
||||
10c38f91d8f5db2438414ea58f26dcac78352088 5
|
||||
3f072673752badfbd234d6005ddad60a494a9438 4
|
||||
d4da7236bd09d735dcb92127c73e43b3ca94dd7f 4
|
||||
3bb2f9f4be38b5b08da03ee190c39caec30e2f08 4
|
||||
fc9adbd816109f7705f342c01f168bb09ca4b2ff 4
|
||||
35c02d8d590d92053f083b0c0c897277a5375af6 4
|
||||
772ad4eabbf0941a9b4655f5615f2a5cf22246b1 4
|
||||
1ba6b699b4e34c23ee60db4e58e1265dc03f0b50 4
|
||||
87a7fa43602f74c47151e79f1aaf7f641331ba51 4
|
||||
ecbf33a376a7a108176f8d1009d042e01519241c 4
|
||||
e0a8aff980ed84ec12acbf63b40cf9895997faf3 4
|
||||
81befaa45ee3f1196b0e1ea657b0161495601a87 3
|
||||
6030005c4401b3cbcb09f802cd48f5c1c585303b 3
|
||||
5577e483caca553cfbfc0cba26f3ab2444569f81 4
|
||||
7e9a9ce7c18206b325830e9cdcbb27179118de96 3
|
||||
7c3aa9cca2f1f6e81ae9d24b3a3c675f08a203ea 3
|
||||
27f9144fb24b434f7a75737aa694283084782766 3
|
||||
05280f0a26ac5c42ab63b80a487bb909683e7461 4
|
||||
77fcce7b7c9c915fb0adff059141d4d4307f5a22 4
|
||||
028eb2de64ee129f9403d114b3059e8b62fef6c2 4
|
||||
b63fc17c1d004ca4d7f3b1ef8962210a779ca665 5
|
||||
23f3e1b597bee95375f380638340995b55232e7c 3
|
||||
3f87c3413c8cc2a25e1f64cfdcd01155a13711f0 4
|
||||
fa2d5f56273a0faa5b39096448f82998655de60d 3
|
||||
6d7a8ea1b283ecc1cc94c359e5f053a6e82ab3f5 4
|
||||
b11c0ded529af18c29ec46b9e0a795ed0405e7ec 4
|
||||
af3524caccd33ccb7a5b42b1ce4314d055e01672 4
|
||||
d0bbf730725806384756f5306ceccd91dc01d975 3
|
||||
bd70b00ccb8fafca883c7160585e9c5920cca58f 5
|
||||
a6d285e515ad1e2c15b4352d9b699ebe060b1dba 5
|
||||
cd8ee800822ff0cd295621faafafc73be4bacad0 4
|
||||
caeca37113c56e696d7053d90f5f9f3e02de8ad1 4
|
||||
98f6769741a1c9df4fd203ed19d70b283c94e41a 3
|
||||
475c3af7495922759a5f424d2e22d7e4073d5992 7
|
||||
39bc111c953bdf25683db7ff4c0bad79b5c49958 4
|
||||
f12ad34dc3b4279da0fc7094f3d50d6b8bb517dc 4
|
||||
06132ead4caadb2395302381bf72c60831500dce 4
|
||||
f04f5c6936301eed31a79c23571f8fc497864dbb 3
|
||||
b45172e4628f68c32cd13c73cf17c4dd1bed1bb2 3
|
||||
18eada2178fc1a89895087aa513305d1ba73c926 3
|
||||
924fcf87b3747dae06e621975903ee73c42016f2 4
|
||||
6d72a04ef018fa1fa3708c8b5ed3333b2c5e8ead 4
|
||||
c74c0a9b973f4dbfc132b60fe4d666600ae12552 3
|
||||
d78d763e72e23418f31dc3ce91deea1e8ee10490 4
|
||||
66620207ca6c21bcbae8f868bb55532e72e521a6 3
|
||||
31dbd1c08659c649c49da8d2e6b80328cb6b59e8 3
|
||||
970e26f3c2c085e39267115991add6ccc6e9ff80 5
|
||||
a58ca651f4c12bf07cf3840d5e37b534f5fc075e 5
|
||||
1f39c472f1e02511fa7eaaf8ed9fcce4d45861b9 5
|
||||
df10b3c8470acebbc445f7c24a50b4f24db0187d 5
|
||||
cdeadd6cf7bf5b53aa7d901446b0ce586542c580 4
|
||||
8cbfd94324f297a418e7eec6920dfead7b9bed08 4
|
||||
32dd4df2b39461c0694f6bb84de0709478a69d31 5
|
||||
1f3f586255dd49b0f912bf41e07e88fe3eb3fb61 4
|
||||
273a3dab994b5b9c975fd12711dd19e0c6367caa 4
|
||||
fd71df03b0e9f3caf701ecfc6d5232060cab3b13 3
|
||||
f5009c44ba1e72b64e29fc734741d518b4167aea 3
|
||||
55bad6c00e6a676efc7ff349fa1b5422d624f5ef 3
|
||||
f924980511d2ea191481c1e4ff5ab7adc3f082ab 3
|
||||
02cfc41132d518e2b9fc632ec6ad00656bd9ec92 3
|
||||
f4da2be2ee712ba2e7cccf56fcd15483fe0023ed 5
|
||||
4b872dac11a720e2b9e86f22df1e2214c1059281 3
|
||||
1f26dfa026b116c80c951a995633b4c2f7fa033d 4
|
||||
2a1c91bcc9b1b621773232061d74b7098420f1d4 4
|
||||
4690b2f6ce28e55d56ab185c573fc27a9b414468 4
|
||||
b8f4ee146c3cdb8f506371d001e6398ecda85251 2
|
||||
e22a6317747903475095008d0d5ad9427ddb34af 2
|
||||
ad995ede603a28c72dad06c245fc7d4dad85d230 2
|
||||
d89922ed43ea4fc0b87d7e5baef3f072bb566849 2
|
||||
93b07e3cd5ae2f00b36824a74f83a3ef0d65d0d5 2
|
||||
dbed87a53c604f7140577d6707ca0fc8490463a6 2
|
||||
faa5f0bf79fde9ce74b91a7091d203771cae8499 2
|
||||
74d1c7f66242335c736da29413037bd23384efaa 7
|
||||
8a4bcf0f38c9f243443a4d4865278f695bd83dc8 7
|
||||
bb99fe7702733ab0f9e8856e91f5ddcb55d30b5f 5
|
||||
b74f759ba3837968a04e9b64321b47cf087e76ff 4
|
||||
920f141db0d42952130855ac1dce446c327e7d9c 5
|
||||
14403ca71d287084569e6c2f4124d2712c665219 4
|
||||
90722d413913ab18462aa741f85b820e751bb50f 3
|
||||
c34a1c225d1a5fc41a998e23d1209b59b3b759bb 3
|
||||
f5e199a5b39bad10256d8e963f0da272ad359517 3
|
||||
4376342bf42334d98dbd3e35ef35460974269c58 3
|
||||
25022c4f5cfc805e93026fd5fda781e9a1807474 7
|
||||
3ff54468a5acf1ad44e85bdc993044aaa3165a63 7
|
||||
d08d4e2a8d92c01551ff012a71a1f3e57fe2d09c 7
|
||||
751571d21457d89e5c52c45657bfe9a617ae8e14 7
|
||||
32151ddc4303290c09889bf8107493dd34296043 4
|
||||
4ee3e785e6949bd535804a32c6a1a31eeef30031 3
|
||||
ead699582641d103a94775a08121ecc336b99eae 4
|
||||
6e1d2d5b0688860b0a04d53fe9e5e3939dfba547 4
|
||||
13fbb273a95481330d33c9edc4263e30ccf1774d 4
|
||||
45760316a4ebc74ddd55ee163c5aeaaafe965d2c 4
|
||||
d723f2eb1c887db5448fd56be5e7c57e60d88e63 3
|
||||
612c18616bc800d9eb69b9da3cd29eca31f50c1c 3
|
||||
300f20adde3941ab10eb158db48250e8e856a911 3
|
||||
357c0c2e9b3b2970c587c96f86a6b7272160f54a 3
|
||||
875bbb27f6a54e5d123dc8a6df4bf46f97c23a57 3
|
||||
fed52c0455ce1e7cef80cd144c3d0ef3636134e5 3
|
||||
7e5024e6e6aecd05ec6c885786a4aac287ed110b 3
|
||||
3837d3a72498caa070866d947956a2e30fb94fbe 5
|
||||
facb967717c21fed9b375481908aa337b3361c45 5
|
||||
14537ad9a551245261776bf9b64068fe4921ad47 5
|
||||
f182d4785e3eed00292f7ff4795c9dcc6c990a0a 4
|
||||
5d2062ecc7176ca2b100724c2a17f877878d721d 3
|
||||
219e9acc2c023c25a8bbe9fb7d1764ffcff66034 4
|
||||
e065238580b9e118b6c9e789d797cdd99e0a1c69 5
|
||||
25b80aa670e7fdc84b51628b6dbe930eb234beb7 5
|
||||
fe8aae62fdec28631d8f7b6659dd95135c1bcbb7 5
|
||||
0cc6c30c6918fcf780e57d40f58a4cf2a82225cd 7
|
||||
97f2cc1cd4c51dc20b86cd190016b8f0c006a968 7
|
||||
6420d61002da325403fcb6f41afb1d348eeba3b4 7
|
||||
9afdee40e7b243f99cc50dd1ad710ab0928dd820 4
|
||||
0eb3a48a8ab90826726f0c06daadf4bf13390758 5
|
||||
d78293133b075f48c9dc5c4cf0c4a985ae964b08 5
|
||||
f4dba5ba267b5dd1a35eb74a6ec4fd4d5ca9a1b4 5
|
||||
a0c486d0f25a3dc586717d5d3e1f5a46d36735fc 5
|
||||
6dd28797f9d1fe7cc041077ebe77d08f2ccc0937 4
|
||||
11f1b9fda9a44f59a6de479aebc18fbc6347f5a7 4
|
||||
38a103e540eb5fbe2627fab2991bda08092635e0 4
|
||||
6d3008b97b48d99522e45056f52ed944e3d8e208 3
|
||||
dcc1ecdd0e3a2a33b994e472ea367a1637cc3799 3
|
||||
99330820cf8aef8bb34d56a666accb4b1ca90e30 4
|
||||
ecb538238fc7c5e374d723f4d6120d1b2ef5d80e 4
|
||||
fe4bd35e87dd50fddd255172129b9bec38691188 3
|
||||
c6d2aa3e7303e0e2244256bfcfc113bafe2d6b59 3
|
||||
206b2a47f437ba9dfc85f6d01c9e2c18 3
|
||||
e178917d1974ac85fd58cb93b936eb9a6f44ba0d 3
|
||||
2b4c386a56dddd2a3354bdf1a0041d3faa0ccc72 3
|
||||
e178917d1974ac85fd58cb93b936eb9a6f44ba0d 3
|
||||
bd9852ea114e8b8ff781115d1d6e6da6f8dfafff 3
|
||||
65a5bda34d1e1b22cfa697e4e7fdf1829cf2238d 3
|
||||
502d7cf7bc2595af6f83bb2b95baa4db5b0f6a4d 3
|
||||
de2349227d765db73cdc44efc6338f6b530eb133 3
|
||||
a5963fa6c95fbe34482862b0f7221b7766e3a194 3
|
||||
2e0436303648097e8e936c5467574aff5e3f1517 2
|
||||
f25628e474035e6bf0440b274c5df04f94c49fb8 4
|
||||
5ec8811254dc762c6852289a08acf22954404f0d 2
|
||||
b5acea41aeabb5daa4183953f800d47db0c39fb5 2
|
||||
2e2543ac99193f76b4f35463142294c016f0cf3d 4
|
||||
f90064fe4ffed170f9e9c79196aa0b17e0bbd86b 2
|
||||
523330d609ca0e527f3e28a078635b3d28489ec9 5
|
||||
f9486dd810d6321bad4bc9d7703a67d630167f98 4
|
||||
22f5998b4de47bf2ccc077d5881ac448e6b0484d 7
|
||||
e003d57d2102e8fdf5d9eea7bd78a3cf67d75778 4
|
||||
51e4231e245ffd733590e3205fa3ffea92ad509f 4
|
||||
68158290666f4d7ac1ada40d674a1160c162b193 4
|
||||
d57fc4121d716182a091bb53c666b46c10142668 4
|
||||
13c59dd8f7320856b15c834038af3c846db33e4e 3
|
||||
db1513dff6dd456fc973286816129ace81bcdfdd 5
|
||||
4c44939a95a20d701f60830499254e5dabedeeaa 4
|
||||
a53feafa4c70d2378998f0dcb837905e5070c541 4
|
||||
ee501fde62b25ddd1c82798ee1b233b8813e717b 4
|
||||
4fe1d66e8f3cbd5ecd9b22b6aea2b37a604f2492 3
|
||||
55fb4e3d3a762b613b635ee9745d92f0f3711272 4
|
||||
de0eb1c46c47924879e2a49f9eafba0ab344fe5f 5
|
||||
e6c01bd90cf0b2793282fc53e9a3150a6d7804c5 5
|
||||
c5e3845c74da6aea2cb68ccd765e4f606f10b5b6 5
|
||||
e3b9241291b5f19ab239726360258a31e02565a3 7
|
||||
845b9263d75d89ef02c23fd05cccc13db5d512ea 4
|
||||
495eb918ced94ef47885df40ceceef8b56e96691 4
|
||||
31b8b69de88d84aabdb762af1adeac815723562c 4
|
||||
5ff1254dccd5dde58d3475a468178738d6260b05 3
|
||||
a52021f1b257c7c35d626d5d642134091c45e4f4 3
|
||||
7d685547c2a4b92fa62e00854e4a9689d495f93d 3
|
||||
b656bd19df58fc1ba4628342b87beeec5948e0b3 3
|
||||
7b959c609deaf67d29e3f79f55a03f53961f129e 3
|
||||
c461efa942e1a3a1e580f9d04bf8d15c5e834f8b 3
|
||||
804be21493a151a0be2075e86c94759dd96f0bf7 3
|
||||
8dfe236a6a5734824035725a4f513b8fd31b310a 3
|
||||
aa881a2936f368ab887c296b837a8f7f553a3fb2 3
|
||||
847841ad88ff2eff6602f03b7231cd1e03f89ffc 3
|
||||
8449cdf161babec85508c35c8ca64a5c1fd7671d 3
|
||||
1417f9e8ca99deb3b422c5968fdfa03cfa633ec6 3
|
||||
65040fb1e9bc4b2d027d7d81e44be30e7620e368 3
|
||||
356a936987e62967597ec64a0d35a1e8ad1aa20b 4
|
||||
e7b8574a42b1029539632ce0f5161b1c38d5e95f 2
|
||||
4ad4898db3bdcf87b2acd5755e06d45c73d338cd 4
|
||||
8262ac069e395ba020025caf0519e8eb5a63a0b8 4
|
||||
ac71117eb20ec8a84035acbbd380df8235a5c665 4
|
||||
af567ea6e27912d6d5bf1c8e9bc18e9b393fd1ab 2
|
||||
983eb5deeb61af5ce82ad598692192b8ae8a2a08 2
|
||||
ad621247f95f80a1a32e67def5e978c845d19208 2
|
||||
a7b196f7e934faa76602c8c00bd2f6e6d2d70787 2
|
||||
7be2f14fd0df5718cdb69b972c5f7c1f284b03e6 2
|
||||
53e1fb8ee77757cd20bf4c7aa4a5c6c786c664d6 2
|
||||
c18adae0ca1243e13a15d381a431cc0dfc68223b 2
|
||||
ea0824ea0692d2cdff816a2b3c3eb9a587a5f536 2
|
||||
e9e778c3d103cc8c32093cd6880fa8d7238bbd9e 2
|
||||
4b78514753008cabda2ff3d3cb537b2429efd7d2 2
|
||||
21ac0ae7da47abf30986b479489134c79405f95d 2
|
||||
3a0b0bdd77a1f3a11533f5ef030370bcc90c6334 2
|
||||
1c17e58f1a602e07f185bce1aa8589fae76e8b44 4
|
||||
d53a8efefe3714269538a91e5256c2938fe13239 4
|
||||
1cbd5c7849f97dea1e3375a842f784ff9283310c 7
|
||||
ab087d04eb5c2c8894758c7cee32ccafd80989a7 4
|
||||
4c2a8cde9b40c4936f512365a7cd6c8cef92095e 3
|
||||
b1cf453206beef8ab2ede2b061ed95a3cd91eae3 3
|
||||
04a135910588ef8753b04a49c66d138c081284d2 3
|
||||
721a2ded692d34d864d0440ac347c60880942d19 4
|
||||
1d97922a5ab63e73611d0edbe952f041af3385b3 4
|
||||
688b70e60dc272654ac6b0a72237fefdce2ef9ff 4
|
||||
6075cd96bc85864f22c643b023302f006b565049 3
|
||||
5c278deb1390eb45c79b7667b1ea1c54183123ac 4
|
||||
cb6bd26961387def757c7faeec7563d77d404d01 7
|
||||
89943ae938fb308f4b5149ebc0cbea597b9b0223 7
|
||||
fbfdd89ec183ceae63d3d66b0ab45faa951b525a 7
|
||||
c9c272ffa69d3e0af5be42e7636b02dc2af6ea8c 5
|
||||
82397096d5ef436b99b943c2a52d6eff87694183 5
|
||||
8e66731c99f4d041ddcd33088d0ab0d4cae8bf75 5
|
||||
0f10d77d1536993b8455b3b47278ca5782ef9275 4
|
||||
6933de9a128e90a34383f3a9b2660d5bae5d9fe3 4
|
||||
d5902afbd8dfb1ea96fc8cf4d62cf6e4fa40d4f7 4
|
||||
78507f3f8b8601d99bbedb6517bec6cddf0bd5b4 4
|
||||
4607ed284bd4602affa00600c749ce43b2b89b6d 5
|
||||
b7104477c8801fe54d1ba91f3a77ac6e4f399f52 5
|
||||
788c53657d9ea180d04f29ccaf1f1c29a9b75519 5
|
||||
ce4c5ce07afd297156899eb6c1056eef3f83b803 5
|
||||
cbec713b32517a503ae6c02497357a8361eccb76 3
|
||||
b20e02cbffef692c7aee6281eb36729ee1e928ef 4
|
||||
ae6ad52d5ebcad7722ea070109a286fe13b06cb7 4
|
||||
d7f8c34e3ae9dea51d0c87857e0ff78028d402b7 4
|
||||
f52690157a51c662ffdf4ae3592ada93d7be4032 4
|
||||
81143d2a8ef7cc593a604f3cc890312b42bdff01 5
|
||||
8afe57c287adc0f93f234e8e8c136ae3c00947c1 5
|
||||
418f6248221c79039fe6c44fc5a9514842e3ec71 4
|
||||
07c4c39c6e6c03241d2353300f630b367322e78a 4
|
||||
91afe2ee3a5b8e80d67f6c7a30bafbc2d63b2421 3
|
||||
29a42c2b679bac55a0318ce8c97708e402e2779b 4
|
||||
0c62591033aa4e5e6b9eeb21eb2e5e60dcd8ee8e 2
|
||||
2312bff70c83e60d1ca0fb9ca78a50637d02771c 2
|
||||
1ccac7caeaaa1c5a89503221b0a5eec2f34b1c91 2
|
||||
c82c6e054313f4c8864e64897baea8b63776020d 4
|
||||
f787271597abbcb1297e4e8a4a9561959a195649 4
|
||||
c08a3c1478e51db62624814acbf36c198d6561e6 4
|
||||
b81dd702afaaa5946e4ec065042c891ad2f76c2b 3
|
||||
02c3ec94190c6fce6fa4984d92be48b2697e7706 4
|
||||
4bd533cd7859489a3b26787fb5c7e4d8662cc420 4
|
||||
b5749b4cac530e261da9acc0d494a81766d2acc3 3
|
||||
afb693fd0a138cfc59a2bf81eabd7ca2abd4e162 4
|
||||
81bbbd4ea86350ebba03e8d8cb29f050a3d93a83 4
|
||||
d17acc97bf2f853a5fff58da733e4cd53cdaa3ed 5
|
||||
59f679c5ebf75de98b5e909da9182dbd80413364 4
|
||||
a80b5426fd0f4ab19eba1c06620f5efb8fbade3a 3
|
||||
a57f8ec4f89ab84936f46821969de6bca9f46d8e 4
|
||||
d3a936e5ef24fdbc7a02a81644ab6cd4b88119d3 3
|
||||
522a53034cf40448d441683f3308fcb4b65e6d7c 7
|
||||
dab5a9f93a35fcb92c01e4250b01928fe8bd294b 7
|
||||
25ffc7e8ca90274566c31e10b5998cca6522673a 7
|
||||
c1923ab5c5dcaf67af3e23fd1ac42e2d4c61aca7 4
|
||||
24384e63bfe450bce6abd327eae3e27969025379 4
|
||||
3f9d72bdafecfa640639cf66721e7380e41c6e6d 3
|
||||
c5b4cd4b49144e8f77455e9ff9077ff840ab278c 3
|
||||
c74a5a6164536750d6b3ea90e19798ab6fad79d7 4
|
||||
510f6d854f813269f67ee15a4cc2ed77d96d2903 4
|
||||
a5f3ada0610ad32f59d2f114167612d4f62bec4e 3
|
||||
d076d7185078b8adddbacfee7e46c61e3e02fe7e 3
|
||||
77d95640c80bc4868d04a913f9dbf4b5f6d877d2 5
|
||||
dbcfa55870a267112c9a71bcf85b481b11d98e04 3
|
||||
ee095ee6361f0a767250fe19c9bc805bba8da4e9 3
|
||||
39d500fbf22168be2a12ac89ff5a50131bb1c30b 4
|
||||
3194153a9c93aa24b37804a764f112bdef091bf8 4
|
||||
eca36fe80a916eb6b196ec56edfc1296d793e350 3
|
||||
d452a79b25f18e6a6eadc5c592d5101f115ef0f0 3
|
||||
ebed19269b7625c93eccefc2bd758555e2027431 3
|
||||
e388e8d8546e329d2c58269d4fa026624a640f1b 4
|
||||
f6199f48ff994fc9a8e33a8581bb3bb16dd301ab 2
|
||||
9447e50d1266b7cb96a414eaf9ee16c0f99e55f3 2
|
||||
ad1081f398ac69c0c92e4afadde482574fe875bb 2
|
||||
17583adb63d16d64ae51820055cd32c0e935425a 2
|
||||
2fc050dbc44ba9dfb72299129d48e5e5e1c892c3 4
|
||||
2bfa08db95502ee9bde61c5fe7b6557c0e4aef5a 4
|
||||
dc56cff1211bacd94f59e188e44a58d6f40a0c26 5
|
||||
de251a0af1df3be18469578dc00d414e572ee33e 7
|
||||
d1cc2a77fb17608d542c50e2a1404cf5b4231521 5
|
||||
8666f3109ad01093b0afab11986cfd60ba37d2a0 5
|
||||
fbb22cea9227f6f40080a42a1a169c0747129c95 5
|
||||
e171d0cec1d32aaf084e3c8150705c177522cbe6 3
|
||||
4164dcdfe0613d0f4c53b6f3581548bbbad5eb43 7
|
||||
ef6c6cde14eb551b74640ed6b38660572f121b86 7
|
||||
b9d46267d081882dfd89342d3e09b82d7e8f618d 7
|
||||
2a3c7ad70e34989fa5170028bad760e65ebe9d57 5
|
||||
3202af113265e67e130a0b948dc167a9f9e9cc79 4
|
||||
1ab38b014480745eaae143c9e6f67b542e62442f 3
|
||||
795d47c6aae378d0d5bedc9f104a597bcc1ee16b 4
|
||||
414fd2a22076f45502c2329b45bda9f8730dcaae 4
|
||||
b2ce0bc86f82f727db956dfbbe2a3fd0cb72f5fc 7
|
||||
00c70cf37c71cb8f99567ae407ff6dd52c4774c2 4
|
||||
c3ab3edb7f9ba31124092dc0f1dd2f13d3b52f8f 4
|
||||
aba839d554733850902f3073f7974e2e87c488ba 4
|
||||
19e79a79be13ac62bb002ed3323502be97886e17 3
|
||||
db22cd03db61a495d55c460cfaa266271c8a5926 3
|
||||
17dcbe8e9ab792483a542b0230897baf0240dcc9 3
|
||||
af310ee21b5534f32ea92c0ae34a44d828d157a7 4
|
||||
e3036a7bc6ed3ece1c85d5e37fb2ff39ba98ba47 4
|
||||
2300aa82bfcbcf95329eb04e58bcd7e4ca0a7889 3
|
||||
7fe5f17ad7e6b70dd56cad2c8bdc516a86f03207 4
|
||||
632cb0834441626d20cc113cfad2e3a7ec0e0dc7 3
|
||||
d7fb2ca6004c5fdf77c42a5eab102b95a9a862d7 3
|
||||
4ff2aad8371e382e203c7f29b665612a8c9d937c 3
|
||||
7c7d0bff4a51bb0f1f0cdb4132fdb11f8a71c623 3
|
||||
216b2c181c9ee0fb48e2d9efdb88ea918c8ff04f 3
|
||||
338460029d65ebce0d9119d811187a35c866a958 4
|
||||
108e9164ef6cf1ffe6e3c5303bfbbc3bd807b6df 4
|
||||
18be429f8b5c7bc4775c99292110aa09341cd644 4
|
||||
92bada2d019fcd6eee6d332a8068a9ddfa30d518 4
|
||||
c7377eaeb7f91639296c3df095ba403dbf4f8e79 2
|
||||
2f2c7559a5ba7fb938aba152bd84879c0bd3cae2 5
|
||||
7ed1308179c41ae62cfb46124ab0ce22d8b0513b 5
|
||||
6a95b7f3a4cff9c9b3d7b8b30b0b0f752dadaa37 5
|
||||
34635bf3518c7b33164f3d96da769c7a01102d28 4
|
||||
ebe20c85c5314957fafc223c26bf393847e3bb03 5
|
||||
f2361230358bd945690ca1c2a9dcc1cbce83941b 5
|
||||
ab3f375b6890b2a9bb1b6124f0fa690950c749f2 5
|
||||
f84d7fc089b31440cac1f4fbee3d45b2f6c90e37 5
|
||||
28b54294007ec345aef7322a2fcaa18d3363a73e 5
|
||||
3e57fad130be79223068ab29f1e77ecb7f2ad237 4
|
||||
efed48854beb2803d9f2b5644edff2aacf7c6af9 4
|
||||
9347890b025cc8c521a4abbff309ffc0466f22b3 4
|
||||
6fe7a6bb86897e579393e70961a3a3204adfa48b 3
|
||||
c570eccb1bf0c993e375e094d803ef112d0763ad 3
|
||||
2724871629b46e05a0c8b5554a962211e700de0e 3
|
||||
9200fd6f1e92f78e3d9c6d082837f719ad0500d4 5
|
||||
23e702084e3031158a50a0560746767bbc1b7bee 5
|
||||
289ac36381905685dda39946127ab2af3317a010 5
|
||||
36eda820b734ac7a42653af370a475f36bd36b1b 5
|
||||
d526249c1a35cf1174300df75bc28662f579290a 5
|
||||
a322d4e572467be5e1b452214143f88db526b49f 4
|
||||
67fa6e9005d23d9c49f77884a856cfb376194083 3
|
||||
4cc5f197d2bd3f0306c07a880590b4b4a5574e12 4
|
||||
06c527db4fbe929b4da005e7463078c05944f477 4
|
||||
094d11ebf8a20b6bfc07902c7f136bdd18b1e7ca 4
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
include ../../EMULib/Rules.Unix
|
||||
|
||||
# Depending on your CPU endianess, use either -DLSB_FIRST or -DMSB_FIRST.
|
||||
# Depending on your X11 display mode, use -DBPP8, -DBPP16, or -DBPP32.
|
||||
DEFINES+= -DFMSX -DLSB_FIRST -DCONDEBUG -DDEBUG -DNEW_STATES \
|
||||
-DNO_WAVE_INTERPOLATION
|
||||
CFLAGS += -I$(LIBZ80)
|
||||
OBJECTS+= $(SHA1) $(FLOPPY) $(FDIDISK) $(HUNT) \
|
||||
$(Z80) $(I8255) $(YM2413) $(AY8910) $(SCC) $(WD1793) \
|
||||
../fMSX.o ../MSX.o ../V9938.o ../I8251.o ../Patch.o \
|
||||
../Menu.o Unix.o
|
||||
|
||||
all: fmsx
|
||||
|
||||
fmsx: Makefile $(OBJECTS)
|
||||
$(CC) -o $@ $(CFLAGS) $(OBJECTS) $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS)
|
||||
Executable
+414
@@ -0,0 +1,414 @@
|
||||
/** fMSX: portable MSX emulator ******************************/
|
||||
/** **/
|
||||
/** Unix.c **/
|
||||
/** **/
|
||||
/** This file contains Unix-dependent subroutines and **/
|
||||
/** drivers. It includes screen drivers via CommonMux.h. **/
|
||||
/** **/
|
||||
/** Copyright (C) Marat Fayzullin 1994-2017 **/
|
||||
/** You are not allowed to distribute this software **/
|
||||
/** commercially. Please, notify me, if you make any **/
|
||||
/** changes to this file. **/
|
||||
/*************************************************************/
|
||||
#include "MSX.h"
|
||||
#include "Console.h"
|
||||
#include "EMULib.h"
|
||||
#include "NetPlay.h"
|
||||
#include "Sound.h"
|
||||
#include "Record.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define WIDTH 272 /* Buffer width */
|
||||
#define HEIGHT 228 /* Buffer height */
|
||||
|
||||
/* Press/Release keys in the background KeyState */
|
||||
#define XKBD_SET(K) XKeyState[Keys[K][0]]&=~Keys[K][1]
|
||||
#define XKBD_RES(K) XKeyState[Keys[K][0]]|=Keys[K][1]
|
||||
|
||||
/* Combination of EFF_* bits */
|
||||
int UseEffects = EFF_SCALE|EFF_SAVECPU|EFF_MITSHM|EFF_VARBPP|EFF_SYNC;
|
||||
|
||||
int InMenu; /* 1: In MenuMSX(), ignore keys */
|
||||
int UseZoom = 2; /* Zoom factor (1=no zoom) */
|
||||
int UseSound = 22050; /* Audio sampling frequency (Hz) */
|
||||
int SyncFreq = 60; /* Sync frequency (0=sync off) */
|
||||
int FastForward; /* Fast-forwarded UPeriod backup */
|
||||
int SndSwitch; /* Mask of enabled sound channels */
|
||||
int SndVolume; /* Master volume for audio */
|
||||
int OldScrMode; /* fMSX "ScrMode" variable storage*/
|
||||
|
||||
const char *Title = "fMSX Unix 4.9"; /* Program version */
|
||||
|
||||
Image NormScreen; /* Main screen image */
|
||||
Image WideScreen; /* Wide screen image */
|
||||
static pixel *WBuf; /* From Wide.h */
|
||||
static pixel *XBuf; /* From Common.h */
|
||||
static unsigned int XPal[80];
|
||||
static unsigned int BPal[256];
|
||||
static unsigned int XPal0;
|
||||
|
||||
const char *Disks[2][MAXDISKS+1]; /* Disk names */
|
||||
volatile byte XKeyState[20]; /* Temporary KeyState array */
|
||||
|
||||
void HandleKeys(unsigned int Key);
|
||||
void PutImage(void);
|
||||
|
||||
/** CommonMux.h **********************************************/
|
||||
/** Display drivers for all possible screen depths. **/
|
||||
/*************************************************************/
|
||||
#include "CommonMux.h"
|
||||
|
||||
/** InitMachine() ********************************************/
|
||||
/** Allocate resources needed by machine-dependent code. **/
|
||||
/*************************************************************/
|
||||
int InitMachine(void)
|
||||
{
|
||||
int J;
|
||||
|
||||
/* Initialize variables */
|
||||
UseZoom = UseZoom<1? 1:UseZoom>5? 5:UseZoom;
|
||||
InMenu = 0;
|
||||
FastForward = 0;
|
||||
OldScrMode = 0;
|
||||
NormScreen.Data = 0;
|
||||
WideScreen.Data = 0;
|
||||
|
||||
/* Initialize system resources */
|
||||
InitUnix(Title,UseZoom*WIDTH,UseZoom*HEIGHT);
|
||||
|
||||
/* Set visual effects */
|
||||
SetEffects(UseEffects);
|
||||
|
||||
/* Create main image buffer */
|
||||
if(!NewImage(&NormScreen,WIDTH,HEIGHT)) { TrashUnix();return(0); }
|
||||
XBuf = NormScreen.Data;
|
||||
|
||||
#ifndef NARROW
|
||||
/* Create wide image buffer */
|
||||
if(!NewImage(&WideScreen,WIDTH*2,HEIGHT)) { TrashUnix();return(0); }
|
||||
WBuf = WideScreen.Data;
|
||||
#endif
|
||||
|
||||
/* Set correct screen drivers */
|
||||
if(!SetScreenDepth(NormScreen.D)) { TrashUnix();return(0); }
|
||||
|
||||
/* Initialize video to main image */
|
||||
SetVideo(&NormScreen,0,0,WIDTH,HEIGHT);
|
||||
|
||||
/* Set all colors to black */
|
||||
for(J=0;J<80;J++) SetColor(J,0,0,0);
|
||||
|
||||
/* Create SCREEN8 palette (GGGRRRBB) */
|
||||
for(J=0;J<256;J++)
|
||||
BPal[J]=X11GetColor(((J>>2)&0x07)*255/7,((J>>5)&0x07)*255/7,(J&0x03)*255/3);
|
||||
|
||||
/* Initialize temporary keyboard array */
|
||||
memset((void *)XKeyState,0xFF,sizeof(XKeyState));
|
||||
|
||||
/* Attach keyboard handler */
|
||||
SetKeyHandler(HandleKeys);
|
||||
|
||||
/* Initialize sound */
|
||||
InitSound(UseSound,150);
|
||||
SndSwitch=(1<<MAXCHANNELS)-1;
|
||||
SndVolume=64;
|
||||
SetChannels(SndVolume,SndSwitch);
|
||||
|
||||
/* Initialize sync timer if needed */
|
||||
if((SyncFreq>0)&&!SetSyncTimer(SyncFreq*UPeriod/100)) SyncFreq=0;
|
||||
|
||||
/* Initialize record/replay */
|
||||
RPLInit(SaveState,LoadState,MAX_STASIZE);
|
||||
RPLRecord(RPL_RESET);
|
||||
|
||||
/* Done */
|
||||
return(1);
|
||||
}
|
||||
|
||||
/** TrashMachine() *******************************************/
|
||||
/** Deallocate all resources taken by InitMachine(). **/
|
||||
/*************************************************************/
|
||||
void TrashMachine(void)
|
||||
{
|
||||
/* Flush and free recording buffers */
|
||||
RPLTrash();
|
||||
|
||||
#ifndef NARROW
|
||||
FreeImage(&WideScreen);
|
||||
#endif
|
||||
FreeImage(&NormScreen);
|
||||
TrashSound();
|
||||
TrashUnix();
|
||||
}
|
||||
|
||||
/** PutImage() ***********************************************/
|
||||
/** Put an image on the screen. **/
|
||||
/*************************************************************/
|
||||
void PutImage(void)
|
||||
{
|
||||
#ifndef NARROW
|
||||
/* If screen mode changed... */
|
||||
if(ScrMode!=OldScrMode)
|
||||
{
|
||||
/* Switch to the new screen mode */
|
||||
OldScrMode=ScrMode;
|
||||
/* Depending on the new screen width... */
|
||||
if((ScrMode==6)||((ScrMode==7)&&!ModeYJK)||(ScrMode==MAXSCREEN+1))
|
||||
SetVideo(&WideScreen,0,0,WIDTH*2,HEIGHT);
|
||||
else
|
||||
SetVideo(&NormScreen,0,0,WIDTH,HEIGHT);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Show replay icon */
|
||||
if(RPLPlay(RPL_QUERY)) RPLShow(VideoImg,VideoX+10,VideoY+10);
|
||||
|
||||
/* Show display buffer */
|
||||
ShowVideo();
|
||||
}
|
||||
|
||||
/** Joystick() ***********************************************/
|
||||
/** Query positions of two joystick connected to ports 0/1. **/
|
||||
/** Returns 0.0.B2.A2.R2.L2.D2.U2.0.0.B1.A1.R1.L1.D1.U1. **/
|
||||
/*************************************************************/
|
||||
unsigned int Joystick(void)
|
||||
{
|
||||
byte RemoteKeyState[20];
|
||||
unsigned int J,I;
|
||||
|
||||
/* Render audio (two frames to avoid skipping) */
|
||||
RenderAndPlayAudio(UseSound/30);
|
||||
|
||||
/* Get joystick state, minus the fire buttons */
|
||||
I = BTN_LEFT|BTN_RIGHT|BTN_UP|BTN_DOWN;
|
||||
J = GetJoystick()&(I|(I<<16)|BTN_MODES);
|
||||
|
||||
/* Make SHIFT/CONTROL act as fire buttons */
|
||||
if(J&BTN_SHIFT) J|=(J&BTN_ALT? (BTN_FIREB<<16):BTN_FIREB);
|
||||
if(J&BTN_CONTROL) J|=(J&BTN_ALT? (BTN_FIREA<<16):BTN_FIREA);
|
||||
|
||||
/* Store joystick state for NetPlay transmission */
|
||||
*(unsigned int *)&XKeyState[sizeof(XKeyState)-sizeof(int)]=J;
|
||||
|
||||
/* If failed exchanging KeyStates with remote... */
|
||||
if(!NETExchange(RemoteKeyState,(const void *)XKeyState,sizeof(XKeyState)))
|
||||
/* Copy temporary keyboard map into permanent one */
|
||||
memcpy((void *)KeyState,(const void *)XKeyState,sizeof(KeyState));
|
||||
else
|
||||
{
|
||||
/* Merge local and remote KeyStates */
|
||||
for(I=0;I<sizeof(KeyState);++I) KeyState[I]=XKeyState[I]&RemoteKeyState[I];
|
||||
/* Merge joysticks, server is player #1, client is player #2 */
|
||||
I = *(unsigned int *)&RemoteKeyState[sizeof(XKeyState)-sizeof(int)];
|
||||
J = NETConnected()==NET_SERVER?
|
||||
((J&(BTN_ALL|BTN_MODES))|((I&BTN_ALL)<<16))
|
||||
: ((I&(BTN_ALL|BTN_MODES))|((J&BTN_ALL)<<16));
|
||||
}
|
||||
|
||||
/* Replay recorded joystick and keyboard states */
|
||||
if(J) RPLPlay(RPL_OFF);
|
||||
I = RPLPlayKeys(RPL_NEXT,(byte *)KeyState,sizeof(KeyState));
|
||||
I = I!=RPL_ENDED? I:0;
|
||||
|
||||
/* Parse joystick */
|
||||
if(J&BTN_LEFT) I|=JST_LEFT;
|
||||
if(J&BTN_RIGHT) I|=JST_RIGHT;
|
||||
if(J&BTN_UP) I|=JST_UP;
|
||||
if(J&BTN_DOWN) I|=JST_DOWN;
|
||||
if(J&(BTN_FIREA|BTN_FIRER)) I|=JST_FIREA;
|
||||
if(J&(BTN_FIREB|BTN_FIREL)) I|=JST_FIREB;
|
||||
if(J&(BTN_LEFT<<16)) I|=JST_LEFT<<8;
|
||||
if(J&(BTN_RIGHT<<16)) I|=JST_RIGHT<<8;
|
||||
if(J&(BTN_UP<<16)) I|=JST_UP<<8;
|
||||
if(J&(BTN_DOWN<<16)) I|=JST_DOWN<<8;
|
||||
if(J&((BTN_FIREA|BTN_FIRER)<<16)) I|=JST_FIREA<<8;
|
||||
if(J&((BTN_FIREB|BTN_FIREL)<<16)) I|=JST_FIREB<<8;
|
||||
|
||||
/* Record joystick and keyboard states */
|
||||
RPLRecordKeys(I,(byte *)KeyState,sizeof(KeyState));
|
||||
|
||||
/* Done */
|
||||
return(I);
|
||||
}
|
||||
|
||||
/** Keyboard() ***********************************************/
|
||||
/** Modify keyboard matrix. **/
|
||||
/*************************************************************/
|
||||
void Keyboard(void)
|
||||
{
|
||||
/* Everything is done in Joystick() */
|
||||
}
|
||||
|
||||
/** Mouse() **************************************************/
|
||||
/** Query coordinates of a mouse connected to port N. **/
|
||||
/** Returns F2.F1.Y.Y.Y.Y.Y.Y.Y.Y.X.X.X.X.X.X.X.X. **/
|
||||
/*************************************************************/
|
||||
unsigned int Mouse(byte N)
|
||||
{
|
||||
unsigned int J;
|
||||
int X,Y;
|
||||
|
||||
J = GetMouse();
|
||||
X = ScanLines212? 212:192;
|
||||
Y = ((J&MSE_YPOS)>>16)-(HEIGHT-X)/2-VAdjust;
|
||||
Y = Y<0? 0:Y>=X? X-1:Y;
|
||||
X = J&MSE_XPOS;
|
||||
X = (ScrMode==6)||((ScrMode==7)&&!ModeYJK)||(ScrMode==MAXSCREEN+1)? (X>>1):X;
|
||||
X = X-(WIDTH-256)/2-HAdjust;
|
||||
X = X<0? 0:X>=256? 255:X;
|
||||
|
||||
return(((J&MSE_BUTTONS)>>14)|X|(Y<<8));
|
||||
}
|
||||
|
||||
/** SetColor() ***********************************************/
|
||||
/** Set color N to (R,G,B). **/
|
||||
/*************************************************************/
|
||||
void SetColor(byte N,byte R,byte G,byte B)
|
||||
{
|
||||
if(N) XPal[N]=X11GetColor(R,G,B); else XPal0=X11GetColor(R,G,B);
|
||||
}
|
||||
|
||||
/** HandleKeys() *********************************************/
|
||||
/** Keyboard handler. **/
|
||||
/*************************************************************/
|
||||
void HandleKeys(unsigned int Key)
|
||||
{
|
||||
/* When in MenuMSX() or ConDebug(), ignore keypresses */
|
||||
if(InMenu||CPU.Trace) return;
|
||||
|
||||
/* Handle special keys */
|
||||
if(Key&CON_RELEASE)
|
||||
switch(Key&CON_KEYCODE)
|
||||
{
|
||||
case XK_F9:
|
||||
if(FastForward)
|
||||
{
|
||||
SetEffects(UseEffects);
|
||||
UPeriod=FastForward;
|
||||
FastForward=0;
|
||||
}
|
||||
break;
|
||||
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R: XKBD_RES(KBD_SHIFT);break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R: XKBD_RES(KBD_CONTROL);break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R: XKBD_RES(KBD_GRAPH);break;
|
||||
case XK_Caps_Lock: XKBD_RES(KBD_CAPSLOCK);break;
|
||||
case XK_Escape: XKBD_RES(KBD_ESCAPE);break;
|
||||
case XK_Return: XKBD_RES(KBD_ENTER);break;
|
||||
case XK_BackSpace: XKBD_RES(KBD_BS);break;
|
||||
case XK_Tab: XKBD_RES(KBD_TAB);break;
|
||||
case XK_End: XKBD_RES(KBD_SELECT);break;
|
||||
case XK_Home: XKBD_RES(KBD_HOME);break;
|
||||
case XK_Page_Up: XKBD_RES(KBD_STOP);break;
|
||||
case XK_Page_Down: XKBD_RES(KBD_COUNTRY);break;
|
||||
case XK_Insert: XKBD_RES(KBD_INSERT);break;
|
||||
case XK_Delete: XKBD_RES(KBD_DELETE);break;
|
||||
case XK_Up: XKBD_RES(KBD_UP);break;
|
||||
case XK_Down: XKBD_RES(KBD_DOWN);break;
|
||||
case XK_Left: XKBD_RES(KBD_LEFT);break;
|
||||
case XK_Right: XKBD_RES(KBD_RIGHT);break;
|
||||
case XK_F1: XKBD_RES(KBD_F1);break;
|
||||
case XK_F2: XKBD_RES(KBD_F2);break;
|
||||
case XK_F3: XKBD_RES(KBD_F3);break;
|
||||
case XK_F4: XKBD_RES(KBD_F4);break;
|
||||
case XK_F5: XKBD_RES(KBD_F5);break;
|
||||
|
||||
default:
|
||||
Key&=CON_KEYCODE;
|
||||
if(Key<128) XKBD_RES(Key);
|
||||
break;
|
||||
}
|
||||
else
|
||||
switch(Key&CON_KEYCODE)
|
||||
{
|
||||
case XK_F6:
|
||||
LoadSTA(STAName? STAName:"DEFAULT.STA");
|
||||
RPLPlay(RPL_OFF);
|
||||
break;
|
||||
case XK_F7:
|
||||
SaveSTA(STAName? STAName:"DEFAULT.STA");
|
||||
break;
|
||||
case XK_F8:
|
||||
if(!(Key&(CON_ALT|CON_CONTROL))) RPLPlay(RPL_RESET);
|
||||
else
|
||||
{
|
||||
/* [ALT]+[F8] toggles screen softening */
|
||||
/* [CTRL]+[F8] toggles scanlines */
|
||||
UseEffects^=Key&CON_ALT? EFF_SOFTEN:EFF_TVLINES;
|
||||
SetEffects(UseEffects);
|
||||
}
|
||||
break;
|
||||
case XK_F9:
|
||||
if(!FastForward)
|
||||
{
|
||||
SetEffects(UseEffects&~EFF_SYNC);
|
||||
FastForward=UPeriod;
|
||||
UPeriod=10;
|
||||
}
|
||||
break;
|
||||
case XK_F10:
|
||||
#ifdef DEBUG
|
||||
/* [CTRL]+[F10] invokes built-in debugger */
|
||||
if(Key&CON_CONTROL)
|
||||
{ XKBD_RES(KBD_CONTROL);CPU.Trace=1;break; }
|
||||
#endif
|
||||
/* [ALT]+[F10] invokes NetPlay */
|
||||
if(Key&CON_ALT)
|
||||
{
|
||||
XKBD_RES(KBD_GRAPH);
|
||||
InMenu=1;
|
||||
if(NETPlay(NET_TOGGLE)) ResetMSX(Mode,RAMPages,VRAMPages);
|
||||
InMenu=0;
|
||||
break;
|
||||
}
|
||||
/* [F10] invokes built-in menu */
|
||||
InMenu=1;
|
||||
MenuMSX();
|
||||
InMenu=0;
|
||||
break;
|
||||
case XK_F11:
|
||||
ResetMSX(Mode,RAMPages,VRAMPages);
|
||||
RPLPlay(RPL_OFF);
|
||||
break;
|
||||
case XK_F12:
|
||||
ExitNow=1;
|
||||
break;
|
||||
|
||||
case XK_Shift_L:
|
||||
case XK_Shift_R: XKBD_SET(KBD_SHIFT);break;
|
||||
case XK_Control_L:
|
||||
case XK_Control_R: XKBD_SET(KBD_CONTROL);break;
|
||||
case XK_Alt_L:
|
||||
case XK_Alt_R: XKBD_SET(KBD_GRAPH);break;
|
||||
case XK_Caps_Lock: XKBD_SET(KBD_CAPSLOCK);break;
|
||||
case XK_Escape: XKBD_SET(KBD_ESCAPE);break;
|
||||
case XK_Return: XKBD_SET(KBD_ENTER);break;
|
||||
case XK_BackSpace: XKBD_SET(KBD_BS);break;
|
||||
case XK_Tab: XKBD_SET(KBD_TAB);break;
|
||||
case XK_End: XKBD_SET(KBD_SELECT);break;
|
||||
case XK_Home: XKBD_SET(KBD_HOME);break;
|
||||
case XK_Page_Up: XKBD_SET(KBD_STOP);break;
|
||||
case XK_Page_Down: XKBD_SET(KBD_COUNTRY);break;
|
||||
case XK_Insert: XKBD_SET(KBD_INSERT);break;
|
||||
case XK_Delete: XKBD_SET(KBD_DELETE);break;
|
||||
case XK_Up: XKBD_SET(KBD_UP);break;
|
||||
case XK_Down: XKBD_SET(KBD_DOWN);break;
|
||||
case XK_Left: XKBD_SET(KBD_LEFT);break;
|
||||
case XK_Right: XKBD_SET(KBD_RIGHT);break;
|
||||
case XK_F1: XKBD_SET(KBD_F1);break;
|
||||
case XK_F2: XKBD_SET(KBD_F2);break;
|
||||
case XK_F3: XKBD_SET(KBD_F3);break;
|
||||
case XK_F4: XKBD_SET(KBD_F4);break;
|
||||
case XK_F5: XKBD_SET(KBD_F5);break;
|
||||
|
||||
default:
|
||||
Key&=CON_KEYCODE;
|
||||
if(Key<128) XKBD_SET(Key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user