- Change savestate code to support loosely bound chunks and more easily other parts of the emu (GE, GPU; also we need SPU eventually). The savestate format is changed, but from now on it is in principle more resilient (it will continue to break though)

- Remove 16MB of WRAM at 0x01****** from arm9
This commit is contained in:
zeromus 2008-09-19 08:08:34 +00:00
parent 319adfc4e0
commit b1e4934421
23 changed files with 1344 additions and 550 deletions

View File

@ -14,6 +14,9 @@
- Added gfx3d module which emulates the whole GE as part of the core emu. Moved the windows/cocoa OGLRender to the
emu core and replace ogl_collector. Now every platform shares the same 3d code. [zeromus]
- Add in some crude interpolation in the SPU (conditionally compiled) so that I can bear to listen to it. [zeromus]
- Change savestate code to support loosely bound chunks and more easily other parts of the emu (GE, GPU).
The savestate format is changed, but from now on it is in principle more resilient (it will continue to break though) [zeromus]
- Remove 16MB of WRAM at 0x01****** from arm9. Maped to unusued instead. What was this? [zeromus]
Mac OS X port:
- Fixed: Filenames and paths with unicode characters now work. [Jeff]
- Fixed: Load state from file button works again. [Jeff]

View File

@ -2,7 +2,7 @@ Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006, 2007 Free Software Foundation, Inc.
2006 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
@ -67,9 +67,6 @@ The simplest way to compile this package is:
all sorts of other programs in order to regenerate files that came
with the distribution.
6. Often, you can also type `make uninstall' to remove the installed
files again.
Compilers and Options
=====================

View File

@ -7,7 +7,6 @@ typedef struct {
//ARM9 mem
u8 ARM9_ITCM[0x8000];
u8 ARM9_DTCM[0x4000];
u8 ARM9_WRAM[0x1000000];
u8 MAIN_MEM[0x400000];
u8 ARM9_REG[0x1000000];
u8 ARM9_BIOS[0x8000];

View File

@ -40,9 +40,11 @@
// GRAPHICS CORE
// GPU_ligne
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
#include "MMU.h"
#include "GPU.h"
#include "debug.h"
@ -545,9 +547,9 @@ static BOOL setFinalColorSpecialBlend (const GPU *gpu, u32 passing, u8 bgnum, u8
targetG = (((color>>5) & 0x1F) * targetFraction) >> 4 ;
targetB = (((color>>10) & 0x1F) * targetFraction) >> 4 ;
// limit combined components to 31 max
sourceR = min(0x1F,targetR+sourceR) ;
sourceG = min(0x1F,targetG+sourceG) ;
sourceB = min(0x1F,targetB+sourceB) ;
sourceR = std::min(0x1F,targetR+sourceR) ;
sourceG = std::min(0x1F,targetG+sourceG) ;
sourceB = std::min(0x1F,targetB+sourceB) ;
//}
}
color = (sourceR & 0x1F) | ((sourceG & 0x1F) << 5) | ((sourceB & 0x1F) << 10) | 0x8000 ;
@ -660,9 +662,9 @@ static BOOL setFinalColorSpecialBlendWnd (const GPU *gpu, u32 passing, u8 bgnum,
targetG = (((color>>5) & 0x1F) * targetFraction) >> 4 ;
targetB = (((color>>10) & 0x1F) * targetFraction) >> 4 ;
// limit combined components to 31 max
sourceR = min(0x1F,targetR+sourceR) ;
sourceG = min(0x1F,targetG+sourceG) ;
sourceB = min(0x1F,targetB+sourceB) ;
sourceR = std::min(0x1F,targetR+sourceR) ;
sourceG = std::min(0x1F,targetG+sourceG) ;
sourceB = std::min(0x1F,targetB+sourceB) ;
//}
}
color = (sourceR & 0x1F) | ((sourceG & 0x1F) << 5) | ((sourceB & 0x1F) << 10) | 0x8000 ;
@ -789,7 +791,7 @@ INLINE void renderline_textBG(const GPU * gpu, u8 num, u8 * dst, u32 Y, u16 XBG,
yoff = ((YBG&7)<<2);
xfin = 8 - (xoff&7);
for(x = 0; x < LG; xfin = min(x+8, LG))
for(x = 0; x < LG; xfin = std::min<u16>(x+8, LG))
{
u8 pt = 0, save = 0;
tmp = ((xoff&(lg-1))>>3);
@ -848,7 +850,7 @@ INLINE void renderline_textBG(const GPU * gpu, u8 num, u8 * dst, u32 Y, u16 XBG,
} else { /* no mosaic mode */
yoff = ((YBG&7)<<2);
xfin = 8 - (xoff&7);
for(x = 0; x < LG; xfin = min(x+8, LG))
for(x = 0; x < LG; xfin = std::min<u16>(x+8, LG))
{
u16 tilePalette = 0;
tmp = ((xoff&(lg-1))>>3);
@ -918,7 +920,7 @@ INLINE void renderline_textBG(const GPU * gpu, u8 num, u8 * dst, u32 Y, u16 XBG,
yoff = ((YBG&7)<<3);
xfin = 8 - (xoff&7);
for(x = 0; x < LG; xfin = min(x+8, LG))
for(x = 0; x < LG; xfin = std::min<u16>(x+8, LG))
{
tmp = (xoff & (lg-1))>>3;
mapinfo = map + (tmp & 31) * 2;
@ -2431,3 +2433,14 @@ void GPU_ligne(NDS_Screen * screen, u16 l)
}
#endif
}
void gpu_savestate(std::ostream* os)
{
os->write((char*)GPU_screen,sizeof(GPU_screen));
}
bool gpu_loadstate(std::istream* is)
{
is->read((char*)GPU_screen,sizeof(GPU_screen));
return !is->fail();
}

View File

@ -32,6 +32,10 @@
#include "FIFO.h"
#include "MMU.h"
#include "GPU_osd.h"
#include <iosfwd>
void gpu_savestate(std::ostream* os);
bool gpu_loadstate(std::istream* is);
/*******************************************************************************
this structure is for display control,
@ -385,20 +389,6 @@ typedef struct _reg_dispx {
} REG_DISPx ;
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
typedef BOOL (*fun_gl_Begin) (int screen);
typedef void (*fun_gl_End) (int screen);
// the GUI should use this function prior to all gl calls

View File

@ -63,12 +63,12 @@ OSDCLASS::OSDCLASS(u8 core)
}
printlog("OSD_Init (%s)\n",name);
LOG("OSD_Init (%s)\n",name);
}
OSDCLASS::~OSDCLASS()
{
printlog("OSD_Deinit (%s)\n",name);
LOG("OSD_Deinit (%s)\n",name);
delete old_msg;
}

View File

@ -69,7 +69,7 @@ MMU_struct MMU;
u8 * MMU_ARM9_MEM_MAP[256]={
/* 0X*/ DUP16(ARM9Mem.ARM9_ITCM),
/* 1X*/ //DUP16(ARM9Mem.ARM9_ITCM)
/* 1X*/ DUP16(ARM9Mem.ARM9_WRAM),
/* 1X*/ DUP16(MMU.UNUSED_RAM),
/* 2X*/ DUP16(ARM9Mem.MAIN_MEM),
/* 3X*/ DUP16(MMU.SWIRAM),
/* 4X*/ DUP16(ARM9Mem.ARM9_REG),
@ -93,7 +93,7 @@ u8 * MMU_ARM9_MEM_MAP[256]={
u32 MMU_ARM9_MEM_MASK[256]={
/* 0X*/ DUP16(0x00007FFF),
/* 1X*/ //DUP16(0x00007FFF)
/* 1X*/ DUP16(0x00FFFFFF),
/* 1X*/ DUP16(0x00000003),
/* 2X*/ DUP16(0x003FFFFF),
/* 3X*/ DUP16(0x00007FFF),
/* 4X*/ DUP16(0x00FFFFFF),
@ -253,7 +253,6 @@ void MMU_clearMem()
memset(ARM9Mem.ARM9_OAM, 0, 0x0800);
memset(ARM9Mem.ARM9_REG, 0, 0x01000000);
memset(ARM9Mem.ARM9_VMEM, 0, 0x0800);
memset(ARM9Mem.ARM9_WRAM, 0, 0x01000000);
memset(ARM9Mem.MAIN_MEM, 0, 0x400000);
memset(ARM9Mem.blank_memory, 0, 0x020000);

View File

@ -13,8 +13,11 @@ libdesmume_a_SOURCES = \
Disassembler.cpp Disassembler.h \
dscard.h fat.h FIFO.cpp FIFO.h \
GPU.cpp GPU.h \
GPU_osd.cpp GPU_osd.h \
gl_vertex.cpp gl_vertex.h \
mem.h mc.cpp mc.h \
memorystream.h \
readwrite.cpp readwrite.h \
wifi.cpp wifi.h \
MMU.cpp MMU.h NDSSystem.cpp NDSSystem.h registers.h \
OGLRender.cpp OGLRender.h \

View File

@ -119,11 +119,13 @@ typedef struct
u16 touchX;
u16 touchY;
//this is not essential NDS runtime state.
//it was perhaps a mistake to put it here.
//it is far less important than the above.
//maybe I should move it.
s32 idleCycles;
s32 runCycleCollector[16];
s32 idleFrameCounter;
} NDSSystem;
/** /brief A touchscreen calibration point.

View File

@ -24,6 +24,7 @@
//so, it doesnt composite to 2d correctly.
//(re: new super mario brothers renders the stormclouds at the beginning)
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <string.h>
@ -78,7 +79,6 @@ static const unsigned short map3d_cull[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BAC
static const int texEnv[4] = { GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE };
static const int depthFunc[2] = { GL_LESS, GL_EQUAL };
static bool needRefreshFramebuffer = false;
static unsigned short matrixMode[2] = {GL_PROJECTION, GL_MODELVIEW};
static unsigned char texMAP[1024*2048*4];
static unsigned int textureMode=0;
@ -508,7 +508,7 @@ void setTexture(unsigned int format, unsigned int texpal)
{
//TODO - we need to compare the palette also.
//TODO - this doesnt correctly span bank boundaries. in fact, it seems quite dangerous.
if (!texcache[i].suspectedInvalid || !memcmp(adr,texcache[i].texture,min(imageSize,sizeof(texcache[i].texture))))
if (!texcache[i].suspectedInvalid || !memcmp(adr,texcache[i].texture,std::min(imageSize,sizeof(texcache[i].texture))))
{
texcache[i].suspectedInvalid = false;
texcache_count=i;
@ -550,7 +550,7 @@ void setTexture(unsigned int format, unsigned int texpal)
texcache[i].invSizeX=1.0f/((float)sizeX*(1<<4));
texcache[i].invSizeY=1.0f/((float)sizeY*(1<<4));
//memcpy(texcache[i].texture,adr,imageSize); //======================= copy
memcpy_fast(texcache[i].texture,adr,min(imageSize,sizeof(texcache[i].texture))); //======================= copy
memcpy_fast(texcache[i].texture,adr,std::min(imageSize,sizeof(texcache[i].texture))); //======================= copy
texcache[i].numcolors=palSize[texcache[i].mode];
texcache[i].frm=format;
@ -798,7 +798,7 @@ void setTexture(unsigned int format, unsigned int texpal)
texcache[i].sizeX, texcache[i].sizeY, 0,
GL_RGBA, GL_UNSIGNED_BYTE, texMAP);
DebugDumpTexture(i);
//DebugDumpTexture(i);
//============================================================================================
@ -992,6 +992,12 @@ static void Render()
glBegin(type==3?GL_TRIANGLES:GL_QUADS);
for(int j=0;j<type;j++) {
VERT* vert = &gfx3d.vertlist->list[poly->vertIndexes[j]];
u8 color[4] = {
material_5bit_to_8bit[vert->color[0]],
material_5bit_to_8bit[vert->color[1]],
material_5bit_to_8bit[vert->color[2]],
material_5bit_to_8bit[vert->color[3]]
};
//float tempCoord[4];
//Vector4Copy(tempCoord,vert->coord);
@ -1004,7 +1010,7 @@ static void Render()
//todo - edge flag?
glTexCoord2fv(vert->texcoord);
glColor4iv((GLint*)vert->color);
glColor4ubv((GLubyte*)color);
//glVertex3fv(tempCoord);
glVertex3fv(vert->coord);
}
@ -1101,9 +1107,9 @@ static void GetLine (int line, u16* dst)
g = (g*a + oldg*(255-a)) >> 8;
b = (b*a + oldb*(255-a)) >> 8;
r=min(255,r);
g=min(255,g);
b=min(255,b);
r=std::min(255ul,r);
g=std::min(255ul,g);
b=std::min(255ul,b);
//debug: display alpha channel
//u32 r = screen3D[t+3];

View File

@ -22,6 +22,7 @@
//This handles almost all of the work of 3d rendering, leaving the renderer
// plugin responsible only for drawing primitives.
#include <algorithm>
#include "debug.h"
#include "gfx3d.h"
#include "matrix.h"
@ -29,18 +30,11 @@
#include "MMU.h"
#include "render3D.h"
#include "types.h"
#include "saves.h"
#include "readwrite.h"
GFX3D gfx3d;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
//tables that are provided to anyone
u32 color_15bit_to_24bit[32768];
@ -81,7 +75,7 @@ static float normalTable[1024];
static ALIGN(16) MatrixStack mtxStack[4];
static ALIGN(16) float mtxCurrent [4][16];
static ALIGN(16) float mtxTemporal[16];
static short mode = 0;
static u32 mode = 0;
// Indexes for matrix loading/multiplication
static char ML4x4ind = 0;
@ -93,7 +87,7 @@ static char MM3x3_c = 0, MM3x3_l = 0;
// Data for vertex submission
static ALIGN(16) float coord[4] = {0.0, 0.0, 0.0, 0.0};
static char coordind = 0;
static unsigned int vtxFormat;
static u32 vtxFormat;
// Data for basic transforms
static ALIGN(16) float trans[4] = {0.0, 0.0, 0.0, 0.0};
@ -102,45 +96,43 @@ static ALIGN(16) float scale[4] = {0.0, 0.0, 0.0, 0.0};
static char scaleind = 0;
//various other registers
static float fogColor[4] = {0.f};
static float fogOffset = 0.f;
static float alphaTestRef = 0.01f;
static int colorRGB[4] = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff};
static int texCoordinateTransform = 0;
static int _t=0, _s=0;
static float last_t, last_s;
static float alphaTestBase = 0;
static unsigned long clCmd = 0;
static unsigned long clInd = 0;
static unsigned long clInd2 = 0;
static int alphaDepthWrite = 0;
static int colorAlpha=0;
static unsigned int polyID=0;
static unsigned int depthFuncMode=0;
static unsigned int envMode=0;
static unsigned int cullingMask=0;
static u32 clCmd = 0;
static u32 clInd = 0;
static u32 clInd2 = 0;
//raw ds format poly attributes
static u32 polyAttr=0,textureFormat=0, texturePalette=0;
//------lighting state
struct LightInformation
{
unsigned int color; // Color in hardware format
unsigned int direction; // Direction in hardware format
float floatDirection[4];
} ;
//the current vertex color, 5bit values
static u8 colorRGB[4] = { 31,31,31,31 };
static LightInformation g_lightInfo[4] = { 0 };
static unsigned int lightMask=0;
u32 control = 0;
//light state:
static u32 lightColor[4] = {0,0,0,0};
static u32 lightDirection[4] = {0,0,0,0};
//material state:
static u16 dsDiffuse, dsAmbient, dsSpecular, dsEmission;
static int diffuse[4] = {0},
ambient[4] = {0},
specular[4] = {0},
emission[4] = {0};
//-----------cached things:
//these dont need to go into the savestate. they can be regenerated from HW registers
//from polygonattr:
static unsigned int cullingMask=0;
static u8 colorAlpha=0;
static u32 envMode=0;
static u32 lightMask=0;
//other things:
static int texCoordinateTransform = 0;
static float cacheLightDirection[4][4];
//------------------
#define RENDER_FRONT_SURFACE 0x80
#define RENDER_BACK_SURFACE 0X40
//-------------poly and vertex lists
POLYLIST polylists[2];
POLYLIST* polylist = &polylists[0];
@ -230,31 +222,28 @@ void gfx3d_glClearColor(unsigned long v)
void gfx3d_glFogColor(unsigned long v)
{
fogColor[0] = ((float)((v )&0x1F))/31.0f;
fogColor[1] = ((float)((v>> 5)&0x1F))/31.0f;
fogColor[2] = ((float)((v>>10)&0x1F))/31.0f;
fogColor[3] = ((float)((v>>16)&0x1F))/31.0f;
gfx3d.fogColor[0] = ((float)((v )&0x1F))/31.0f;
gfx3d.fogColor[1] = ((float)((v>> 5)&0x1F))/31.0f;
gfx3d.fogColor[2] = ((float)((v>>10)&0x1F))/31.0f;
gfx3d.fogColor[3] = ((float)((v>>16)&0x1F))/31.0f;
}
void gfx3d_glFogOffset (unsigned long v)
{
fogOffset = (float)(v&0xffff);
gfx3d.fogOffset = (float)(v&0xffff);
}
void gfx3d_glClearDepth(unsigned long v)
{
u32 depth24b;
v &= 0x7FFFF;
//Thanks to NHerve
depth24b = (v*0x200)+((v+1)/0x8000)*0x01FF;
v &= 0x7FFFF;
u32 depth24b = (v*0x200)+((v+1)/0x8000)*0x01FF;
gfx3d.clearDepth = depth24b / ((float)(1<<24));
}
void gfx3d_glMatrixMode(unsigned long v)
void gfx3d_glMatrixMode(u32 v)
{
mode = (short)(v&3);
mode = (v&3);
}
@ -467,15 +456,16 @@ void gfx3d_glEnd(void)
void gfx3d_glColor3b(unsigned long v)
{
colorRGB[0] = material_5bit_to_31bit[(v&0x1F)];
colorRGB[1] = material_5bit_to_31bit[((v>>5)&0x1F)];
colorRGB[2] = material_5bit_to_31bit[((v>>10)&0x1F)];
colorRGB[0] = (v&0x1F);
colorRGB[1] = ((v>>5)&0x1F);
colorRGB[2] = ((v>>10)&0x1F);
}
//Submit a vertex to the GE
static void SetVertex()
{
ALIGN(16) float coordTransformed[4] = { coord[0], coord[1], coord[2], 1 };
ALIGN(16) float coordProjected[4];
if (texCoordinateTransform == 3)
{
@ -496,8 +486,6 @@ static void SetVertex()
//apply modelview matrix
MatrixMultVec4x4 (mtxCurrent[1], coordTransformed);
//deferred rendering:
//todo - we havent got the whole pipeline working yet, so lets save the projection matrix and let opengl do it
////apply projection matrix
//MatrixMultVec4x4 (mtxCurrent[0], coordTransformed);
@ -511,19 +499,19 @@ static void SetVertex()
//TODO - culling should be done here.
//TODO - viewport transform
//record the vertex
tempVertList.list[tempVertList.count].texcoord[0] = last_s;
tempVertList.list[tempVertList.count].texcoord[1] = last_t;
tempVertList.list[tempVertList.count].coord[0] = coordTransformed[0];
tempVertList.list[tempVertList.count].coord[1] = coordTransformed[1];
tempVertList.list[tempVertList.count].coord[2] = coordTransformed[2];
tempVertList.list[tempVertList.count].coord[3] = coordTransformed[3];
tempVertList.list[tempVertList.count].color[0] = colorRGB[0];
tempVertList.list[tempVertList.count].color[1] = colorRGB[1];
tempVertList.list[tempVertList.count].color[2] = colorRGB[2];
tempVertList.list[tempVertList.count].color[3] = colorRGB[3];
tempVertList.list[tempVertList.count].depth = 0x7FFF * coordTransformed[2];
VERT &vert = tempVertList.list[tempVertList.count];
vert.texcoord[0] = last_s;
vert.texcoord[1] = last_t;
vert.coord[0] = coordTransformed[0];
vert.coord[1] = coordTransformed[1];
vert.coord[2] = coordTransformed[2];
vert.coord[3] = coordTransformed[3];
vert.color[0] = colorRGB[0];
vert.color[1] = colorRGB[1];
vert.color[2] = colorRGB[2];
vert.color[3] = colorRGB[3];
vert.depth = 0x7FFF * coordTransformed[2];
tempVertList.count++;
//possibly complete a polygon
@ -653,35 +641,34 @@ int gfx3d_GetNumVertex()
return 0;
}
static void InstallPolygonAttrib(unsigned long val)
static void gfx3d_glPolygonAttrib_cache()
{
// Light enable/disable
lightMask = (val&0xF);
lightMask = (polyAttr&0xF);
// texture environment
//envMode = texEnv[(val&0x30)>>4];
envMode = (val&0x30)>>4;
envMode = (polyAttr&0x30)>>4;
//// overwrite depth on alpha pass
//alphaDepthWrite = BIT11(val);
//alphaDepthWrite = BIT11(polyAttr);
//// depth test function
//depthFuncMode = depthFunc[BIT14(val)];
//depthFuncMode = depthFunc[BIT14(polyAttr)];
//// back face culling
//cullingMask = (val&0xC0);
cullingMask = (polyAttr>>6)&3;
// Alpha value, actually not well handled, 0 should be wireframe
colorRGB[3] = colorAlpha = material_5bit_to_31bit[((val>>16)&0x1F)];
colorRGB[3] = colorAlpha = ((polyAttr>>16)&0x1F);
//// polyID
//polyID = (val>>24)&0x1F;
//polyID = (polyAttr>>24)&0x1F;
}
void gfx3d_glPolygonAttrib (unsigned long val)
{
polyAttr = val;
InstallPolygonAttrib(polyAttr);
gfx3d_glPolygonAttrib_cache();
}
/*
@ -698,21 +685,11 @@ void gfx3d_glMaterial0(unsigned long val)
dsDiffuse = val&0xFFFF;
dsAmbient = val>>16;
diffuse[0] = material_5bit_to_31bit[(val)&0x1F];
diffuse[1] = material_5bit_to_31bit[(val>>5)&0x1F];
diffuse[2] = material_5bit_to_31bit[(val>>10)&0x1F];
diffuse[3] = 0x7fffffff;
ambient[0] = material_5bit_to_31bit[(val>>16)&0x1F];
ambient[1] = material_5bit_to_31bit[(val>>21)&0x1F];
ambient[2] = material_5bit_to_31bit[(val>>26)&0x1F];
ambient[3] = 0x7fffffff;
if (BIT15(val))
{
colorRGB[0] = diffuse[0];
colorRGB[1] = diffuse[1];
colorRGB[2] = diffuse[2];
colorRGB[0] = (val)&0x1F;
colorRGB[1] = (val>>5)&0x1F;
colorRGB[2] = (val>>10)&0x1F;
}
}
@ -720,16 +697,6 @@ void gfx3d_glMaterial1(unsigned long val)
{
dsSpecular = val&0xFFFF;
dsEmission = val>>16;
specular[0] = material_5bit_to_31bit[(val)&0x1F];
specular[1] = material_5bit_to_31bit[(val>>5)&0x1F];
specular[2] = material_5bit_to_31bit[(val>>10)&0x1F];
specular[3] = 0x7fffffff;
emission[0] = material_5bit_to_31bit[(val>>16)&0x1F];
emission[1] = material_5bit_to_31bit[(val>>21)&0x1F];
emission[2] = material_5bit_to_31bit[(val>>26)&0x1F];
emission[3] = 0x7fffffff;
}
void gfx3d_glShininess (unsigned long val)
@ -745,11 +712,14 @@ void gfx3d_UpdateToonTable(void* toonTable)
gfx3d.rgbToonTable[i] = RGB15TO32(u16toonTable[i],255);
}
static void gfx3d_glTexImage_cache()
{
texCoordinateTransform = (textureFormat>>30);
}
void gfx3d_glTexImage(unsigned long val)
{
textureFormat = val;
texCoordinateTransform = (val>>30);
gfx3d_glTexImage_cache();
}
void gfx3d_glTexPalette(unsigned long val)
@ -837,13 +807,13 @@ void gfx3d_glNormal(unsigned long v)
continue;
{
u8 lightColor[3] = {
(g_lightInfo[i].color)&0x1F,
(g_lightInfo[i].color>>5)&0x1F,
(g_lightInfo[i].color>>10)&0x1F };
u8 _lightColor[3] = {
(lightColor[i])&0x1F,
(lightColor[i]>>5)&0x1F,
(lightColor[i]>>10)&0x1F };
float dot = Vector3Dot(g_lightInfo[i].floatDirection,normal);
float diffuseComponent = max(0,dot);
float dot = Vector3Dot(cacheLightDirection[i],normal);
float diffuseComponent = std::max(0.f,dot);
float specularComponent;
//a specular formula which I couldnt get working
@ -863,28 +833,28 @@ void gfx3d_glNormal(unsigned long v)
//a specular formula which seems to work
float temp[4];
float diff = Vector3Dot(normal,g_lightInfo[i].floatDirection);
float diff = Vector3Dot(normal,cacheLightDirection[i]);
Vector3Copy(temp,normal);
Vector3Scale(temp,-2*diff);
Vector3Add(temp,g_lightInfo[i].floatDirection);
Vector3Add(temp,cacheLightDirection[i]);
Vector3Scale(temp,-1);
specularComponent = max(0,Vector3Dot(lineOfSight,temp));
specularComponent = std::max(0.f,Vector3Dot(lineOfSight,temp));
//if the game isnt producing unit normals, then we can accidentally out of range components. so lets saturate them here
//so we can at least keep for crashing. we're not sure what the hardware does in this case, but the game shouldnt be doing this.
specularComponent = max(0,min(1,specularComponent));
diffuseComponent = max(0,min(1,diffuseComponent));
specularComponent = std::max(0.f,std::min(1.f,specularComponent));
diffuseComponent = std::max(0.f,std::min(1.f,diffuseComponent));
for(c=0;c<3;c++) {
vertexColor[c] += (diffuseComponent*lightColor[c]*diffuse[c])/31;
vertexColor[c] += (specularComponent*lightColor[c]*specular[c])/31;
vertexColor[c] += ((float)lightColor[c]*ambient[c])/31;
vertexColor[c] += (diffuseComponent*_lightColor[c]*diffuse[c])/31;
vertexColor[c] += (specularComponent*_lightColor[c]*specular[c])/31;
vertexColor[c] += ((float)_lightColor[c]*ambient[c])/31;
}
}
}
for(c=0;c<3;c++)
colorRGB[c] = material_5bit_to_31bit[min(31,vertexColor[c])];
colorRGB[c] = std::min(31,vertexColor[c]);
}
}
@ -905,6 +875,16 @@ signed long gfx3d_GetDirectionalMatrix (unsigned int index)
return (signed long)(mtxCurrent[2][(index)*(1<<12)]);
}
void gfx3d_glLightDirection_cache(int index)
{
u32 v = lightDirection[index];
// Convert format into floating point value
cacheLightDirection[index][0] = -normalTable[v&1023];
cacheLightDirection[index][1] = -normalTable[(v>>10)&1023];
cacheLightDirection[index][2] = -normalTable[(v>>20)&1023];
cacheLightDirection[index][3] = 0;
}
/*
0-9 Directional Vector's X component (1bit sign + 9bit fractional part)
@ -912,30 +892,18 @@ signed long gfx3d_GetDirectionalMatrix (unsigned int index)
20-29 Directional Vector's Z component (1bit sign + 9bit fractional part)
30-31 Light Number (0..3)
*/
void gfx3d_glLightDirection (unsigned long v)
void gfx3d_glLightDirection (u32 v)
{
int index = v>>30;
float direction[4];
int index = v>>30;
// Convert format into floating point value
g_lightInfo[index].floatDirection[0] = -normalTable[v&1023];
g_lightInfo[index].floatDirection[1] = -normalTable[(v>>10)&1023];
g_lightInfo[index].floatDirection[2] = -normalTable[(v>>20)&1023];
g_lightInfo[index].floatDirection[3] = 0;
// Keep information for fightDirection function
g_lightInfo[index].direction = v;
lightDirection[index] = v;
gfx3d_glLightDirection_cache(index);
}
void gfx3d_glLightColor (unsigned long v)
{
int lightColor[4] = { ((v) &0x1F)<<26,
((v>> 5)&0x1F)<<26,
((v>>10)&0x1F)<<26,
0x7fffffff};
int index = v>>30;
g_lightInfo[index].color = v;
lightColor[index] = v;
}
void gfx3d_glAlphaFunc(unsigned long v)
@ -1436,34 +1404,42 @@ void gfx3d_VBlankSignal()
gpu3D->NDS_3D_Render();
}
void gfx3d_Control(unsigned long v)
void gfx3d_Control_cache()
{
if(v&1) gfx3d.enableTexturing = true;
else gfx3d.enableTexturing = false;
u32 v = control;
if(v&1) gfx3d.enableTexturing = TRUE;
else gfx3d.enableTexturing = FALSE;
if((v>>1)&1) gfx3d.shading = GFX3D::HIGHLIGHT;
else gfx3d.shading = GFX3D::TOON;
if((v>>2)&1) gfx3d.enableAlphaTest = true;
else gfx3d.enableAlphaTest = false;
if((v>>2)&1) gfx3d.enableAlphaTest = TRUE;
else gfx3d.enableAlphaTest = FALSE;
if((v>>3)&1) gfx3d.enableAlphaBlending = true;
else gfx3d.enableAlphaBlending = false;
if((v>>3)&1) gfx3d.enableAlphaBlending = TRUE;
else gfx3d.enableAlphaBlending = FALSE;
if((v>>4)&1) gfx3d.enableAntialiasing = true;
else gfx3d.enableAntialiasing = false;
if((v>>4)&1) gfx3d.enableAntialiasing = TRUE;
else gfx3d.enableAntialiasing = FALSE;
if((v>>5)&1) gfx3d.enableEdgeMarking = true;
else gfx3d.enableEdgeMarking = false;
if((v>>5)&1) gfx3d.enableEdgeMarking = TRUE;
else gfx3d.enableEdgeMarking = FALSE;
//other junk
if (v&(1<<14))
{
LOG("Enabled BITMAP background mode\n");
}
}
void gfx3d_Control(u32 v)
{
control = v;
gfx3d_Control_cache();
}
//--------------
//other misc stuff
void gfx3d_glGetMatrix(unsigned int mode, unsigned int index, float* dest)
@ -1481,15 +1457,115 @@ void gfx3d_glGetMatrix(unsigned int mode, unsigned int index, float* dest)
void gfx3d_glGetLightDirection(unsigned int index, unsigned int* dest)
{
*dest = g_lightInfo[index].direction;
*dest = lightDirection[index];
}
void gfx3d_glGetLightColor(unsigned int index, unsigned int* dest)
{
*dest = g_lightInfo[index].color;
*dest = lightColor[index];
}
//http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node17.html
//talks about the state required to process verts in quadlists etc. helpful ideas.
//consider building a little state structure that looks exactly like this describes
SFORMAT SF_GFX3D[]={
{ &control, 4|SS_RLSB, "GCTL" },
{ &polyAttr, 4|SS_RLSB, "GPAT" },
{ &textureFormat, 4|SS_RLSB, "GTFM" },
{ &texturePalette, 4|SS_RLSB, "GTPA" },
{ &mode, 4|SS_RLSB, "GMOD" },
{ mtxTemporal, 4|SS_MULT(16), "GMTM" },
{ mtxCurrent, 4|SS_MULT(64), "GMCU" },
{ &mtxStack[0].position, 4|SS_RLSB, "GM0P" },
{ mtxStack[0].matrix, 4|SS_MULT(16), "GM1M" },
{ &mtxStack[1].position, 4|SS_RLSB, "GM1P" },
{ mtxStack[1].matrix, 4|SS_MULT(16*31), "GM1M" },
{ &mtxStack[2].position, 4|SS_RLSB, "GM2P" },
{ mtxStack[2].matrix, 4|SS_MULT(16*31), "GM2M" },
{ &mtxStack[3].position, 4|SS_RLSB, "GM3P" },
{ mtxStack[3].matrix, 4|SS_MULT(16), "GM3M" },
{ &ML4x4ind, 1, "ML4I" },
{ &ML4x3_c, 1, "ML3C" },
{ &ML4x3_l, 1, "ML3L" },
{ &MM4x4ind, 1, "MM4I" },
{ &MM4x3_c, 1, "MM3C" },
{ &MM4x3_l, 1, "MM3L" },
{ &MM3x3_c, 1, "MMxC" },
{ &MM3x3_l, 1, "MMxL" },
{ coord, 4|SS_MULT(4), "GCOR" },
{ &coordind, 1, "GCOI" },
{ &vtxFormat, 4|SS_RLSB, "GCOI" },
{ trans, 4|SS_MULT(4), "GTRN" },
{ &transind, 1, "GTRI" },
{ scale, 4|SS_MULT(4), "GSCA" },
{ &scaleind, 1, "GSCI" },
{ &_t, 4|SS_RLSB, "G_T_" },
{ &_s, 4|SS_RLSB, "G_S_" },
{ &last_t, 4|SS_RLSB, "GL_T" },
{ &last_s, 4|SS_RLSB, "GL_S" },
{ &clCmd, 4|SS_RLSB, "GLCM" },
{ &clInd, 4|SS_RLSB, "GLIN" },
{ &clInd2, 4|SS_RLSB, "GLI2" },
{ colorRGB, 4, "GCOL" },
{ lightColor, 4|SS_MULT(4), "GLCO" },
{ lightDirection, 4|SS_MULT(4), "GLDI" },
{ &dsDiffuse, 2|SS_RLSB, "GMDI" },
{ &dsAmbient, 2|SS_RLSB, "GMAM" },
{ &dsSpecular, 2|SS_RLSB, "GMSP" },
{ &dsEmission, 2|SS_RLSB, "GMEM" },
{ &triStripToggle, 4|SS_RLSB, "GTST" },
{ &listTwiddle, 4|SS_RLSB, "GLTW" },
{ &gfx3d.enableTexturing, 4|SS_RLSB, "GSET" },
{ &gfx3d.enableAlphaTest, 4|SS_RLSB, "GSEA" },
{ &gfx3d.enableAlphaBlending, 4|SS_RLSB, "GSEB" },
{ &gfx3d.enableAntialiasing, 4|SS_RLSB, "GSEX" },
{ &gfx3d.enableEdgeMarking, 4|SS_RLSB, "GSEE" },
{ &gfx3d.shading, 4|SS_RLSB, "GSSH" },
{ &gfx3d.wbuffer, 4|SS_RLSB, "GSWB" },
{ &gfx3d.sortmode, 4|SS_RLSB, "GSSM" },
{ &gfx3d.alphaTestRef, 4|SS_RLSB, "GSAR" },
{ &gfx3d.viewport.x, 4|SS_RLSB, "GSVX" },
{ &gfx3d.viewport.y, 4|SS_RLSB, "GSVY" },
{ &gfx3d.viewport.width, 4|SS_RLSB, "GSVW" },
{ &gfx3d.viewport.height, 4|SS_RLSB, "GSVH" },
{ gfx3d.clearColor, 4|SS_MULT(4), "GSCC" },
{ &gfx3d.clearDepth , 4|SS_RLSB, "GSCD" },
{ gfx3d.fogColor, 4|SS_MULT(4), "GSFC" },
{ &gfx3d.fogOffset, 4|SS_RLSB, "GSFO" },
{ gfx3d.rgbToonTable, 4|SS_MULT(32), "GSTT" },
{ 0 }
};
//-------------savestate
void gfx3d_savestate(std::ostream* os)
{
//dump the render lists
//TODO!!!!
}
bool gfx3d_loadstate(std::istream* is)
{
gfx3d_glPolygonAttrib_cache();
gfx3d_glTexImage_cache();
gfx3d_Control_cache();
gfx3d_glLightDirection_cache(0);
gfx3d_glLightDirection_cache(1);
gfx3d_glLightDirection_cache(2);
gfx3d_glLightDirection_cache(3);
//jiggle the lists. and also wipe them. this is clearly not the best thing to be doing.
polylist = &polylists[listTwiddle];
vertlist = &vertlists[listTwiddle];
polylist->count = 0;
vertlist->count = 0;
gfx3d.polylist = &polylists[listTwiddle^1];
gfx3d.vertlist = &vertlists[listTwiddle^1];
gfx3d.polylist->count=0;
gfx3d.vertlist->count=0;
return true;
}

View File

@ -22,6 +22,7 @@
#define _GFX3D_H_
#include "types.h"
#include <iosfwd>
void gfx3d_init();
void gfx3d_reset();
@ -47,7 +48,7 @@ struct POLY {
}
};
#define POLYLIST_SIZE 6000
#define POLYLIST_SIZE 100000
//#define POLYLIST_SIZE 2048
struct POLYLIST {
int count;
@ -57,11 +58,11 @@ struct POLYLIST {
struct VERT {
float coord[4];
float texcoord[2];
int color[4];
u8 color[4];
u32 depth;
};
#define VERTLIST_SIZE 30000
#define VERTLIST_SIZE 400000
//#define VERTLIST_SIZE 10000
struct VERTLIST {
int count;
@ -84,10 +85,12 @@ struct GFX3D
, clearDepth(1)
{
clearColor[0] = clearColor[1] = clearColor[2] = clearColor[3] = 0;
fogColor[0] = fogColor[1] = fogColor[2] = fogColor[3] = 0;
fogOffset = 0;
}
bool enableTexturing, enableAlphaTest, enableAlphaBlending, enableAntialiasing, enableEdgeMarking;
BOOL enableTexturing, enableAlphaTest, enableAlphaBlending, enableAntialiasing, enableEdgeMarking;
enum {
enum : u32 {
TOON, HIGHLIGHT
} shading;
@ -95,7 +98,7 @@ struct GFX3D
VERTLIST* vertlist;
int indexlist[POLYLIST_SIZE];
bool wbuffer, sortmode;
BOOL wbuffer, sortmode;
float alphaTestRef;
@ -108,6 +111,9 @@ struct GFX3D
float clearColor[4];
float clearDepth;
float fogColor[4];
float fogOffset;
u32 rgbToonTable[32];
};
@ -187,5 +193,9 @@ void gfx3d_glGetMatrix(unsigned int mode, unsigned int index, float* dest);
void gfx3d_glGetLightDirection(unsigned int index, unsigned int* dest);
void gfx3d_glGetLightColor(unsigned int index, unsigned int* dest);
struct SFORMAT;
extern SFORMAT SF_GFX3D[];
void gfx3d_savestate(std::ostream* os);
bool gfx3d_loadstate(std::istream* is);
#endif

303
desmume/src/memorystream.h Normal file
View File

@ -0,0 +1,303 @@
#ifndef _memorystream_h_
#define _memorystream_h_
#include <iostream>
#include <string.h>
#include <vector>
#include <sstream>
#include <stdexcept>
#include <algorithm>
template<typename T>
class memory_streambuf: public std::streambuf {
private:
friend class memorystream;
//the current buffer
T* buf;
//the current allocated capacity of the buffer
size_t capacity;
//whether the sequence is owned by the stringbuf
bool myBuf;
//the logical length of the buffer
size_t length;
//the current 'write window' starting position within the buffer for writing.
size_t ww;
//a vector that we have been told to use
std::vector<T>* usevec;
public:
memory_streambuf(int _capacity)
: buf(new T[capacity=_capacity])
, myBuf(true)
, length(_capacity)
, ww(0)
, usevec(0)
{
sync();
}
memory_streambuf()
: buf(new T[capacity = 128])
, myBuf(true)
, length(0)
, ww(0)
, usevec(0)
{
sync();
}
//constructs a non-expandable streambuf around the provided buffer
memory_streambuf(T* usebuf, int buflength)
: buf(usebuf)
, myBuf(false)
, length(buflength)
, ww(0)
, usevec(0)
{
sync();
}
//constructs an expandable streambuf around the provided buffer
memory_streambuf(std::vector<T>* _usevec)
: capacity(_usevec->size())
, myBuf(false)
, length(_usevec->size())
, ww(0)
, usevec(_usevec)
{
if(length>0)
buf = &(*_usevec)[0];
else buf = 0;
sync();
}
~memory_streambuf()
{
//only cleanup if we own the seq
if(myBuf) delete[] buf;
}
//the logical length of the buffer
size_t size()
{
sync();
return length;
}
//to avoid copying, rebuilds the provided vector and copies the streambuf contents into it
void toVector(std::vector<T>& out)
{
out.resize(length);
memcpy(&out[0],buf,length);
}
//maybe the compiler can avoid copying, but maybe not: returns a vector representing the current streambuf
std::vector<T> toVector()
{
return std::vector<T>(buf,buf+length);
}
//if the memorystream wraps a vector, the vector will be trimmed to the correct size,.
//you probably need to use this if you are using the vector wrapper
void trim()
{
if(!usevec) return;
usevec->resize(size());
}
//tells the current read or write position
std::streampos tell(std::ios::openmode which)
{
if(which == std::ios::in)
return tellRead();
else if(which == std::ios::out)
return tellWrite();
else return -1;
}
//tells the current read position
std::streampos tellRead()
{
return gptr()-eback();
}
//tells the current write position
std::streampos tellWrite()
{
return pptr()-pbase() + ww;
}
int sync()
{
dosync(-1);
return 0;
}
T* getbuf()
{
sync();
return buf;
}
//if we were provided a buffer, then calling this gives us ownership of it
void giveBuf() {
myBuf = true;
}
private:
void dosync(int c)
{
size_t wp = tellWrite();
size_t rp = tellRead();
//if we are supposed to insert a character..
if(c != -1)
{
buf[wp] = c;
wp++;
}
//the length is determined by the highest character that was ever inserted
length = std::max(length,wp);
//the write window advances to begin at the current write insertion point
ww = wp;
//set the new write and read windows
setp(buf+ww, buf + capacity);
setg(buf, buf+rp, buf + length);
}
void expand(size_t upto)
{
if(!myBuf && !usevec)
throw new std::runtime_error("memory_streambuf is not expandable");
size_t newcapacity;
if(upto == -1)
newcapacity = capacity + capacity/2 + 2;
else
newcapacity = std::max(upto,capacity);
if(newcapacity == capacity) return;
//if we are supposed to use the vector, then do it now
if(usevec)
{
usevec->resize(newcapacity);
capacity = usevec->size();
buf = &(*usevec)[0];
}
else
{
//otherwise, manage our own buffer
T* newbuf = new T[newcapacity];
memcpy(newbuf,buf,capacity);
delete[] buf;
capacity = newcapacity;
buf = newbuf;
}
}
protected:
int overflow(int c)
{
expand(-1);
dosync(c);
return 1;
}
std::streambuf::pos_type seekpos(pos_type pos, std::ios::openmode which)
{
//extend if we are seeking the write cursor
if(which & std::ios_base::out)
expand(pos);
sync();
if(which & std::ios_base::in)
setg(buf, buf+pos, buf + length);
if(which & std::ios_base::out)
{
ww = pos;
setp(buf+pos, buf + capacity);
}
return pos;
}
pos_type seekoff(off_type off, std::ios::seekdir way, std::ios::openmode which)
{
switch(way) {
case std::ios::beg:
return seekpos(off, which);
case std::ios::cur:
return seekpos(tell(which)+off, which);
case std::ios::end:
return seekpos(length+off, which);
default:
return -1;
}
}
};
//an iostream that uses the memory_streambuf to effectively act much like a c# memorystream
//please call sync() after writing data if you want to read it back
class memorystream : public std::basic_iostream<char, std::char_traits<char> >
{
public:
memorystream()
: std::basic_iostream<char, std::char_traits<char> >(&streambuf)
{}
memorystream(int size)
: std::basic_iostream<char, std::char_traits<char> >(&streambuf)
, streambuf(size)
{}
memorystream(char* usebuf, int buflength)
: std::basic_iostream<char, std::char_traits<char> >(&streambuf)
, streambuf(usebuf, buflength)
{}
memorystream(std::vector<char>* usevec)
: std::basic_iostream<char, std::char_traits<char> >(&streambuf)
, streambuf(usevec)
{}
//the underlying memory_streambuf
memory_streambuf<char> streambuf;
public:
size_t size() { return streambuf.size(); }
char* buf() { return streambuf.getbuf(); }
//flushes all the writing state and ensures the stream is ready for reading
void sync() { streambuf.sync(); }
//rewinds the cursors to offset 0
void rewind() { streambuf.seekpos(0,std::ios::in | std::ios::out); }
//if the memorystream wraps a vector, the vector will be trimmed to the correct size,.
//you probably need to use this if you are using the vector wrapper
void trim() { streambuf.trim(); }
void giveBuf() { streambuf.giveBuf(); }
};
#endif

117
desmume/src/readwrite.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "readwrite.h"
#include "types.h"
///writes a little endian 16bit value to the specified file
int write16le(u16 b, FILE *fp)
{
u8 s[2];
s[0]=b;
s[1]=b>>8;
return((fwrite(s,1,2,fp)<2)?0:2);
}
///writes a little endian 32bit value to the specified file
int write32le(u32 b, FILE *fp)
{
u8 s[4];
s[0]=b;
s[1]=b>>8;
s[2]=b>>16;
s[3]=b>>24;
return((fwrite(s,1,4,fp)<4)?0:4);
}
int write32le(u32 b, std::ostream* os)
{
u8 s[4];
s[0]=b;
s[1]=b>>8;
s[2]=b>>16;
s[3]=b>>24;
os->write((char*)&s,4);
return 4;
}
int write64le(u64 b, std::ostream* os)
{
u8 s[8];
s[0]=b;
s[1]=b>>8;
s[2]=b>>16;
s[3]=b>>24;
s[4]=b>>32;
s[5]=b>>40;
s[6]=b>>48;
s[7]=b>>56;
os->write((char*)&s,8);
return 8;
}
///reads a little endian 32bit value from the specified file
int read32le(u32 *Bufo, FILE *fp)
{
u32 buf;
if(fread(&buf,1,4,fp)<4)
return 0;
#ifdef LOCAL_LE
*(u32*)Bufo=buf;
#else
*(u32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
#endif
return 1;
}
int read16le(u16 *Bufo, std::istream *is)
{
u16 buf;
if(is->read((char*)&buf,2).gcount() != 2)
return 0;
#ifdef LOCAL_LE
*Bufo=buf;
#else
*Bufo = LE_TO_LOCAL_16(buf);
#endif
return 1;
}
///reads a little endian 64bit value from the specified file
int read64le(u64 *Bufo, std::istream *is)
{
u64 buf;
if(is->read((char*)&buf,8).gcount() != 8)
return 0;
#ifdef LOCAL_LE
*Bufo=buf;
#else
*Bufo = LE_TO_LOCAL_64(buf);
#endif
return 1;
}
int read32le(u32 *Bufo, std::istream *is)
{
u32 buf;
if(is->read((char*)&buf,4).gcount() != 4)
return 0;
#ifdef LOCAL_LE
*(u32*)Bufo=buf;
#else
*(u32*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
#endif
return 1;
}
///reads a little endian 16bit value from the specified file
int read16le(char *d, FILE *fp)
{
#ifdef LOCAL_LE
return((fread(d,1,2,fp)<2)?0:2);
#else
int ret;
ret=fread(d+1,1,1,fp);
ret+=fread(d,1,1,fp);
return ret<2?0:2;
#endif
}

16
desmume/src/readwrite.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _READWRITE_H_
#define _READWRITE_H_
#include "types.h"
#include <iostream>
int write16le(u16 b, FILE *fp);
int write32le(u32 b, FILE *fp);
int write32le(u32 b, std::ostream* os);
int write64le(u64 b, std::ostream* os);
int read64le(u64 *Bufo, std::istream *is);
int read32le(u32 *Bufo, std::istream *is);
int read32le(u32 *Bufo, FILE *fp);
int read16le(u16 *Bufo, std::istream *is);
#endif

View File

@ -29,15 +29,137 @@
#include "NDSSystem.h"
#include <sys/stat.h>
#include <time.h>
#include <fstream>
#include "memorystream.h"
#include "readwrite.h"
#include "gfx3d.h"
//void*v is actually a void** which will be indirected before reading
//since this isnt supported right now, it is declared in here to make things compile
#define SS_INDIRECT 0x80000000
savestates_t savestates[NB_STATES];
#define SAVESTATE_VERSION 010
#define SAVESTATE_VERSION 10
static const char* magic = "DeSmuME SState\0";
#ifndef MAX_PATH
#define MAX_PATH 256
#endif
SFORMAT SF_ARM7[]={
{ &NDS_ARM7.instruction, 4|SS_RLSB, "7INS" },
{ &NDS_ARM7.instruct_adr, 4|SS_RLSB, "7INA" },
{ &NDS_ARM7.next_instruction, 4|SS_RLSB, "7INN" },
{ NDS_ARM7.R, 4|SS_MULT(16), "7REG" },
{ &NDS_ARM7.CPSR, 4|SS_RLSB, "7CPS" },
{ &NDS_ARM7.SPSR, 4|SS_RLSB, "7SPS" },
{ &NDS_ARM7.R13_usr, 4|SS_RLSB, "7DUS" },
{ &NDS_ARM7.R14_usr, 4|SS_RLSB, "7EUS" },
{ &NDS_ARM7.R13_svc, 4|SS_RLSB, "7DSV" },
{ &NDS_ARM7.R14_svc, 4|SS_RLSB, "7ESV" },
{ &NDS_ARM7.R13_abt, 4|SS_RLSB, "7DAB" },
{ &NDS_ARM7.R14_abt, 4|SS_RLSB, "7EAB" },
{ &NDS_ARM7.R13_und, 4|SS_RLSB, "7DUN" },
{ &NDS_ARM7.R14_und, 4|SS_RLSB, "7EUN" },
{ &NDS_ARM7.R13_irq, 4|SS_RLSB, "7DIR" },
{ &NDS_ARM7.R14_irq, 4|SS_RLSB, "7EIR" },
{ &NDS_ARM7.R8_fiq, 4|SS_RLSB, "78FI" },
{ &NDS_ARM7.R9_fiq, 4|SS_RLSB, "79FI" },
{ &NDS_ARM7.R10_fiq, 4|SS_RLSB, "7AFI" },
{ &NDS_ARM7.R11_fiq, 4|SS_RLSB, "7BFI" },
{ &NDS_ARM7.R12_fiq, 4|SS_RLSB, "7CFI" },
{ &NDS_ARM7.R13_fiq, 4|SS_RLSB, "7DFI" },
{ &NDS_ARM7.R14_fiq, 4|SS_RLSB, "7EFI" },
{ &NDS_ARM7.SPSR_svc, 4|SS_RLSB, "7SVC" },
{ &NDS_ARM7.SPSR_abt, 4|SS_RLSB, "7ABT" },
{ &NDS_ARM7.SPSR_und, 4|SS_RLSB, "7UND" },
{ &NDS_ARM7.SPSR_irq, 4|SS_RLSB, "7IRQ" },
{ &NDS_ARM7.SPSR_fiq, 4|SS_RLSB, "7FIQ" },
{ &NDS_ARM7.intVector, 4|SS_RLSB, "7int" },
{ &NDS_ARM7.LDTBit, 1, "7LDT" },
{ &NDS_ARM7.waitIRQ, 4|SS_RLSB, "7Wai" },
{ &NDS_ARM7.wIRQ, 4|SS_RLSB, "7wIR" },
{ &NDS_ARM7.wirq, 4|SS_RLSB, "7wir" },
{ 0 }
};
SFORMAT SF_ARM9[]={
{ &NDS_ARM9.instruction, 4|SS_RLSB, "9INS" },
{ &NDS_ARM9.instruct_adr, 4|SS_RLSB, "9INA" },
{ &NDS_ARM9.next_instruction, 4|SS_RLSB, "9INN" },
{ NDS_ARM9.R, 4|SS_MULT(16), "9REG" },
{ &NDS_ARM9.CPSR, 4|SS_RLSB, "9CPS" },
{ &NDS_ARM9.SPSR, 4|SS_RLSB, "9SPS" },
{ &NDS_ARM9.R13_usr, 4|SS_RLSB, "9DUS" },
{ &NDS_ARM9.R14_usr, 4|SS_RLSB, "9EUS" },
{ &NDS_ARM9.R13_svc, 4|SS_RLSB, "9DSV" },
{ &NDS_ARM9.R14_svc, 4|SS_RLSB, "9ESV" },
{ &NDS_ARM9.R13_abt, 4|SS_RLSB, "9DAB" },
{ &NDS_ARM9.R14_abt, 4|SS_RLSB, "9EAB" },
{ &NDS_ARM9.R13_und, 4|SS_RLSB, "9DUN" },
{ &NDS_ARM9.R14_und, 4|SS_RLSB, "9EUN" },
{ &NDS_ARM9.R13_irq, 4|SS_RLSB, "9DIR" },
{ &NDS_ARM9.R14_irq, 4|SS_RLSB, "9EIR" },
{ &NDS_ARM9.R8_fiq, 4|SS_RLSB, "98FI" },
{ &NDS_ARM9.R9_fiq, 4|SS_RLSB, "99FI" },
{ &NDS_ARM9.R10_fiq, 4|SS_RLSB, "9AFI" },
{ &NDS_ARM9.R11_fiq, 4|SS_RLSB, "9BFI" },
{ &NDS_ARM9.R12_fiq, 4|SS_RLSB, "9CFI" },
{ &NDS_ARM9.R13_fiq, 4|SS_RLSB, "9DFI" },
{ &NDS_ARM9.R14_fiq, 4|SS_RLSB, "9EFI" },
{ &NDS_ARM9.SPSR_svc, 4|SS_RLSB, "9SVC" },
{ &NDS_ARM9.SPSR_abt, 4|SS_RLSB, "9ABT" },
{ &NDS_ARM9.SPSR_und, 4|SS_RLSB, "9UND" },
{ &NDS_ARM9.SPSR_irq, 4|SS_RLSB, "9IRQ" },
{ &NDS_ARM9.SPSR_fiq, 4|SS_RLSB, "9FIQ" },
{ &NDS_ARM9.intVector, 4|SS_RLSB, "9int" },
{ &NDS_ARM9.LDTBit, 1, "9LDT" },
{ &NDS_ARM9.waitIRQ, 4|SS_RLSB, "9Wai" },
{ &NDS_ARM9.wIRQ, 4|SS_RLSB, "9wIR" },
{ &NDS_ARM9.wirq, 4|SS_RLSB, "9wir" },
{ 0 }
};
SFORMAT SF_MEM[]={
{ ARM9Mem.ARM9_ITCM, 0x8000, "ITCM" },
{ ARM9Mem.ARM9_DTCM, 0x4000, "DTCM" },
{ ARM9Mem.MAIN_MEM, 0x400000, "WRAM" },
{ ARM9Mem.ARM9_REG, 0x10000, "9REG" },
{ ARM9Mem.ARM9_VMEM, 0x800, "VMEM" },
{ ARM9Mem.ARM9_OAM, 0x800, "OAMS" },
{ ARM9Mem.ARM9_ABG, 0x80000, "ABGM" },
{ ARM9Mem.ARM9_BBG, 0x20000, "BBGM" },
{ ARM9Mem.ARM9_AOBJ, 0x40000, "AOBJ" },
{ ARM9Mem.ARM9_BOBJ, 0x20000, "BOBJ" },
{ ARM9Mem.ARM9_LCD, 0xA4000, "LCDM" },
{ MMU.ARM7_ERAM, 0x10000, "ERAM" },
{ MMU.ARM7_REG, 0x10000, "7REG" },
{ MMU.ARM7_WIRAM, 0x10000, "WIRA" },
{ MMU.SWIRAM, 0x8000, "SWIR" },
{ MMU.CART_RAM, SRAM_SIZE, "SRAM" },
{ 0 }
};
SFORMAT SF_NDS[]={
{ &nds.ARM9Cycle, 4|SS_RLSB, "_9CY" },
{ &nds.ARM7Cycle, 4|SS_RLSB, "_7CY" },
{ &nds.cycles, 4|SS_RLSB, "_CYC" },
{ nds.timerCycle, 4|SS_MULT(8), "_TCY" },
{ nds.timerOver, 4|SS_MULT(8), "_TOV" },
{ &nds.nextHBlank, 4|SS_RLSB, "_NHB" },
{ &nds.VCount, 4|SS_RLSB, "_VCT" },
{ &nds.old, 4|SS_RLSB, "_OLD" },
{ &nds.diff, 4|SS_RLSB, "_DIF" },
{ &nds.lignerendu, 4|SS_RLSB, "_LIG" },
{ &nds.touchX, 2|SS_RLSB, "_TPX" },
{ &nds.touchY, 2|SS_RLSB, "_TPY" },
{ 0 }
};
/* Format time and convert to string */
char * format_time(time_t cal_time)
{
@ -154,262 +276,319 @@ int sram_save (const char *file_name) {
}
int savestate_load (const char *file_name) {
static SFORMAT *CheckS(SFORMAT *sf, u32 tsize, char *desc)
{
while(sf->v)
{
if(sf->s==~0) // Link to another SFORMAT structure.
{
SFORMAT *tmp;
if((tmp= CheckS((SFORMAT *)sf->v, tsize, desc) ))
return(tmp);
sf++;
continue;
}
if(!memcmp(desc,sf->desc,4))
{
if(tsize!=(sf->s))
return(0);
return(sf);
}
sf++;
}
return(0);
}
static bool ReadStateChunk(std::istream* is, SFORMAT *sf, int size)
{
SFORMAT *tmp;
int temp = is->tellg();
while(is->tellg()<temp+size)
{
u32 tsize;
char toa[4];
is->read(toa,4);
if(is->fail())
return false;
read32le(&tsize,is);
if((tmp=CheckS(sf,tsize,toa)))
{
int count = SS_UNMULT(tsize);
int size = tsize & ~SS_FLAGS;
bool rlsb = (count!=0);
if(count == 0) count=1;
for(int i=0;i<count;i++) {
if(tmp->s&SS_INDIRECT)
is->read(*(char **)tmp->v,size);
else
is->read((char *)tmp->v + i*size,size);
#ifndef LOCAL_LE
if(rlsb)
FlipByteOrder((u8*)tmp->v + i*size,size);
#endif
}
}
else
is->seekg(tsize,std::ios::cur);
} // while(...)
return true;
}
static int SubWrite(std::ostream* os, SFORMAT *sf)
{
uint32 acc=0;
while(sf->v)
{
if(sf->s==~0) //Link to another struct
{
uint32 tmp;
if(!(tmp=SubWrite(os,(SFORMAT *)sf->v)))
return(0);
acc+=tmp;
sf++;
continue;
}
int count = SS_UNMULT(sf->s);
int size = sf->s & ~SS_FLAGS;
bool rlsb = (count!=0);
acc+=8; //Description + size
if(count==0) count=1;
acc += count * size;
if(os) //Are we writing or calculating the size of this block?
{
os->write(sf->desc,4);
write32le(sf->s,os);
for(int i=0;i<count;i++) {
#ifndef LOCAL_LE
if(rlsb)
FlipByteOrder(sf->v,sf->s&(~SS_FLAGS));
#endif
if(sf->s&SS_INDIRECT)
os->write(*(char **)sf->v,size);
else
os->write((char*)sf->v + i*size,size);
//Now restore the original byte order.
#ifndef LOCAL_LE
if(rlsb)
FlipByteOrder(sf->v,sf->s&(~SS_FLAGS));
#endif
}
}
sf++;
}
return(acc);
}
static int savestate_WriteChunk(std::ostream* os, int type, SFORMAT *sf)
{
write32le(type,os);
if(!sf) return 4;
int bsize = SubWrite((std::ostream*)0,sf);
write32le(bsize,os);
FILE* outf;
if(!SubWrite(os,sf))
{
return 8;
}
return (bsize+8);
}
static void savestate_WriteChunk(std::ostream* os, int type, void (*saveproc)(std::ostream* os))
{
//get the size
memorystream mstemp;
saveproc(&mstemp);
mstemp.flush();
u32 size = mstemp.size();
//write the type, size, and data
write32le(type,os);
write32le(size,os);
os->write(mstemp.buf(),size);
}
static void writechunks(std::ostream* os);
bool savestate_save(std::ostream* outstream, int compressionLevel)
{
//generate the savestate in memory first
memorystream ms;
std::ostream* os = (std::ostream*)&ms;
writechunks(os);
ms.flush();
//save the length of the file
u32 len = ms.size();
u32 comprlen = -1;
u8* cbuf = (u8*)ms.buf();
#ifdef HAVE_LIBZ
gzFile file;
char idstring[30];
u8 version;
int i;
//compress the data
int error = Z_OK;
if(compressionLevel != Z_NO_COMPRESSION)
{
//worst case compression.
//zlib says "0.1% larger than sourceLen plus 12 bytes"
comprlen = (len>>9)+12 + len;
cbuf = new u8[comprlen];
error = compress2(cbuf,&comprlen,(u8*)ms.buf(),len,compressionLevel);
}
#endif
file = gzopen( file_name, "rb" );
if( file == NULL )
return 0;
//dump the header
outstream->write(magic,16);
write32le(SAVESTATE_VERSION,outstream);
write32le(DESMUME_VERSION_NUMERIC,outstream); //desmume version
write32le(len,outstream); //uncompressed length
write32le(comprlen,outstream); //compressed length (-1 if it is not compressed)
outstream->write((char*)cbuf,comprlen==-1?len:comprlen);
if(cbuf != (uint8*)ms.buf()) delete[] cbuf;
return error == Z_OK;
}
memset(idstring, 0, 30);
gzgets(file, idstring, 23);
bool savestate_save (const char *file_name)
{
memorystream ms;
if(!savestate_save(&ms, Z_DEFAULT_COMPRESSION))
return false;
ms.flush();
FILE* file = fopen(file_name,"wb");
if(file)
{
fwrite(ms.buf(),1,ms.size(),file);
fclose(file);
return true;
} else return false;
}
if (strncmp("DeSmuME Savestate File", idstring, 22) != 0)
{
gzclose (file);
return 0;
}
//u8 GPU_screen[4*256*192];
version = gzgetc(file);
static void writechunks(std::ostream* os) {
savestate_WriteChunk(os,1,SF_ARM9);
savestate_WriteChunk(os,2,SF_ARM7);
savestate_WriteChunk(os,3,SF_MEM);
savestate_WriteChunk(os,4,SF_NDS);
savestate_WriteChunk(os,5,gpu_savestate);
savestate_WriteChunk(os,60,SF_GFX3D);
savestate_WriteChunk(os,61,gfx3d_savestate);
savestate_WriteChunk(os,0xFFFFFFFF,(SFORMAT*)0);
}
// Read ARM7 cpu registers
gzread(file, &NDS_ARM7.proc_ID, sizeof(u32));
gzread(file, &NDS_ARM7.instruction, sizeof(u32));
gzread(file, &NDS_ARM7.instruct_adr, sizeof(u32));
gzread(file, &NDS_ARM7.next_instruction, sizeof(u32));
gzread(file, NDS_ARM7.R, sizeof(u32) * 16);
gzread(file, &NDS_ARM7.CPSR, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.SPSR, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.R13_usr, sizeof(u32));
gzread(file, &NDS_ARM7.R14_usr, sizeof(u32));
gzread(file, &NDS_ARM7.R13_svc, sizeof(u32));
gzread(file, &NDS_ARM7.R14_svc, sizeof(u32));
gzread(file, &NDS_ARM7.R13_abt, sizeof(u32));
gzread(file, &NDS_ARM7.R14_abt, sizeof(u32));
gzread(file, &NDS_ARM7.R13_und, sizeof(u32));
gzread(file, &NDS_ARM7.R14_und, sizeof(u32));
gzread(file, &NDS_ARM7.R13_irq, sizeof(u32));
gzread(file, &NDS_ARM7.R14_irq, sizeof(u32));
gzread(file, &NDS_ARM7.R8_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R9_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R10_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R11_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R12_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R13_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.R14_fiq, sizeof(u32));
gzread(file, &NDS_ARM7.SPSR_svc, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.SPSR_abt, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.SPSR_und, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.SPSR_irq, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.SPSR_fiq, sizeof(Status_Reg));
gzread(file, &NDS_ARM7.intVector, sizeof(u32));
gzread(file, &NDS_ARM7.LDTBit, sizeof(u8));
gzread(file, &NDS_ARM7.waitIRQ, sizeof(BOOL));
gzread(file, &NDS_ARM7.wIRQ, sizeof(BOOL));
gzread(file, &NDS_ARM7.wirq, sizeof(BOOL));
static bool ReadStateChunks(std::istream* is, s32 totalsize)
{
bool ret = true;
while(totalsize > 0)
{
uint32 size;
u32 t;
if(!read32le(&t,is)) { ret=false; break; }
if(t == 0xFFFFFFFF) goto done;
if(!read32le(&size,is)) { ret=false; break; }
switch(t)
{
case 1: if(!ReadStateChunk(is,SF_ARM9,size)) ret=false; break;
case 2: if(!ReadStateChunk(is,SF_ARM7,size)) ret=false; break;
case 3: if(!ReadStateChunk(is,SF_MEM,size)) ret=false; break;
case 4: if(!ReadStateChunk(is,SF_NDS,size)) ret=false; break;
case 5: if(!gpu_loadstate(is)) ret=false; break;
case 60: if(!ReadStateChunk(is,SF_GFX3D,size)) ret=false; break;
case 61: if(!gfx3d_loadstate(is)) ret=false; break;
default:
ret=false;
break;
}
if(!ret) return false;
}
done:
// Read ARM9 cpu registers
gzread(file, &NDS_ARM9.proc_ID, sizeof(u32));
gzread(file, &NDS_ARM9.instruction, sizeof(u32));
gzread(file, &NDS_ARM9.instruct_adr, sizeof(u32));
gzread(file, &NDS_ARM9.next_instruction, sizeof(u32));
gzread(file, NDS_ARM9.R, sizeof(u32) * 16);
gzread(file, &NDS_ARM9.CPSR, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.SPSR, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.R13_usr, sizeof(u32));
gzread(file, &NDS_ARM9.R14_usr, sizeof(u32));
gzread(file, &NDS_ARM9.R13_svc, sizeof(u32));
gzread(file, &NDS_ARM9.R14_svc, sizeof(u32));
gzread(file, &NDS_ARM9.R13_abt, sizeof(u32));
gzread(file, &NDS_ARM9.R14_abt, sizeof(u32));
gzread(file, &NDS_ARM9.R13_und, sizeof(u32));
gzread(file, &NDS_ARM9.R14_und, sizeof(u32));
gzread(file, &NDS_ARM9.R13_irq, sizeof(u32));
gzread(file, &NDS_ARM9.R14_irq, sizeof(u32));
gzread(file, &NDS_ARM9.R8_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R9_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R10_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R11_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R12_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R13_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.R14_fiq, sizeof(u32));
gzread(file, &NDS_ARM9.SPSR_svc, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.SPSR_abt, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.SPSR_und, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.SPSR_irq, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.SPSR_fiq, sizeof(Status_Reg));
gzread(file, &NDS_ARM9.intVector, sizeof(u32));
gzread(file, &NDS_ARM9.LDTBit, sizeof(u8));
gzread(file, &NDS_ARM9.waitIRQ, sizeof(BOOL));
gzread(file, &NDS_ARM9.wIRQ, sizeof(BOOL));
gzread(file, &NDS_ARM9.wirq, sizeof(BOOL));
return ret;
}
// Read in other internal variables that are important
gzread (file, &nds, sizeof(NDSSystem));
static void loadstate()
{
// This should regenerate the vram banks
for (int i = 0; i < 0xA; i++)
MMU_write8(ARMCPU_ARM9, 0x04000240+i, MMU_read8(ARMCPU_ARM9, 0x04000240+i));
// Read in memory/registers specific to the ARM9
gzread (file, ARM9Mem.ARM9_ITCM, 0x8000);
gzread (file ,ARM9Mem.ARM9_DTCM, 0x4000);
gzread (file ,ARM9Mem.ARM9_WRAM, 0x1000000);
gzread (file, ARM9Mem.MAIN_MEM, 0x400000);
gzread (file, ARM9Mem.ARM9_REG, 0x10000);
gzread (file, ARM9Mem.ARM9_VMEM, 0x800);
gzread (file, ARM9Mem.ARM9_OAM, 0x800);
gzread (file, ARM9Mem.ARM9_ABG, 0x80000);
gzread (file, ARM9Mem.ARM9_BBG, 0x20000);
gzread (file, ARM9Mem.ARM9_AOBJ, 0x40000);
gzread (file, ARM9Mem.ARM9_BOBJ, 0x20000);
gzread (file, ARM9Mem.ARM9_LCD, 0xA4000);
// Read in memory/registers specific to the ARM7
gzread (file, MMU.ARM7_ERAM, 0x10000);
gzread (file, MMU.ARM7_REG, 0x10000);
gzread (file, MMU.ARM7_WIRAM, 0x10000);
// Read in shared memory
gzread (file, MMU.SWIRAM, 0x8000);
// Internal variable states should be regenerated
// This should regenerate the vram banks
for (i = 0; i < 0xA; i++)
MMU_write8(ARMCPU_ARM9, 0x04000240+i, MMU_read8(ARMCPU_ARM9, 0x04000240+i));
// This should regenerate the graphics power control register
MMU_write16(ARMCPU_ARM9, 0x04000304, MMU_read16(ARMCPU_ARM9, 0x04000304));
// This should regenerate the graphics power control register
MMU_write16(ARMCPU_ARM9, 0x04000304, MMU_read16(ARMCPU_ARM9, 0x04000304));
// This should regenerate the graphics configuration
for (i = REG_BASE_DISPA; i<=REG_BASE_DISPA + 0x7F; i+=2)
MMU_write16(ARMCPU_ARM9, i, MMU_read16(ARMCPU_ARM9, i));
for (i = REG_BASE_DISPB; i<=REG_BASE_DISPB + 0x7F; i+=2)
MMU_write16(ARMCPU_ARM9, i, MMU_read16(ARMCPU_ARM9, i));
gzclose (file);
return 1;
#else
return 0;
#endif
for (int i = REG_BASE_DISPA; i<=REG_BASE_DISPA + 0x7F; i+=2)
MMU_write16(ARMCPU_ARM9, i, MMU_read16(ARMCPU_ARM9, i));
for (int i = REG_BASE_DISPB; i<=REG_BASE_DISPB + 0x7F; i+=2)
MMU_write16(ARMCPU_ARM9, i, MMU_read16(ARMCPU_ARM9, i));
}
int savestate_save (const char *file_name) {
#ifdef HAVE_LIBZ
gzFile file;
bool savestate_load(std::istream* is)
{
char header[16];
is->read(header,16);
if(is->fail() || memcmp(header,magic,16))
return false;
file = gzopen( file_name, "wb" );
if( file == NULL )
return 0;
u32 ssversion,dversion,len,comprlen;
if(!read32le(&ssversion,is)) return false;
if(!read32le(&dversion,is)) return false;
if(!read32le(&len,is)) return false;
if(!read32le(&comprlen,is)) return false;
gzputs(file, "DeSmuME Savestate File");
gzputc(file, SAVESTATE_VERSION);
if(ssversion != SAVESTATE_VERSION) return false;
// Save ARM7 cpu registers
gzwrite(file, &NDS_ARM7.proc_ID, sizeof(u32));
gzwrite(file, &NDS_ARM7.instruction, sizeof(u32));
gzwrite(file, &NDS_ARM7.instruct_adr, sizeof(u32));
gzwrite(file, &NDS_ARM7.next_instruction, sizeof(u32));
gzwrite(file, NDS_ARM7.R, sizeof(u32) * 16);
gzwrite(file, &NDS_ARM7.CPSR, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.SPSR, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.R13_usr, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_usr, sizeof(u32));
gzwrite(file, &NDS_ARM7.R13_svc, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_svc, sizeof(u32));
gzwrite(file, &NDS_ARM7.R13_abt, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_abt, sizeof(u32));
gzwrite(file, &NDS_ARM7.R13_und, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_und, sizeof(u32));
gzwrite(file, &NDS_ARM7.R13_irq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_irq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R8_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R9_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R10_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R11_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R12_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R13_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.R14_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM7.SPSR_svc, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.SPSR_abt, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.SPSR_und, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.SPSR_irq, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.SPSR_fiq, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM7.intVector, sizeof(u32));
gzwrite(file, &NDS_ARM7.LDTBit, sizeof(u8));
gzwrite(file, &NDS_ARM7.waitIRQ, sizeof(BOOL));
gzwrite(file, &NDS_ARM7.wIRQ, sizeof(BOOL));
gzwrite(file, &NDS_ARM7.wirq, sizeof(BOOL));
std::vector<char> buf(len);
// Save ARM9 cpu registers
gzwrite(file, &NDS_ARM9.proc_ID, sizeof(u32));
gzwrite(file, &NDS_ARM9.instruction, sizeof(u32));
gzwrite(file, &NDS_ARM9.instruct_adr, sizeof(u32));
gzwrite(file, &NDS_ARM9.next_instruction, sizeof(u32));
gzwrite(file, NDS_ARM9.R, sizeof(u32) * 16);
gzwrite(file, &NDS_ARM9.CPSR, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.SPSR, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.R13_usr, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_usr, sizeof(u32));
gzwrite(file, &NDS_ARM9.R13_svc, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_svc, sizeof(u32));
gzwrite(file, &NDS_ARM9.R13_abt, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_abt, sizeof(u32));
gzwrite(file, &NDS_ARM9.R13_und, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_und, sizeof(u32));
gzwrite(file, &NDS_ARM9.R13_irq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_irq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R8_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R9_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R10_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R11_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R12_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R13_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.R14_fiq, sizeof(u32));
gzwrite(file, &NDS_ARM9.SPSR_svc, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.SPSR_abt, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.SPSR_und, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.SPSR_irq, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.SPSR_fiq, sizeof(Status_Reg));
gzwrite(file, &NDS_ARM9.intVector, sizeof(u32));
gzwrite(file, &NDS_ARM9.LDTBit, sizeof(u8));
gzwrite(file, &NDS_ARM9.waitIRQ, sizeof(BOOL));
gzwrite(file, &NDS_ARM9.wIRQ, sizeof(BOOL));
gzwrite(file, &NDS_ARM9.wirq, sizeof(BOOL));
if(comprlen != 0xFFFFFFFF) {
std::vector<char> cbuf(comprlen);
is->read(&cbuf[0],comprlen);
if(is->fail()) return false;
// Save other internal variables that are important
gzwrite (file, &nds, sizeof(NDSSystem));
uLongf uncomprlen = len;
int error = uncompress((uint8*)&buf[0],&uncomprlen,(uint8*)&cbuf[0],comprlen);
if(error != Z_OK || uncomprlen != len)
return false;
} else {
is->read((char*)&buf[0],len);
}
// Save memory/registers specific to the ARM9
gzwrite (file, ARM9Mem.ARM9_ITCM, 0x8000);
gzwrite (file ,ARM9Mem.ARM9_DTCM, 0x4000);
gzwrite (file ,ARM9Mem.ARM9_WRAM, 0x1000000);
gzwrite (file, ARM9Mem.MAIN_MEM, 0x400000);
gzwrite (file, ARM9Mem.ARM9_REG, 0x10000);
gzwrite (file, ARM9Mem.ARM9_VMEM, 0x800);
gzwrite (file, ARM9Mem.ARM9_OAM, 0x800);
gzwrite (file, ARM9Mem.ARM9_ABG, 0x80000);
gzwrite (file, ARM9Mem.ARM9_BBG, 0x20000);
gzwrite (file, ARM9Mem.ARM9_AOBJ, 0x40000);
gzwrite (file, ARM9Mem.ARM9_BOBJ, 0x20000);
gzwrite (file, ARM9Mem.ARM9_LCD, 0xA4000);
// Save memory/registers specific to the ARM7
gzwrite (file, MMU.ARM7_ERAM, 0x10000);
gzwrite (file, MMU.ARM7_REG, 0x10000);
gzwrite (file, MMU.ARM7_WIRAM, 0x10000);
memorystream mstemp(&buf);
bool x = ReadStateChunks(&mstemp,(s32)len);
// Save shared memory
gzwrite (file, MMU.SWIRAM, 0x8000);
loadstate();
gzclose (file);
return 1;
#else
return 0;
#endif
return x;
}
bool savestate_load(const char *file_name)
{
std::ifstream f;
f.open(file_name,std::ios_base::binary|std::ios_base::in);
if(!f) return false;
return savestate_load(&f);
}

View File

@ -33,6 +33,35 @@ typedef struct
char date[40];
} savestates_t;
struct SFORMAT
{
//a void* to the data or a void** to the data
void *v;
//size, plus flags
uint32 s;
//a string description of the element
char *desc;
};
//X multiple multibyte elements
#define SS_MULT(X) (X<<24)
//indicates that the value is a multibyte integer that needs to be put in the correct byte order
//this is the same as SS_MULT(1)
#define SS_RLSB SS_MULT(1)
//all flags together so that we can mask them out and get the size
#define SS_FLAGS (SS_INDIRECT|SS_MULT(127))
//extract the multiplier
#define SS_UNMULT(X) ((X>>24)&0x7F)
extern savestates_t savestates[NB_STATES];
void clear_savestates();
@ -42,8 +71,8 @@ void sram_write (u32 address, u8 value);
int sram_load (const char *file_name);
int sram_save (const char *file_name);
int savestate_load (const char *file_name);
int savestate_save (const char *file_name);
bool savestate_load (const char *file_name);
bool savestate_save (const char *file_name);
void savestate_slot(int num);
void loadstate_slot(int num);

View File

@ -20,6 +20,11 @@
#ifndef TYPES_HPP
#define TYPES_HPP
#define DESMUME_NAME "DeSmuME"
#define DESMUME_VERSION_STRING "0.8.0b2-interim"
#define DESMUME_VERSION_NUMERIC 80002
#define DESMUME_NAME_AND_VERSION DESMUME_NAME " " DESMUME_VERSION_STRING " " VERSION
#ifdef _WIN32
#define strcasecmp(x,y) stricmp(x,y)
#else
@ -168,13 +173,17 @@ typedef int desmume_BOOL;
#ifdef LOCAL_BE /* local arch is big endian */
# define LE_TO_LOCAL_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff))
# define LE_TO_LOCAL_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff))
# define LE_TO_LOCAL_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00))|(((x)>>40)&0xff00))|(((x)>>56)&0xff))
# define LOCAL_TO_LE_16(x) ((((x)&0xff)<<8)|(((x)>>8)&0xff))
# define LOCAL_TO_LE_32(x) ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)>>8)&0xff00)|(((x)>>24)&0xff))
# define LOCAL_TO_LE_64(x) ((((x)&0xff)<<56)|(((x)&0xff00)<<40)|(((x)&0xff0000)<<24)|(((x)&0xff000000)<<8)|(((x)>>8)&0xff000000)|(((x)>>24)&0xff00))|(((x)>>40)&0xff00))|(((x)>>56)&0xff))
#else /* local arch is little endian */
# define LE_TO_LOCAL_16(x) (x)
# define LE_TO_LOCAL_32(x) (x)
# define LE_TO_LOCAL_64(x) (x)
# define LOCAL_TO_LE_16(x) (x)
# define LOCAL_TO_LE_32(x) (x)
# define LOCAL_TO_LE_64(x) (x)
#endif
/* kilobytes and megabytes macro */
@ -194,4 +203,24 @@ typedef enum
#define __PACKED
#endif
///endian-flips count bytes. count should be even and nonzero.
inline void FlipByteOrder(u8 *src, u32 count)
{
u8 *start=src;
u8 *end=src+count-1;
if((count&1) || !count) return; /* This shouldn't happen. */
while(count--)
{
u8 tmp;
tmp=*end;
*end=*start;
*start=tmp;
end--;
start++;
}
}
#endif

View File

@ -54,7 +54,7 @@
EnableFiberSafeOptimizations="false"
WholeProgramOptimization="false"
AdditionalIncludeDirectories="..;.\zlib123;.\zziplib"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;0.8.0b2 DEBUG\&quot;;WIN32;BETA_VERSION;SPU_INTERPOLATE;HAVE_LIBZ"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;DEBUG\&quot;;WIN32;BETA_VERSION;SPU_INTERPOLATE;HAVE_LIBZ;NOMINMAX"
ExceptionHandling="1"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="0"
@ -140,7 +140,7 @@
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
AdditionalIncludeDirectories="..;.\zlib123;.\zziplib"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;0.8.0b2\&quot;;WIN32;HAVE_LIBZ;HAVE_LIBZZIP;BETA_VERSION;SPU_INTERPOLATE"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;Release\&quot;;WIN32;HAVE_LIBZ;HAVE_LIBZZIP;BETA_VERSION;SPU_INTERPOLATE"
StringPooling="true"
ExceptionHandling="1"
BufferSecurityCheck="false"
@ -228,9 +228,9 @@
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="true"
AdditionalIncludeDirectories="..;.\zlib123;.\zziplib"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;0.8.0b2 SSE2\&quot;;WIN32;HAVE_LIBZ;HAVE_LIBZZIP;SSE2;BETA_VERSION;SPU_INTERPOLATE"
PreprocessorDefinitions="_CRT_SECURE_NO_DEPRECATE;VERSION=\&quot;Release SSE2\&quot;;WIN32;HAVE_LIBZ;HAVE_LIBZZIP;SSE2;BETA_VERSION;SPU_INTERPOLATE;NOMINMAX"
StringPooling="true"
ExceptionHandling="0"
ExceptionHandling="1"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
FloatingPointModel="2"
@ -820,6 +820,14 @@
RelativePath=".\palView.cpp"
>
</File>
<File
RelativePath="..\readwrite.cpp"
>
</File>
<File
RelativePath="..\readwrite.h"
>
</File>
<File
RelativePath="..\render3D.cpp"
>

View File

@ -25,6 +25,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include "types.h"
///////////////////////////////////////////////////////////////// Console
@ -43,7 +44,7 @@ void OpenConsole()
if (hConsole) return;
AllocConsole();
memset(buf,0,256);
sprintf(buf,"DeSmuME v%s OUTPUT", VERSION);
sprintf(buf,"%s OUTPUT", DESMUME_NAME_AND_VERSION);
SetConsoleTitle(TEXT(buf));
csize.X = 60;
csize.Y = 800;
@ -56,7 +57,7 @@ void OpenConsole()
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCP(GetACP());
SetConsoleOutputCP(GetACP());
printlog("DeSmuME v%s BETA\n",VERSION);
printlog("%s\n",DESMUME_NAME_AND_VERSION);
printlog("- compiled: %s %s\n\n",__DATE__,__TIME__);
//redirect stdio

View File

@ -19,6 +19,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <algorithm>
#include <tchar.h>
#include <stdio.h>
#include "../MMU.h"
@ -619,16 +620,16 @@ LRESULT CALLBACK DisViewBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
switch LOWORD(wParam)
{
case SB_LINEDOWN :
win->curr_ligne = min(0x3FFFFF7*(1+win->cpu->CPSR.bits.T), win->curr_ligne+1);
win->curr_ligne = std::min<s32>(0x3FFFFF7*(1+win->cpu->CPSR.bits.T), win->curr_ligne+1);
break;
case SB_LINEUP :
win->curr_ligne = (u32)max(0, (s32)win->curr_ligne-1);
win->curr_ligne = (u32)std::max<s32>(0, (s32)win->curr_ligne-1);
break;
case SB_PAGEDOWN :
win->curr_ligne = min(0x3FFFFF7*(1+win->cpu->CPSR.bits.T), win->curr_ligne+nbligne);
win->curr_ligne = std::min<s32>(0x3FFFFF7*(1+win->cpu->CPSR.bits.T), win->curr_ligne+nbligne);
break;
case SB_PAGEUP :
win->curr_ligne = (u32)max(0, (s32)win->curr_ligne-nbligne);
win->curr_ligne = (u32)std::max<s32>(0, (s32)win->curr_ligne-nbligne);
break;
}

View File

@ -22,6 +22,7 @@
*/
#define WIN32_LEAN_AND_MEAN
#include <algorithm>
#include <windows.h>
#include <shellapi.h>
#include <Winuser.h>
@ -533,6 +534,107 @@ int CreateDDrawBuffers()
return 1;
}
void Display()
{
int res;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags=DDSD_ALL;
res=IDirectDrawSurface7_Lock(lpBackSurface,NULL,&ddsd,DDLOCK_WAIT, NULL);
if (res == DD_OK)
{
char* buffer = (char*)ddsd.lpSurface;
int i, j, sz=256*sizeof(u32);
if (ddsd.ddpfPixelFormat.dwRGBBitCount>16)
{
u16 *tmpGPU_Screen_src=(u16*)GPU_screen;
u32 tmpGPU_screen[98304];
for(i=0; i<98304; i++)
tmpGPU_screen[i]= (((tmpGPU_Screen_src[i]>>10)&0x1F)<<3)|
(((tmpGPU_Screen_src[i]>>5)&0x1F)<<11)|
(((tmpGPU_Screen_src[i])&0x1F)<<19);
switch (GPU_rotation)
{
case 0:
{
for (i = 0; i < 98304; i+=256) //384*256
{
memcpy(buffer,tmpGPU_screen+i,sz);
buffer += ddsd.lPitch;
}
break;
}
case 90:
{
u32 start;
memset(buffer,0,384*ddsd.lPitch);
for (j=0; j<256; j++)
{
start=98304+j;
for (i=0; i<384; i++)
{
start-=256;
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
}
buffer += ddsd.lPitch;
}
break;
}
case 180:
{
u32 start=98300;
for (j=0; j<384; j++)
{
for (i=0; i<256; i++, --start)
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
buffer += ddsd.lPitch;
}
break;
}
case 270:
{
u32 start;
memset(buffer,0,384*ddsd.lPitch);
for (j=0; j<256; j++)
{
start=256-j;
for (i=0; i<384; i++)
{
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
start+=256;
}
buffer += ddsd.lPitch;
}
break;
}
}
}
else
printlog("16bit depth color not supported");
IDirectDrawSurface7_Unlock(lpBackSurface,(LPRECT)ddsd.lpSurface);
if (IDirectDrawSurface7_Blt(lpPrimarySurface,&MainWindowRect,lpBackSurface,0, DDBLT_WAIT,0)==DDERR_SURFACELOST)
{
printlog("DirectDraw buffers is lost\n");
if (IDirectDrawSurface7_Restore(lpPrimarySurface)==DD_OK)
IDirectDrawSurface7_Restore(lpBackSurface);
}
}
else
{
if (res==DDERR_SURFACELOST)
{
printlog("DirectDraw buffers is lost\n");
if (IDirectDrawSurface7_Restore(lpPrimarySurface)==DD_OK)
IDirectDrawSurface7_Restore(lpBackSurface);
}
}
}
DWORD WINAPI run( LPVOID lpParameter)
{
char txt[80];
@ -600,101 +702,7 @@ DWORD WINAPI run( LPVOID lpParameter)
if (!skipnextframe)
{
int res;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags=DDSD_ALL;
res=IDirectDrawSurface7_Lock(lpBackSurface,NULL,&ddsd,DDLOCK_WAIT, NULL);
if (res == DD_OK)
{
char* buffer = (char*)ddsd.lpSurface;
int i, j, sz=256*sizeof(u32);
if (ddsd.ddpfPixelFormat.dwRGBBitCount>16)
{
u16 *tmpGPU_Screen_src=(u16*)GPU_screen;
u32 tmpGPU_screen[98304];
for(i=0; i<98304; i++)
tmpGPU_screen[i]= (((tmpGPU_Screen_src[i]>>10)&0x1F)<<3)|
(((tmpGPU_Screen_src[i]>>5)&0x1F)<<11)|
(((tmpGPU_Screen_src[i])&0x1F)<<19);
switch (GPU_rotation)
{
case 0:
{
for (i = 0; i < 98304; i+=256) //384*256
{
memcpy(buffer,tmpGPU_screen+i,sz);
buffer += ddsd.lPitch;
}
break;
}
case 90:
{
u32 start;
memset(buffer,0,384*ddsd.lPitch);
for (j=0; j<256; j++)
{
start=98304+j;
for (i=0; i<384; i++)
{
start-=256;
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
}
buffer += ddsd.lPitch;
}
break;
}
case 180:
{
u32 start=98300;
for (j=0; j<384; j++)
{
for (i=0; i<256; i++, --start)
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
buffer += ddsd.lPitch;
}
break;
}
case 270:
{
u32 start;
memset(buffer,0,384*ddsd.lPitch);
for (j=0; j<256; j++)
{
start=256-j;
for (i=0; i<384; i++)
{
((u32*)buffer)[i]=((u32 *)tmpGPU_screen)[start];
start+=256;
}
buffer += ddsd.lPitch;
}
break;
}
}
}
else
printlog("16bit depth color not supported");
IDirectDrawSurface7_Unlock(lpBackSurface,(LPRECT)ddsd.lpSurface);
if (IDirectDrawSurface7_Blt(lpPrimarySurface,&MainWindowRect,lpBackSurface,0, DDBLT_WAIT,0)==DDERR_SURFACELOST)
{
printlog("DirectDraw buffers is lost\n");
if (IDirectDrawSurface7_Restore(lpPrimarySurface)==DD_OK)
IDirectDrawSurface7_Restore(lpBackSurface);
}
}
else
{
if (res==DDERR_SURFACELOST)
{
printlog("DirectDraw buffers is lost\n");
if (IDirectDrawSurface7_Restore(lpPrimarySurface)==DD_OK)
IDirectDrawSurface7_Restore(lpBackSurface);
}
}
Display();
fpsframecount++;
QueryPerformanceCounter((LARGE_INTEGER *)&curticks);
@ -712,8 +720,8 @@ DWORD WINAPI run( LPVOID lpParameter)
int load = 0;
for(int i=0;i<16;i++)
load = load/8 + nds.runCycleCollector[(i+nds.idleFrameCounter)&15]*7/8;
load = min(100,max(0,(int)(load*100/1120380)));
sprintf(txt,"(%02d%%) DeSmuME v%s", load, VERSION);
load = std::min(100,std::max(0,(int)(load*100/1120380)));
sprintf(txt,"(%02d%%) %s", load, DESMUME_NAME_AND_VERSION);
SetWindowText(hwnd, txt);
osd->addFixed(10, 10, "%02d Fps", fps);
}
@ -810,9 +818,13 @@ void StateSaveSlot(int num)
void StateLoadSlot(int num)
{
BOOL wasPaused = paused;
NDS_Pause();
loadstate_slot(num);
NDS_UnPause();
if(!wasPaused)
NDS_UnPause();
else
Display();
}
BOOL LoadROM(char * filename, const char *cflash_disk_image)
@ -944,7 +956,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance,
GPU_rotation = GetPrivateProfileInt("Video","Window Rotate", 0, IniName);
ForceRatio = GetPrivateProfileInt("Video","Window Force Ratio", 1, IniName);
sprintf(text, "DeSmuME v%s", VERSION);
sprintf(text, "%s", DESMUME_NAME_AND_VERSION);
init_configured_features( &my_config);
if ( !fill_configured_features( &my_config, lpszArgument)) {

View File

@ -19,6 +19,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <algorithm>
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
@ -436,16 +437,16 @@ LRESULT CALLBACK MemViewBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
switch LOWORD(wParam)
{
case SB_LINEDOWN :
win->curr_ligne = min(0X0FFFFFFFF, win->curr_ligne+1);
win->curr_ligne = std::min((s32)0x0FFFFFFFF, (s32)win->curr_ligne+1);
break;
case SB_LINEUP :
win->curr_ligne = (u32)max(0, (s32)win->curr_ligne-1);
win->curr_ligne = (u32)std::max(0l, (s32)win->curr_ligne-1);
break;
case SB_PAGEDOWN :
win->curr_ligne = min(0X0FFFFFFFF, win->curr_ligne+nbligne);
win->curr_ligne = std::min((s32)0x0FFFFFFFF, (s32)win->curr_ligne+nbligne);
break;
case SB_PAGEUP :
win->curr_ligne = (u32)max(0, (s32)win->curr_ligne-nbligne);
win->curr_ligne = (u32)std::max(0l, (s32)win->curr_ligne-nbligne);
break;
}