- revised input code to be more explicit and "sync-safe"

- touchscreen calibration/wraparound fix
- hud edit mode fixes
- nicer input displays
- master brightness blank screen optimization
- implemented left+rt/up+dn checking
- fixed autohold activation
- enabled diagonal keys
- play and record movie dialog and menu improvements
- fixed potential microphone desyncs (savestated, and silenced non-mic-button during movie)
- fixed window squashing when resizing top corner above top of screen
- fixed freeze if frame advance button is pressed before loading a ROM
- implemented joypad Lua functions
This commit is contained in:
nitsuja 2009-08-21 09:56:17 +00:00
parent bb7d9f16a4
commit c20c88bdbc
20 changed files with 1444 additions and 808 deletions

View File

@ -2344,9 +2344,18 @@ static INLINE void GPU_ligne_MasterBrightness(NDS_Screen * screen, u16 l)
// Bright up
case 1:
{
for(i16 = 0; i16 < 256; ++i16)
if(factor != 16)
{
((u16*)dst)[i16] = fadeInColors[factor][((u16*)dst)[i16]&0x7FFF];
for(i16 = 0; i16 < 256; ++i16)
{
((u16*)dst)[i16] = fadeInColors[factor][((u16*)dst)[i16]&0x7FFF];
}
}
else
{
// all white (optimization)
for(i16 = 0; i16 < 256; ++i16)
((u16*)dst)[i16] = 0x7FFF;
}
break;
}
@ -2354,9 +2363,17 @@ static INLINE void GPU_ligne_MasterBrightness(NDS_Screen * screen, u16 l)
// Bright down
case 2:
{
for(i16 = 0; i16 < 256; ++i16)
if(factor != 16)
{
((u16*)dst)[i16] = fadeOutColors[factor][((u16*)dst)[i16]&0x7FFF];
for(i16 = 0; i16 < 256; ++i16)
{
((u16*)dst)[i16] = fadeOutColors[factor][((u16*)dst)[i16]&0x7FFF];
}
}
else
{
// all black (optimization)
memset(dst, 0, 512);
}
break;
}
@ -2493,6 +2510,18 @@ void GPU_ligne(NDS_Screen * screen, u16 l, bool skip)
return;
}
// skip some work if master brightness makes the screen completely white or completely black
if(gpu->MasterBrightFactor >= 16 && (gpu->MasterBrightMode == 1 || gpu->MasterBrightMode == 2))
{
// except if it could cause any side effects (for example if we're capturing), then don't skip anything
if(!(gpu->core == GPU_MAIN && (gpu->dispCapCnt.enabled || l == 0 || l == 191)))
{
gpu->currLine = l;
GPU_ligne_MasterBrightness(screen, l);
return;
}
}
//cache some parameters which are assumed to be stable throughout the rendering of the entire line
gpu->currLine = l;
u16 mosaic_control = T1ReadWord((u8 *)&gpu->dispx_st->dispx_MISC.MOSAIC, 0);

View File

@ -70,7 +70,7 @@ void EditHud(s32 x, s32 y, HudStruct *hudstruct) {
}
if((x >= hud.x && x <= hud.x + hud.xsize) &&
(y >= hud.y && y <= hud.y + hud.ysize) && !hud.clicked ) {
(y >= hud.y && y <= hud.y + hud.ysize) && !hudstruct->clicked ) {
hud.clicked=1;
hud.storedx = x - hud.x;
@ -89,7 +89,10 @@ void EditHud(s32 x, s32 y, HudStruct *hudstruct) {
if(hud.y > 384-16)hud.y = 384-16;
if(hud.clicked)
{
hudstruct->clicked = true;
break;//prevent items from grouping together
}
i++;
}
@ -104,6 +107,8 @@ void HudClickRelease(HudStruct *hudstruct) {
hud.clicked=0;
i++;
}
hudstruct->clicked = false;
}
void HudStruct::reset()
@ -120,13 +125,13 @@ void HudStruct::reset()
InputDisplay.x=0;
InputDisplay.y=45;
InputDisplay.xsize=120;
InputDisplay.xsize=220;
InputDisplay.ysize=10;
GraphicalInputDisplay.x=8;
GraphicalInputDisplay.y=328;
GraphicalInputDisplay.xsize=100;
GraphicalInputDisplay.ysize=40;
GraphicalInputDisplay.xsize=102;
GraphicalInputDisplay.ysize=50;
LagFrameCounter.x=0;
LagFrameCounter.y=65;
@ -144,12 +149,19 @@ void HudStruct::reset()
SavestateSlots.ysize = 24;
SetHudDummy(&Dummy);
clicked = false;
}
static void joyFill(int n) {
if(nds.pad & (1 << n))
bool pressedForGame = NDS_getFinalUserInput().buttons.array[n];
bool physicallyPressed = NDS_getRawUserInput().buttons.array[n];
if(pressedForGame && physicallyPressed)
aggDraw.hud->fillColor(0,0,0,255);
else if(pressedForGame)
aggDraw.hud->fillColor(255,0,0,255);
else if(physicallyPressed)
aggDraw.hud->fillColor(0,255,0,255);
else
aggDraw.hud->fillColor(255,255,255,255);
}
@ -157,65 +169,140 @@ static void joyFill(int n) {
static void joyEllipse(double ex, double ey, int xc, int yc, int x, int y, double ratio, double rad, int button) {
joyFill(button);
aggDraw.hud->lineWidth(rad);
aggDraw.hud->ellipse(x+((xc*ex)*ratio), y+((yc*ey)*ratio), rad*ratio, rad*ratio);
}
static void gradientFill(double x1,double y1,double x2,double y2,AggColor c1,AggColor c2, int n) {
if(nds.pad & (1 << n))
aggDraw.hud->fillLinearGradient(x1,y1,x2,y2,c1,c2);
static void joyRoundedRect(double x1, double y1, int x2, int y2, int alpha1, int alpha2, int button)
{
bool pressedForGame = NDS_getFinalUserInput().buttons.array[button];
bool physicallyPressed = NDS_getRawUserInput().buttons.array[button];
if(pressedForGame && physicallyPressed)
aggDraw.hud->fillLinearGradient(x1,y1,x2,y2,agg::rgba8(0,0,0,alpha1), agg::rgba8(0,0,0,alpha2));
else if(pressedForGame)
aggDraw.hud->fillLinearGradient(x1,y1,x2,y2,agg::rgba8(255,0,0,alpha1), agg::rgba8(255,0,0,alpha2));
else if(physicallyPressed)
aggDraw.hud->fillLinearGradient(x1,y1,x2,y2,agg::rgba8(0,255,0,alpha1), agg::rgba8(0,255,0,alpha2));
else
aggDraw.hud->fillColor(255,255,255,255);
return; //aggDraw.hud->fillLinearGradient(x1,y1,x2,y2,agg::rgba8(255,255,255,alpha1), agg::rgba8(255,255,255,alpha2));
aggDraw.hud->roundedRect(x1,y1,x2,y2,1);
}
static void drawPad(int x, int y, double ratio) {
int xc = 41;
int yc = 20;
static void drawPad(double x, double y, double ratio) {
// you might notice black/red/green colors used to show what buttons are pressed.
// the logic is roughly:
// RED == PAST (the button was held last frame)
// GREEN == FUTURE (the button is physically held now)
// BLACK == PRESENT (the button was held last frame and is still physically held now)
// aligning to odd half-pixel boundaries prevents agg2d from blurring thin straight lines
x = floor(x) + 0.5;
y = floor(y) + 0.5;
double xc = 41 - 0.5;
double yc = 20 - 0.5;
aggDraw.hud->lineColor(128,128,128,255);
aggDraw.hud->fillLinearGradient(x, y, x+(xc*ratio), y+(yc*ratio), agg::rgba8(222,222,222,128), agg::rgba8(255,255,255,255));
if(nds.pad & (1 << 2))
aggDraw.hud->fillLinearGradient(x, y, x+(xc*ratio), y+(yc*ratio), agg::rgba8(0,0,0,128), agg::rgba8(255,255,255,255));
aggDraw.hud->roundedRect (x, y, floor(x+(xc*ratio))+0.5, floor(y+(yc*ratio))+0.5, 1);
if(nds.pad & (1 << 1))
aggDraw.hud->fillLinearGradient(x+(xc*ratio), y+(yc*ratio), x, y, agg::rgba8(0,0,0,128), agg::rgba8(255,255,255,255));
double screenLeft = x+(xc*.25*ratio);
double screenTop = y+(yc*.1*ratio);
double screenRight = x+(xc*.745*ratio);
double screenBottom = y+(yc*.845*ratio);
aggDraw.hud->fillLinearGradient(screenLeft, screenTop, screenRight, screenBottom, agg::rgba8(128,128,128,128), agg::rgba8(255,255,255,255));
aggDraw.hud->roundedRect (screenLeft, screenTop, screenRight, screenBottom, 1);
aggDraw.hud->roundedRect (x, y, x+(xc*ratio), y+(yc*ratio), 1);
aggDraw.hud->fillLinearGradient(x+(xc*.25*ratio), y+(yc*.1*ratio), x+(xc*.75*ratio), y+(yc*.85*ratio), agg::rgba8(128,128,128,128), agg::rgba8(255,255,255,255));
aggDraw.hud->roundedRect (x+(xc*.25*ratio), y+(yc*.1*ratio), x+(xc*.75*ratio),y+(yc*.85*ratio), 1);
joyEllipse(.89,.45,xc,yc,x,y,ratio,1,6);//B
joyEllipse(.89,.22,xc,yc,x,y,ratio,1,3);//X
joyEllipse(.83,.34,xc,yc,x,y,ratio,1,4);//Y
joyEllipse(.95,.34,xc,yc,x,y,ratio,1,5);//A
joyEllipse(.82,.72,xc,yc,x,y,ratio,.5,7);//Start
joyEllipse(.82,.85,xc,yc,x,y,ratio,.5,8);//Select
joyEllipse(.82,.716,xc,yc,x,y,ratio,.5,7);//Start
joyEllipse(.82,.842,xc,yc,x,y,ratio,.5,8);//Select
double dpadPoints [][2] = {
{.04,.33}, // top-left corner of left button
{.08,.33},
{.08,.24}, // top-left corner of up button
{.13,.24}, // top-right corner of up button
{.13,.33},
{.17,.33}, // top-right corner of right button
{.17,.43}, // bottom-right corner of right button
{.13,.43},
{.13,.516}, // bottom-right corner of down button
{.08,.516}, // bottom-left corner of down button
{.08,.43},
{.04,.43}, // bottom-left corner of left button
};
static const int numdpadPoints = sizeof(dpadPoints)/sizeof(dpadPoints[0]);
for(int i = 0; i < numdpadPoints; i++)
{
dpadPoints[i][0] = x+(xc*(dpadPoints[i][0]+.01)*ratio);
dpadPoints[i][1] = y+(yc*(dpadPoints[i][1]+.00)*ratio);
}
// dpad outline
aggDraw.hud->fillColor(255,255,255,200);
aggDraw.hud->polygon((double*)dpadPoints, numdpadPoints);
aggDraw.hud->noLine();
aggDraw.hud->fillColor(255,255,255,200);
//left
gradientFill(x+(xc*.04*ratio), y+(yc*.33*ratio), x+(xc*.17*ratio), y+(yc*.43*ratio), agg::rgba8(0,0,0,255), agg::rgba8(255,255,255,255),11);
// left
joyRoundedRect(dpadPoints[0][0], dpadPoints[0][1], dpadPoints[7][0], dpadPoints[7][1], 255, 0, 11);
// right
joyRoundedRect(dpadPoints[1][0], dpadPoints[1][1], dpadPoints[6][0], dpadPoints[6][1], 0, 255, 12);
//right
if(nds.pad & (1 << 12))
aggDraw.hud->fillLinearGradient(x+(xc*.17*ratio), y+(yc*.43*ratio), x+(xc*.04*ratio), y+(yc*.33*ratio), agg::rgba8(0,0,0,255), agg::rgba8(255,255,255,255));
aggDraw.hud->roundedRect (x+(xc*.04*ratio), y+(yc*.33*ratio), x+(xc*.17*ratio), y+(yc*.43*ratio), 1);
// up
joyRoundedRect(dpadPoints[2][0], dpadPoints[2][1], dpadPoints[7][0], dpadPoints[7][1], 255, 0, 9);
// right
joyRoundedRect(dpadPoints[1][0], dpadPoints[1][1], dpadPoints[8][0], dpadPoints[8][1], 0, 255, 10);
//down
gradientFill(x+(xc*.13*ratio), y+(yc*.52*ratio), x+(xc*.08*ratio), y+(yc*.23*ratio), agg::rgba8(0,0,0,255), agg::rgba8(255,255,255,255),10);
// left shoulder
joyRoundedRect(x+(xc*.00*ratio), y+(yc*.00*ratio), x+(xc*.15*ratio), y+(yc*.07*ratio), 255, 200, 2);
//up
if(nds.pad & (1<< 9))
aggDraw.hud->fillLinearGradient(x+(xc*.08*ratio), y+(yc*.23*ratio), x+(xc*.13*ratio), y+(yc*.52*ratio), agg::rgba8(0,0,0,255), agg::rgba8(255,255,255,255));
// right shoulder
joyRoundedRect(x+(xc*.85*ratio), y+(yc*.00*ratio), x+(xc*1.0*ratio), y+(yc*.07*ratio), 200, 255, 1);
aggDraw.hud->roundedRect (x+(xc*.08*ratio), y+(yc*.23*ratio), x+(xc*.13*ratio), y+(yc*.52*ratio), 1);
// lid...
joyRoundedRect(x+(xc*.4*ratio), y+(yc*.96*ratio), x+(xc*0.6*ratio), y+(yc*1.0*ratio), 200, 200, 13);
// touch pad
{
bool gameTouchOn = nds.isTouch;
double gameTouchX = screenLeft+1 + (nds.touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0;
double gameTouchY = screenTop+1 + (nds.touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0;
bool physicalTouchOn = NDS_getRawUserInput().touch.isTouch;
double physicalTouchX = screenLeft+1 + (NDS_getRawUserInput().touch.touchX * 0.0625) * (screenRight - screenLeft - 2) / 256.0;
double physicalTouchY = screenTop+1 + (NDS_getRawUserInput().touch.touchY * 0.0625) * (screenBottom - screenTop - 2) / 192.0;
if(gameTouchOn && physicalTouchOn && gameTouchX == physicalTouchX && gameTouchY == physicalTouchY)
{
aggDraw.hud->fillColor(0,0,0,255);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37);
}
else
{
if(physicalTouchOn)
{
aggDraw.hud->fillColor(0,0,0,128);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.5, ratio*0.5);
aggDraw.hud->fillColor(0,255,0,255);
aggDraw.hud->ellipse(physicalTouchX, physicalTouchY, ratio*0.37, ratio*0.37);
}
if(gameTouchOn)
{
aggDraw.hud->fillColor(255,0,0,255);
aggDraw.hud->ellipse(gameTouchX, gameTouchY, ratio*0.37, ratio*0.37);
}
}
}
}
@ -225,20 +312,87 @@ struct TouchInfo{
};
static int touchalpha[8]= {31, 63, 95, 127, 159, 191, 223, 255};
static TouchInfo temptouch;
bool touchshadow = true;
static const bool touchshadow = false;//true; // sorry, it's cool but also distracting and looks cleaner with it off. maybe if it drew line segments between touch points instead of isolated crosses...
static std::vector<TouchInfo> touch (8);
static void TextualInputDisplay() {
// drawing the whole string at once looks ugly
// (because of variable width font and the "shadow" appearing over blank space)
// and can't give us the color-coded effects we want anyway (see drawPad for info)
const UserButtons& gameButtons = NDS_getFinalUserInput().buttons;
const UserButtons& physicalButtons = NDS_getRawUserInput().buttons;
double x = Hud.InputDisplay.x;
// from order FRLDUTSBAYXWEG where G is 0
static const char* buttonChars = "<^>vABXYLRSsgf";
static const int buttonIndex [14] = {11,9,12,10,5,6,3,4,2,1,7,8,0,13};
for(int i = 0; i < 14; i++, x+=11.0)
{
bool pressedForGame = gameButtons.array[buttonIndex[i]];
bool physicallyPressed = physicalButtons.array[buttonIndex[i]];
if(pressedForGame && physicallyPressed)
aggDraw.hud->lineColor(255,255,255,255);
else if(pressedForGame)
aggDraw.hud->lineColor(255,48,48,255);
else if(physicallyPressed)
aggDraw.hud->lineColor(0,255,0,255);
else
continue;
// cast from char to std::string is a bit awkward
std::string str(buttonChars+i, 2);
str[1] = '\0';
aggDraw.hud->renderTextDropshadowed(x, Hud.InputDisplay.y, str);
}
// touch pad
{
char str [32];
bool gameTouchOn = nds.isTouch;
int gameTouchX = nds.touchX >> 4;
int gameTouchY = nds.touchY >> 4;
bool physicalTouchOn = NDS_getRawUserInput().touch.isTouch;
int physicalTouchX = NDS_getRawUserInput().touch.touchX >> 4;
int physicalTouchY = NDS_getRawUserInput().touch.touchY >> 4;
if(gameTouchOn && physicalTouchOn && gameTouchX == physicalTouchX && gameTouchY == physicalTouchY)
{
sprintf(str, "%d,%d", gameTouchX, gameTouchY);
aggDraw.hud->lineColor(255,255,255,255);
aggDraw.hud->renderTextDropshadowed(x, Hud.InputDisplay.y, str);
}
else
{
if(gameTouchOn)
{
sprintf(str, "%d,%d", gameTouchX, gameTouchY);
aggDraw.hud->lineColor(255,48,48,255);
aggDraw.hud->renderTextDropshadowed(x, Hud.InputDisplay.y-(physicalTouchOn?8:0), str);
}
if(physicalTouchOn)
{
sprintf(str, "%d,%d", physicalTouchX, physicalTouchY);
aggDraw.hud->lineColor(0,255,0,255);
aggDraw.hud->renderTextDropshadowed(x, Hud.InputDisplay.y+(gameTouchOn?8:0), str);
}
}
}
}
static void TouchDisplay() {
aggDraw.hud->lineWidth(1.0);
temptouch.X = nds.touchX >> 4;
temptouch.Y = nds.touchY >> 4;
touch.push_back(temptouch);
if(touch.size() > 8) touch.erase(touch.begin());
temptouch.X = NDS_getRawUserInput().touch.touchX >> 4;
temptouch.Y = NDS_getRawUserInput().touch.touchY >> 4;
if(touchshadow) {
touch.push_back(temptouch);
if(touch.size() > 8) touch.erase(touch.begin());
for (int i = 0; i < 8; i++) {
temptouch = touch[i];
if(temptouch.X != 0 || temptouch.Y != 0) {
@ -251,10 +405,20 @@ static void TouchDisplay() {
}
}
else
if(nds.isTouch) {
if(NDS_getRawUserInput().touch.isTouch) {
aggDraw.hud->lineColor(0, 255, 0, 128);
aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert
}
if(nds.isTouch) {
temptouch.X = nds.touchX >> 4;
temptouch.Y = nds.touchY >> 4;
aggDraw.hud->lineColor(255, 0, 0, 128);
aggDraw.hud->line(temptouch.X - 256, temptouch.Y + 192, temptouch.X + 256, temptouch.Y + 192); //horiz
aggDraw.hud->line(temptouch.X, temptouch.Y - 256, temptouch.X, temptouch.Y + 384); //vert
}
}
static int previousslot = 0;
@ -304,19 +468,37 @@ static void DrawStateSlots(){
previousslot = lastSaveState;
}
static void DrawEditableElementIndicators()
{
u32 i = 0;
while (!IsHudDummy(&Hud.hud(i))) {
HudCoordinates &hud = Hud.hud(i);
aggDraw.hud->fillColor(0,0,0,0);
aggDraw.hud->lineColor(0,0,0,64);
aggDraw.hud->lineWidth(2.0);
aggDraw.hud->rectangle(hud.x,hud.y,hud.x+hud.xsize+1.0,hud.y+hud.ysize+1.0);
aggDraw.hud->lineColor(255,hud.clicked?127:255,0,255);
aggDraw.hud->lineWidth(1.0);
aggDraw.hud->rectangle(hud.x-0.5,hud.y-0.5,hud.x+hud.xsize+0.5,hud.y+hud.ysize+0.5);
i++;
}
}
void DrawHUD()
{
GTimeVal time;
g_get_current_time(&time);
hudTimer = ((s64)time.tv_sec * 1000) + ((s64)time.tv_usec/1000);
if (HudEditorMode)
{
DrawEditableElementIndicators();
}
if (CommonSettings.hud.ShowInputDisplay)
{
std::stringstream ss;
if(nds.isTouch)
ss << (nds.touchX >> 4) << " " << (nds.touchY >> 4);
osd->addFixed(Hud.InputDisplay.x, Hud.InputDisplay.y, "%s",(InputDisplayString + ss.str()).c_str());
TextualInputDisplay();
TouchDisplay();
}
@ -341,7 +523,9 @@ void DrawHUD()
}
if (CommonSettings.hud.ShowGraphicalInputDisplay)
{
drawPad(Hud.GraphicalInputDisplay.x, Hud.GraphicalInputDisplay.y, 2.5);
}
#ifdef WIN32
if (CommonSettings.hud.ShowMicrophone)

View File

@ -50,6 +50,7 @@ public:
HudStruct()
: fps(0)
, fps3d(0)
, clicked(false)
{}
HudCoordinates SavestateSlots;
@ -65,6 +66,7 @@ public:
void reset();
int fps, fps3d;
bool clicked;
};
void EditHud(s32 x, s32 y, HudStruct *hudstruct);

View File

@ -541,12 +541,12 @@ int NDS_Init( void) {
// Init calibration info
TSCal.adc.x1 = 0x0200;
TSCal.adc.y1 = 0x0200;
TSCal.scr.x1 = 0x20;
TSCal.scr.y1 = 0x20;
TSCal.scr.x1 = 0x20 + 1; // calibration screen coords are 1-based,
TSCal.scr.y1 = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong.
TSCal.adc.x2 = 0x0E00;
TSCal.adc.y2 = 0x0800;
TSCal.scr.x2 = 0xE0;
TSCal.scr.y2 = 0x80;
TSCal.scr.x2 = 0xE0 + 1;
TSCal.scr.y2 = 0x80 + 1;
return 0;
}
@ -621,35 +621,6 @@ NDS_header * NDS_getROMHeader(void)
}
INLINE u16 NDS_getADCTouchPosX(u16 scrX)
{
return (scrX - TSCal.scr.x1 + 1) * (TSCal.adc.x2 - TSCal.adc.x1) / (TSCal.scr.x2 - TSCal.scr.x1) + TSCal.adc.x1;
}
INLINE u16 NDS_getADCTouchPosY(u16 scrY)
{
return (scrY - TSCal.scr.y1 + 1) * (TSCal.adc.y2 - TSCal.adc.y1) / (TSCal.scr.y2 - TSCal.scr.y1) + TSCal.adc.y1;
}
void NDS_setTouchPos(u16 x, u16 y)
{
//nds.touchX = (x <<4);
//nds.touchY = (y <<4);
nds.touchX = NDS_getADCTouchPosX(x);
nds.touchY = NDS_getADCTouchPosY(y);
nds.isTouch = 1;
MMU.ARM7_REG[0x136] &= 0xBF;
}
void NDS_releaseTouch(void)
{
nds.touchX = 0;
nds.touchY = 0;
nds.isTouch = 0;
MMU.ARM7_REG[0x136] |= 0x40;
}
void debug()
@ -1446,13 +1417,13 @@ void NDS_FillDefaultFirmwareConfigData( struct NDS_fw_config_data *fw_config) {
/* default touchscreen calibration */
fw_config->touch_cal[0].adc_x = 0x200;
fw_config->touch_cal[0].adc_y = 0x200;
fw_config->touch_cal[0].screen_x = 0x20;
fw_config->touch_cal[0].screen_y = 0x20;
fw_config->touch_cal[0].screen_x = 0x20 + 1; // calibration screen coords are 1-based,
fw_config->touch_cal[0].screen_y = 0x20 + 1; // either that or NDS_getADCTouchPosX/Y are wrong.
fw_config->touch_cal[1].adc_x = 0xe00;
fw_config->touch_cal[1].adc_y = 0x800;
fw_config->touch_cal[1].screen_x = 0xe0;
fw_config->touch_cal[1].screen_y = 0x80;
fw_config->touch_cal[1].screen_x = 0xe0 + 1;
fw_config->touch_cal[1].screen_y = 0x80 + 1;
}
int NDS_LoadFirmware(const char *filename)
@ -1639,9 +1610,11 @@ template<int procnum, int num> struct TSequenceItem_Timer : public TSequenceItem
nds.timerCycle[procnum][i] += (remain << MMU.timerMODE[procnum][i]);
ctr++;
}
#if defined(DEBUG) || defined(_DEBUG)
if(ctr>1) {
printf("yikes!!!!! please report!\n");
}
#endif
}
if(over)
@ -2081,12 +2054,17 @@ void Sequencer::execHardware()
void execHardware_interrupts();
static void saveUserInput(std::ostream* os);
static bool loadUserInput(std::istream* is, int version);
void nds_savestate(std::ostream* os)
{
//version
write32le(1,os);
write32le(2,os);
sequencer.save(os);
saveUserInput(os);
}
bool nds_loadstate(std::istream* is, int size)
@ -2095,9 +2073,13 @@ bool nds_loadstate(std::istream* is, int size)
int version;
if(read32le(&version,is) != 1) return false;
if(version > 1) return false;
if(version > 2) return false;
return sequencer.load(is, version);
bool temp = true;
temp &= sequencer.load(is, version);
if(version <= 1 || !temp) return temp;
temp &= loadUserInput(is, version);
return temp;
}
//#define LOG_ARM9
@ -2522,131 +2504,243 @@ static std::string MakeInputDisplayString(u16 pad, u16 padExt) {
return s;
}
buttonstruct<bool> Turbo;
buttonstruct<int> TurboTime;
buttonstruct<bool> AutoHold;
void ClearAutoHold(void) {
for (int i=0; i < 12; i++) {
AutoHold.hold(i)=false;
for (int i=0; i < ARRAY_SIZE(AutoHold.array); i++) {
AutoHold.array[i]=false;
}
}
void NDS_setPadFromMovie(u16 pad)
INLINE u16 NDS_getADCTouchPosX(u16 scrX)
{
#define FIX(b,n) (((pad>>n)&1)!=0)
NDS_setPad(
FIX(pad,12), //R
FIX(pad,11), //L
FIX(pad,10), //D
FIX(pad,9), //U
FIX(pad,7), //Select
FIX(pad,8), //Start
FIX(pad,6), //B
FIX(pad,5), //A
FIX(pad,4), //Y
FIX(pad,3), //X
FIX(pad,2),
FIX(pad,1),
FIX(pad,0),
movie_lid
);
#undef FIX
// this is a little iffy,
// we're basically adjusting the ADC results to
// compensate for how they will be interpreted.
// the actual system doesn't do this transformation.
int rv = (scrX - TSCal.scr.x1 + 1) * (TSCal.adc.x2 - TSCal.adc.x1) / (TSCal.scr.x2 - TSCal.scr.x1) + TSCal.adc.x1;
rv = min(0xFFF, max(0, rv));
return (u16)rv;
}
INLINE u16 NDS_getADCTouchPosY(u16 scrY)
{
int rv = (scrY - TSCal.scr.y1 + 1) * (TSCal.adc.y2 - TSCal.adc.y1) / (TSCal.scr.y2 - TSCal.scr.y1) + TSCal.adc.y1;
rv = min(0xFFF, max(0, rv));
return (u16)rv;
}
turbo Turbo;
turbotime TurboTime;
static UserInput rawUserInput = {}; // requested input, generally what the user is physically pressing
static UserInput intermediateUserInput = {}; // intermediate buffer for modifications (seperated from finalUserInput for safety reasons)
static UserInput finalUserInput = {}; // what gets sent to the game and possibly recorded
bool validToProcessInput = false;
static void SetTurbo(bool (&pad) [12]) {
bool turbo[4] = {true, false, true, false};
bool currentbutton;
for (int i=0; i < 12; i++) {
currentbutton=Turbo.button(i);
if(currentbutton && movieMode != MOVIEMODE_PLAY) {
pad[i]=turbo[TurboTime.time(i)-1];
if(TurboTime.time(i) >= (int)ARRAY_SIZE(turbo))
TurboTime.time(i)=0;
}
else
TurboTime.time(i)=0; //reset timer if the button isn't pressed
}
for (int i=0; i<12; i++)
TurboTime.time(i)++;
const UserInput& NDS_getRawUserInput()
{
return rawUserInput;
}
UserInput& NDS_getProcessingUserInput()
{
assert(validToProcessInput);
return intermediateUserInput;
}
bool NDS_isProcessingUserInput()
{
return validToProcessInput;
}
const UserInput& NDS_getFinalUserInput()
{
return finalUserInput;
}
autohold AutoHold;
static void saveUserInput(std::ostream* os, UserInput& input)
{
os->write((const char*)input.buttons.array, 14);
writebool(input.touch.isTouch, os);
write16le(input.touch.touchX, os);
write16le(input.touch.touchY, os);
write32le(input.mic.micButtonPressed, os);
}
static bool loadUserInput(std::istream* is, UserInput& input, int version)
{
is->read((char*)input.buttons.array, 14);
readbool(&input.touch.isTouch, is);
read16le(&input.touch.touchX, is);
read16le(&input.touch.touchY, is);
read32le(&input.mic.micButtonPressed, is);
return true;
}
// (userinput is kind of a misnomer, e.g. finalUserInput has to mirror nds.pad, nds.touchX, etc.)
static void saveUserInput(std::ostream* os)
{
saveUserInput(os, finalUserInput);
saveUserInput(os, intermediateUserInput); // saved in case a savestate is made during input processing (which Lua could do if nothing else)
writebool(validToProcessInput, os);
for(int i = 0; i < 14; i++)
write32le(TurboTime.array[i], os); // saved to make autofire more tolerable to use with re-recording
}
static bool loadUserInput(std::istream* is, int version)
{
bool rv = true;
rv &= loadUserInput(is, finalUserInput, version);
rv &= loadUserInput(is, intermediateUserInput, version);
readbool(&validToProcessInput, is);
for(int i = 0; i < 14; i++)
read32le(&TurboTime.array[i], is);
return rv;
}
static inline void gotInputRequest()
{
// nobody should set the raw input while we're processing the input.
// it might not screw anything up but it would be completely useless.
assert(!validToProcessInput);
}
void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F)
{
gotInputRequest();
UserButtons& rawButtons = rawUserInput.buttons;
rawButtons.R = R;
rawButtons.L = L;
rawButtons.D = D;
rawButtons.U = U;
rawButtons.T = T;
rawButtons.S = S;
rawButtons.B = B;
rawButtons.A = A;
rawButtons.Y = Y;
rawButtons.X = X;
rawButtons.W = W;
rawButtons.E = E;
rawButtons.G = G;
rawButtons.F = F;
}
void NDS_setTouchPos(u16 x, u16 y)
{
gotInputRequest();
rawUserInput.touch.touchX = NDS_getADCTouchPosX(x);
rawUserInput.touch.touchY = NDS_getADCTouchPosY(y);
rawUserInput.touch.isTouch = true;
bool padarray[12] = {R, L, D, U, T, S, B, A, Y, X, W, E};
SetTurbo(padarray);
R=padarray[0];
L=padarray[1];
D=padarray[2];
U=padarray[3];
T=padarray[4];
S=padarray[5];
B=padarray[6];
A=padarray[7];
Y=padarray[8];
X=padarray[9];
W=padarray[10];
E=padarray[11];
if (movieMode != MOVIEMODE_PLAY) {
if(AutoHold.Right) R=!padarray[0];
if(AutoHold.Left) L=!padarray[1];
if(AutoHold.Down) D=!padarray[2];
if(AutoHold.Up) U=!padarray[3];
if(AutoHold.Select)T=!padarray[4];
if(AutoHold.Start) S=!padarray[5];
if(AutoHold.B) B=!padarray[6];
if(AutoHold.A) A=!padarray[7];
if(AutoHold.Y) Y=!padarray[8];
if(AutoHold.X) X=!padarray[9];
if(AutoHold.L) W=!padarray[10];
if(AutoHold.R) E=!padarray[11];
if(movieMode != MOVIEMODE_INACTIVE)
{
// just in case, since the movie only stores 8 bits per touch coord
rawUserInput.touch.touchX &= 0x0FF0;
rawUserInput.touch.touchY &= 0x0FF0;
}
//this macro is the opposite of what you would expect
#define FIX(b) (b?0:0x80)
#ifndef WIN32
// FIXME: this code should be deleted from here,
// other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead
// (see the function called "run" in src/windows/main.cpp),
// but I'm leaving this here for now since I can't test those other platforms myself.
nds.touchX = rawUserInput.touch.touchX;
nds.touchY = rawUserInput.touch.touchY;
nds.isTouch = 1;
MMU.ARM7_REG[0x136] &= 0xBF;
#endif
}
void NDS_releaseTouch(void)
{
gotInputRequest();
rawUserInput.touch.touchX = 0;
rawUserInput.touch.touchY = 0;
rawUserInput.touch.isTouch = false;
int r = FIX(R);
int l = FIX(L);
int d = FIX(D);
int u = FIX(U);
int t = FIX(T);
int s = FIX(S);
int b = FIX(B);
int a = FIX(A);
int y = FIX(Y);
int x = FIX(X);
int w = FIX(W);
int e = FIX(E);
int g = FIX(G);
int f = FIX(F);
#ifndef WIN32
// FIXME: this code should be deleted from here,
// other platforms should call NDS_beginProcessingInput,NDS_endProcessingInput once per frame instead
// (see the function called "run" in src/windows/main.cpp),
// but I'm leaving this here for now since I can't test those other platforms myself.
nds.touchX = 0;
nds.touchY = 0;
nds.isTouch = 0;
MMU.ARM7_REG[0x136] |= 0x40;
#endif
}
void NDS_setMic(bool pressed)
{
gotInputRequest();
rawUserInput.mic.micButtonPressed = (pressed ? TRUE : FALSE);
}
static void NDS_applyFinalInput();
void NDS_beginProcessingInput()
{
// start off from the raw input
intermediateUserInput = rawUserInput;
// processing is valid now
validToProcessInput = true;
}
void NDS_endProcessingInput()
{
// transfer the processed input
finalUserInput = intermediateUserInput;
// processing is invalid now
validToProcessInput = false;
// use the final input for a few things right away
NDS_applyFinalInput();
}
static void NDS_applyFinalInput()
{
const UserInput& input = NDS_getFinalUserInput();
u16 pad = (0 |
((a) >> 7) |
((b) >> 6) |
((s) >> 5) |
((t) >> 4) |
((r) >> 3) |
((l) >> 2) |
((u) >> 1) |
((d)) |
((e) << 1) |
((w) << 2)) ;
((input.buttons.A ? 0 : 0x80) >> 7) |
((input.buttons.B ? 0 : 0x80) >> 6) |
((input.buttons.T ? 0 : 0x80) >> 5) |
((input.buttons.S ? 0 : 0x80) >> 4) |
((input.buttons.R ? 0 : 0x80) >> 3) |
((input.buttons.L ? 0 : 0x80) >> 2) |
((input.buttons.U ? 0 : 0x80) >> 1) |
((input.buttons.D ? 0 : 0x80) ) |
((input.buttons.E ? 0 : 0x80) << 1) |
((input.buttons.W ? 0 : 0x80) << 2)) ;
((u16 *)MMU.ARM9_REG)[0x130>>1] = (u16)pad;
((u16 *)MMU.ARM7_REG)[0x130>>1] = (u16)pad;
if (!f && !countLid)
if(input.touch.isTouch)
{
nds.touchX = input.touch.touchX;
nds.touchY = input.touch.touchY;
nds.isTouch = 1;
MMU.ARM7_REG[0x136] &= 0xBF;
}
else
{
nds.touchX = 0;
nds.touchY = 0;
nds.isTouch = 0;
MMU.ARM7_REG[0x136] |= 0x40;
}
if (input.buttons.F && !countLid)
{
LidClosed = (!LidClosed) & 0x01;
if (!LidClosed)
@ -2667,9 +2761,9 @@ void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,b
}
u16 padExt = (((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0070) |
((x) >> 7) |
((y) >> 6) |
((g) >> 4) |
((input.buttons.X ? 0 : 0x80) >> 7) |
((input.buttons.Y ? 0 : 0x80) >> 6) |
((input.buttons.G ? 0 : 0x80) >> 4) |
((LidClosed) << 7) |
0x0034;
@ -2678,41 +2772,22 @@ void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,b
InputDisplayString=MakeInputDisplayString(padExt, pad);
//put into the format we want for the movie system
//RLDUTSBAYXWEGF
#undef FIX
#define FIX(b) (b?1:0)
//fRLDUTSBAYXWEg
//we don't really need nds.pad anymore, but removing it would be a pain
r = FIX(R);
l = FIX(L);
d = FIX(D);
u = FIX(U);
t = FIX(T);
s = FIX(S);
b = FIX(B);
a = FIX(A);
y = FIX(Y);
x = FIX(X);
w = FIX(W);
e = FIX(E);
g = FIX(G);
f = FIX(F);
if(f) movie_lid=true;
else movie_lid=false;
nds.pad =
(FIX(r)<<12)|
(FIX(l)<<11)|
(FIX(d)<<10)|
(FIX(u)<<9)|
(FIX(s)<<8)|
(FIX(t)<<7)|
(FIX(b)<<6)|
(FIX(a)<<5)|
(FIX(y)<<4)|
(FIX(x)<<3)|
(FIX(w)<<2)|
(FIX(e)<<1);
nds.pad =
((input.buttons.R ? 1 : 0) << 12)|
((input.buttons.L ? 1 : 0) << 11)|
((input.buttons.D ? 1 : 0) << 10)|
((input.buttons.U ? 1 : 0) << 9)|
((input.buttons.T ? 1 : 0) << 8)|
((input.buttons.S ? 1 : 0) << 7)|
((input.buttons.B ? 1 : 0) << 6)|
((input.buttons.A ? 1 : 0) << 5)|
((input.buttons.Y ? 1 : 0) << 4)|
((input.buttons.X ? 1 : 0) << 3)|
((input.buttons.W ? 1 : 0) << 2)|
((input.buttons.E ? 1 : 0) << 1);
// TODO: low power IRQ
}

View File

@ -39,62 +39,34 @@
#include "pathsettings.h"
#endif
struct turbo {
bool Right;
bool Left;
bool Down;
bool Up;
bool Start;
bool Select;
bool B;
bool A;
bool Y;
bool X;
bool L;
bool R;
bool &button(int i) { return ((bool*)this)[i]; }
template<typename Type>
struct buttonstruct {
union {
struct {
// changing the order of these fields would break stuff
//fRLDUTSBAYXWEg
Type G; // debug
Type E; // right shoulder
Type W; // left shoulder
Type X;
Type Y;
Type A;
Type B;
Type S; // start
Type T; // select
Type U; // up
Type D; // down
Type L; // left
Type R; // right
Type F; // lid
};
Type array[14];
};
};
extern turbo Turbo;
struct turbotime {
int Right;
int Left;
int Down;
int Up;
int Start;
int Select;
int B;
int A;
int Y;
int X;
int L;
int R;
int &time(int i) { return ((int*)this)[i]; }
};
extern turbotime TurboTime;
struct autohold {
bool Right;
bool Left;
bool Down;
bool Up;
bool Start;
bool Select;
bool B;
bool A;
bool Y;
bool X;
bool L;
bool R;
bool &hold(int i) { return ((bool*)this)[i]; }
};
extern autohold AutoHold;
extern buttonstruct<bool> Turbo;
extern buttonstruct<int> TurboTime;
extern buttonstruct<bool> AutoHold;
int NDS_WritePNG(const char *fname);
@ -310,10 +282,60 @@ typedef struct TSCalInfo
} TSCalInfo;
extern GameInfo gameInfo;
struct UserButtons : buttonstruct<bool>
{
};
struct UserTouch
{
u16 touchX;
u16 touchY;
bool isTouch;
};
struct UserMicrophone
{
BOOL micButtonPressed;
};
struct UserInput
{
UserButtons buttons;
UserTouch touch;
UserMicrophone mic;
};
// set physical user input
// these functions merely request the input to be changed.
// the actual change happens later at a specific time during the frame.
// this is to minimize the risk of desyncs.
void NDS_setTouchPos(u16 x, u16 y);
void NDS_releaseTouch(void);
void NDS_setPad(bool R,bool L,bool D,bool U,bool T,bool S,bool B,bool A,bool Y,bool X,bool W,bool E,bool G, bool F);
void NDS_setPadFromMovie(u16 pad);
void NDS_setPad(bool right,bool left,bool down,bool up,bool select,bool start,bool B,bool A,bool Y,bool X,bool leftShoulder,bool rightShoulder,bool debug, bool lid);
void NDS_setMic(bool pressed);
// get physical user input
// not including the results of autofire/etc.
// the effects of calls to "set physical user input" functions will be immediately reflected here though.
const UserInput& NDS_getRawUserInput();
const UserInput& NDS_getPrevRawUserInput();
// get final (fully processed) user input
// this should match whatever was or would be sent to the game
const UserInput& NDS_getFinalUserInput();
// set/get to-be-processed or in-the-middle-of-being-processed user input
// to process input, simply call this function and edit the return value.
// (applying autofire is one example of processing the input.)
// (movie playback is another example.)
// this must be done after the raw user input is set
// and before that input is sent to the game's memory.
UserInput& NDS_getProcessingUserInput();
bool NDS_isProcessingUserInput();
// call once per frame to prepare input for processing
void NDS_beginProcessingInput();
// call once per frame to copy the processed input to the final input
void NDS_endProcessingInput();
int NDS_LoadROM(const char *filename, const char* logicalFilename=0);
void NDS_FreeROM(void);

View File

@ -405,7 +405,10 @@ public:
virtual void renderTextDropshadowed(double dstX, double dstY, const std::string& str)
{
AggColor lineColorOld = lineColor();
lineColor(255-lineColorOld.r,255-lineColorOld.g,255-lineColorOld.b);
if(lineColorOld.r+lineColorOld.g+lineColorOld.b<192)
lineColor(255-lineColorOld.r,255-lineColorOld.g,255-lineColorOld.b);
else
lineColor(0,0,0);
renderText(dstX-1,dstY-1,str);
renderText(dstX,dstY-1,str);
renderText(dstX+1,dstY-1,str);

View File

@ -1923,251 +1923,154 @@ DEFINE_LUA_FUNCTION(state_load, "location[,option]")
//joypad lib
static const char *button_mappings[] = {
"debug","r","l","x","y","a","b","start","select","up","down","left","right"
"debug","R","L","X","Y","A","B","start","select","up","down","left","right","lid"
};
// table joypad.read(int which = 1)
//
// Reads the joypads as inputted by the user.
static int joy_get(lua_State *L) {
uint16 buttons = nds.pad;
lua_newtable(L);
int i;
for (i = 0; i < 16; i++) {
if (buttons & (1<<i)) {
lua_pushinteger(L,1);
lua_setfield(L, -2, button_mappings[i]);
}
}
static int joy_getArgControllerNum(lua_State* L, int& index)
{
// well, I think there's only one controller,
// but this should probably stay here for cross-emulator consistency
int type = lua_type(L,index);
if(type == LUA_TSTRING || type == LUA_TNUMBER)
index++;
return 1;
}
/*
static const struct ButtonDesc
// joypad.set(table buttons)
//
// Sets the joypad state (takes effect at the next frame boundary)
// true -> pressed
// false -> unpressed
// nil -> no change
DEFINE_LUA_FUNCTION(joy_set, "buttonTable")
{
unsigned short controllerNum;
unsigned short bit;
const char* name;
}
s_buttonDescs [] =
{
{1, 0, "up"},
{1, 1, "down"},
{1, 2, "left"},
{1, 3, "right"},
{1, 4, "A"},
{1, 5, "B"},
{1, 6, "C"},
{1, 7, "start"},
{1, 32, "X"},
{1, 33, "Y"},
{1, 34, "Z"},
{1, 35, "mode"},
{2, 24, "up"},
{2, 25, "down"},
{2, 26, "left"},
{2, 27, "right"},
{2, 28, "A"},
{2, 29, "B"},
{2, 30, "C"},
{2, 31, "start"},
{2, 36, "X"},
{2, 37, "Y"},
{2, 38, "Z"},
{2, 39, "mode"},
{0x1B, 8, "up"},
{0x1B, 9, "down"},
{0x1B, 10, "left"},
{0x1B, 11, "right"},
{0x1B, 12, "A"},
{0x1B, 13, "B"},
{0x1B, 14, "C"},
{0x1B, 15, "start"},
{0x1C, 16, "up"},
{0x1C, 17, "down"},
{0x1C, 18, "left"},
{0x1C, 19, "right"},
{0x1C, 20, "A"},
{0x1C, 21, "B"},
{0x1C, 22, "C"},
{0x1C, 23, "start"},
};
if(movieMode == MOVIEMODE_PLAY) // don't allow tampering with a playing movie's input
return 0; // (although it might be useful sometimes...)
int joy_getArgControllerNum(lua_State* L, int& index)
{
int controllerNumber;
int type = lua_type(L,index);
if(type == LUA_TSTRING || type == LUA_TNUMBER)
{
controllerNumber = 0;
if(type == LUA_TSTRING)
{
const char* str = lua_tostring(L,index);
if(!stricmp(str, "1C"))
controllerNumber = 0x1C;
else if(!stricmp(str, "1B"))
controllerNumber = 0x1B;
else if(!stricmp(str, "1A"))
controllerNumber = 0x1A;
}
if(!controllerNumber)
controllerNumber = luaL_checkinteger(L,index);
index++;
}
else
{
// argument omitted; default to controller 1
controllerNumber = 1;
}
if(controllerNumber == 0x1A)
controllerNumber = 1;
if(controllerNumber != 1 && controllerNumber != 2 && controllerNumber != 0x1B && controllerNumber != 0x1C)
luaL_error(L, "controller number must be 1, 2, '1B', or '1C'");
return controllerNumber;
}
// joypad.set(controllerNum = 1, inputTable)
// controllerNum can be 1, 2, '1B', or '1C'
DEFINE_LUA_FUNCTION(joy_set, "[controller=1,]inputtable")
{
int index = 1;
int controllerNumber = joy_getArgControllerNum(L, index);
(void)joy_getArgControllerNum(L, index);
luaL_checktype(L, index, LUA_TTABLE);
int input = ~0;
int mask = 0;
UserButtons buttons = NDS_isProcessingUserInput() ? NDS_getProcessingUserInput().buttons : NDS_getRawUserInput().buttons;
for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++)
for(int i = 0; i < sizeof(button_mappings)/sizeof(*button_mappings); i++)
{
const ButtonDesc& bd = s_buttonDescs[i];
if(bd.controllerNum == controllerNumber)
const char* name = button_mappings[i];
lua_getfield(L, index, name);
if (!lua_isnil(L,-1))
{
lua_getfield(L, index, bd.name);
if (!lua_isnil(L,-1))
{
bool pressed = lua_toboolean(L,-1) != 0;
int bitmask = ((long long)1 << bd.bit);
if(pressed)
input &= ~bitmask;
else
input |= bitmask;
mask |= bitmask;
}
lua_pop(L,1);
bool pressed = lua_toboolean(L,-1) != 0;
buttons.array[i] = pressed;
}
lua_pop(L,1);
}
SetNextInputCondensed(input, mask);
if(NDS_isProcessingUserInput())
NDS_getProcessingUserInput().buttons = buttons;
else
NDS_setPad(buttons.R, buttons.L, buttons.D, buttons.U, buttons.T, buttons.S, buttons.B, buttons.A, buttons.Y, buttons.X, buttons.W, buttons.E, buttons.G, buttons.F);
return 0;
}
// joypad.get(controllerNum = 1)
// controllerNum can be 1, 2, '1B', or '1C'
// table joypad.read()
//
// Reads the joypad state (what the game sees)
int joy_get_internal(lua_State* L, bool reportUp, bool reportDown)
{
int index = 1;
int controllerNumber = joy_getArgControllerNum(L, index);
(void)joy_getArgControllerNum(L, index);
lua_newtable(L);
long long input = GetCurrentInputCondensed();
const UserButtons& buttons = NDS_getFinalUserInput().buttons;
for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++)
for(int i = 0; i < sizeof(button_mappings)/sizeof(*button_mappings); i++)
{
const ButtonDesc& bd = s_buttonDescs[i];
if(bd.controllerNum == controllerNumber)
const char* name = button_mappings[i];
bool pressed = buttons.array[i];
if((pressed && reportDown) || (!pressed && reportUp))
{
bool pressed = (input & ((long long)1<<bd.bit)) == 0;
if((pressed && reportDown) || (!pressed && reportUp))
{
lua_pushboolean(L, pressed);
lua_setfield(L, -2, bd.name);
}
lua_pushboolean(L, pressed);
lua_setfield(L, -2, name);
}
}
return 1;
}/*
// joypad.get(int controllerNumber = 1)
}
// joypad.get()
// returns a table of every game button,
// true meaning currently-held and false meaning not-currently-held
// (as of last frame boundary)
// this WILL read input from a currently-playing movie
DEFINE_LUA_FUNCTION(joy_get, "[controller=1]")
DEFINE_LUA_FUNCTION(joy_get, "")
{
return joy_get_internal(L, true, true);
}
// joypad.getdown(int controllerNumber = 1)
// joypad.getdown()
// returns a table of every game button that is currently held
DEFINE_LUA_FUNCTION(joy_getdown, "[controller=1]")
DEFINE_LUA_FUNCTION(joy_getdown, "")
{
return joy_get_internal(L, false, true);
}
// joypad.getup(int controllerNumber = 1)
// joypad.getup()
// returns a table of every game button that is not currently held
DEFINE_LUA_FUNCTION(joy_getup, "[controller=1]")
DEFINE_LUA_FUNCTION(joy_getup, "")
{
return joy_get_internal(L, true, false);
}
// joypad.peek(controllerNum = 1)
// controllerNum can be 1, 2, '1B', or '1C'
// table joypad.peek()
//
// Reads the joypad state (what the user is currently pressing/requesting)
int joy_peek_internal(lua_State* L, bool reportUp, bool reportDown)
{
int index = 1;
int controllerNumber = joy_getArgControllerNum(L, index);
(void)joy_getArgControllerNum(L, index);
lua_newtable(L);
long long input = PeekInputCondensed();
const UserButtons& buttons = NDS_getRawUserInput().buttons;
for(int i = 0; i < sizeof(s_buttonDescs)/sizeof(*s_buttonDescs); i++)
for(int i = 0; i < sizeof(button_mappings)/sizeof(*button_mappings); i++)
{
const ButtonDesc& bd = s_buttonDescs[i];
if(bd.controllerNum == controllerNumber)
const char* name = button_mappings[i];
bool pressed = buttons.array[i];
if((pressed && reportDown) || (!pressed && reportUp))
{
bool pressed = (input & ((long long)1<<bd.bit)) == 0;
if((pressed && reportDown) || (!pressed && reportUp))
{
lua_pushboolean(L, pressed);
lua_setfield(L, -2, bd.name);
}
lua_pushboolean(L, pressed);
lua_setfield(L, -2, name);
}
}
return 1;
}
// joypad.peek(int controllerNumber = 1)
// joypad.peek()
// returns a table of every game button,
// true meaning currently-held and false meaning not-currently-held
// peek checks which joypad buttons are physically pressed, so it will NOT read input from a playing movie, it CAN read mid-frame input, and it will NOT pay attention to stuff like autofire or autohold or disabled L+R/U+D
DEFINE_LUA_FUNCTION(joy_peek, "[controller=1]")
// peek checks which joypad buttons are physically pressed,
// so it will NOT read input from a playing movie,
// it CAN read mid-frame input,
// and it will NOT pay attention to stuff like disabled L+R/U+D
DEFINE_LUA_FUNCTION(joy_peek, "")
{
return joy_peek_internal(L, true, true);
}
// joypad.peekdown(int controllerNumber = 1)
// joypad.peekdown()
// returns a table of every game button that is currently held (according to what joypad.peek() would return)
DEFINE_LUA_FUNCTION(joy_peekdown, "[controller=1]")
DEFINE_LUA_FUNCTION(joy_peekdown, "")
{
return joy_peek_internal(L, false, true);
}
// joypad.peekup(int controllerNumber = 1)
// joypad.peekup()
// returns a table of every game button that is not currently held (according to what joypad.peek() would return)
DEFINE_LUA_FUNCTION(joy_peekup, "[controller=1]")
DEFINE_LUA_FUNCTION(joy_peekup, "")
{
return joy_peek_internal(L, true, false);
}
*/
static const struct ColorMapping
{
const char* name;
@ -3441,10 +3344,24 @@ static int stylus_read(lua_State *L){
return 1;
}
static int stylus_peek(lua_State *L){
lua_newtable(L);
lua_pushinteger(L, NDS_getRawUserInput().touch.touchX >> 4);
lua_setfield(L, -2, "x");
lua_pushinteger(L, NDS_getRawUserInput().touch.touchY >> 4);
lua_setfield(L, -2, "y");
lua_pushinteger(L, NDS_getRawUserInput().touch.isTouch?1:0);
lua_setfield(L, -2, "touch");
return 1;
}
static const struct luaL_reg styluslib [] =
{
{"read", stylus_read},
{"peek", stylus_peek},
{NULL, NULL}
};
@ -3560,17 +3477,17 @@ static const struct luaL_reg memorylib [] =
static const struct luaL_reg joylib [] =
{
{"get", joy_get},
// {"getdown", joy_getdown},
// {"getup", joy_getup},
// {"peek", joy_peek},
// {"peekdown", joy_peekdown},
// {"peekup", joy_peekup},
// {"set", joy_set},
{"getdown", joy_getdown},
{"getup", joy_getup},
{"peek", joy_peek},
{"peekdown", joy_peekdown},
{"peekup", joy_peekup},
{"set", joy_set},
// alternative names
{"read", joy_get},
// {"write", joy_set},
// {"readdown", joy_getdown},
// {"readup", joy_getup},
{"write", joy_set},
{"readdown", joy_getdown},
{"readup", joy_getup},
{NULL, NULL}
};
static const struct luaL_reg inputlib [] =

View File

@ -21,8 +21,6 @@
#ifndef MIC_H
#define MIC_H
extern int MicButtonPressed;
#ifdef WIN32
static char MicSampleName[256];
bool LoadSample(const char *name);
@ -39,4 +37,7 @@ void Mic_Reset();
void Mic_DeInit();
u8 Mic_ReadSample();
void mic_savestate(std::ostream* os);
bool mic_loadstate(std::istream* is, int size);
#endif

View File

@ -60,7 +60,6 @@ char curMovieFilename[512] = {0};
MovieData currMovieData;
int currRerecordCount;
bool movie_reset_command = false;
bool movie_lid = false;
//--------------
@ -434,10 +433,23 @@ void _CDECL_ FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, i
//LoadFM2(currMovieData, fp->stream, INT_MAX, false);
fstream fs (fname);
LoadFM2(currMovieData, &fs, INT_MAX, false);
fs.close();
bool opened = false;
{
fstream fs (fname);
if(fs.is_open())
{
LoadFM2(currMovieData, &fs, INT_MAX, false);
opened = true;
}
fs.close();
}
if(!opened)
{
// for some reason fs.open doesn't work, it has to be a whole new fstream object
fstream fs (fname, std::ios_base::in);
LoadFM2(currMovieData, &fs, INT_MAX, false);
fs.close();
}
//TODO
//fully reload the game to reinitialize everything before playing any movie
@ -589,33 +601,17 @@ void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, s
driver->USR_InfoMessage("Movie recording started.");
}
void NDS_setTouchFromMovie(void) {
if(movieMode == MOVIEMODE_PLAY)
{
MovieRecord* mr = &currMovieData.records[currFrameCounter];
nds.touchX=mr->touch.x << 4;
nds.touchY=mr->touch.y << 4;
if(mr->touch.touch) {
nds.isTouch=mr->touch.touch;
MMU.ARM7_REG[0x136] &= 0xBF;
}
else {
nds.touchX=0;
nds.touchY=0;
nds.isTouch=0;
MMU.ARM7_REG[0x136] |= 0x40;
}
//osd->addFixed(mr->touch.x, mr->touch.y, "%s", "X");
}
}
//the main interaction point between the emulator and the movie system.
//either dumps the current joystick state or loads one state from the movie
//either dumps the current joystick state or loads one state from the movie.
//deprecated, should use the two functions it has been split into directly
void FCEUMOV_AddInputState()
{
FCEUMOV_HandlePlayback();
FCEUMOV_HandleRecording();
}
void FCEUMOV_HandlePlayback()
{
if(movieMode == MOVIEMODE_PLAY)
{
@ -626,18 +622,36 @@ void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, s
}
else
{
UserInput& input = NDS_getProcessingUserInput();
MovieRecord* mr = &currMovieData.records[currFrameCounter];
if(mr->command_microphone()) MicButtonPressed=1;
else MicButtonPressed=0;
if(mr->command_microphone()) input.mic.micButtonPressed = 1;
else input.mic.micButtonPressed = 0;
if(mr->command_reset()) NDS_Reset();
if(mr->command_lid()) movie_lid = true;
else movie_lid = false;
if(mr->command_lid()) input.buttons.F = true;
else input.buttons.F = false;
NDS_setPadFromMovie(mr->pad);
NDS_setTouchFromMovie();
u16 pad = mr->pad;
input.buttons.R = (((pad>>12)&1)!=0);
input.buttons.L = (((pad>>11)&1)!=0);
input.buttons.D = (((pad>>10)&1)!=0);
input.buttons.U = (((pad>>9)&1)!=0);
input.buttons.T = (((pad>>8)&1)!=0);
input.buttons.S = (((pad>>7)&1)!=0);
input.buttons.B = (((pad>>6)&1)!=0);
input.buttons.A = (((pad>>5)&1)!=0);
input.buttons.Y = (((pad>>4)&1)!=0);
input.buttons.X = (((pad>>3)&1)!=0);
input.buttons.W = (((pad>>2)&1)!=0);
input.buttons.E = (((pad>>1)&1)!=0);
input.buttons.G = (((pad>>0)&1)!=0);
input.touch.touchX = mr->touch.x << 4;
input.touch.touchY = mr->touch.y << 4;
input.touch.isTouch = mr->touch.touch;
}
//if we are on the last frame, then pause the emulator if the player requested it
@ -655,43 +669,57 @@ void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, s
// FCEUI_ToggleEmulationPause();
// FCEU_DispMessage("Paused at specified movie frame");
//}
osd->addFixed(180, 176, "%s", "Playback");
// it's apparently un-threadsafe to do this here
// (causes crazy flickering in other OSD elements, at least)
// and it's also pretty annoying,
// and the framecounter display already conveys this info as well.
// so, I'm disabling this, at least for now.
// osd->addFixed(180, 176, "%s", "Playback");
}
else if(movieMode == MOVIEMODE_RECORD)
}
void FCEUMOV_HandleRecording()
{
if(movieMode == MOVIEMODE_RECORD)
{
const UserInput& input = NDS_getFinalUserInput();
MovieRecord mr;
mr.commands = 0;
if(MicButtonPressed == 1)
mr.commands=1;
if(input.mic.micButtonPressed == 1)
mr.commands = MOVIECMD_MIC;
mr.pad = nds.pad;
if(movie_lid) {
mr.commands=4;
movie_lid = false;
}
if(input.buttons.F)
mr.commands = MOVIECMD_LID;
if(movie_reset_command) {
mr.commands=2;
mr.commands = MOVIECMD_RESET;
movie_reset_command = false;
}
if(nds.isTouch) {
mr.touch.x = nds.touchX >> 4;
mr.touch.y = nds.touchY >> 4;
mr.touch.touch = 1;
} else {
mr.touch.x = 0;
mr.touch.y = 0;
mr.touch.touch = 0;
}
mr.touch.touch = input.touch.isTouch ? 1 : 0;
mr.touch.x = input.touch.isTouch ? input.touch.touchX >> 4 : 0;
mr.touch.y = input.touch.isTouch ? input.touch.touchY >> 4 : 0;
assert(mr.touch.touch || (!mr.touch.x && !mr.touch.y));
assert(nds.touchX == input.touch.touchX && nds.touchY == input.touch.touchY);
assert((mr.touch.x << 4) == nds.touchX && (mr.touch.y << 4) == nds.touchY);
mr.dump(&currMovieData, osRecordingMovie,currMovieData.records.size());
currMovieData.records.push_back(mr);
osd->addFixed(180, 176, "%s", "Recording");
// it's apparently un-threadsafe to do this here
// (causes crazy flickering in other OSD elements, at least)
// and it's also pretty annoying,
// and the framecounter display already conveys this info as well.
// so, I'm disabling this, at least for now.
// osd->addFixed(180, 176, "%s", "Recording");
}
/*extern uint8 joy[4];
@ -859,6 +887,12 @@ bool mov_loadstate(std::istream* is, int size)
currMovieData.rerecordCount = currRerecordCount;
openRecordingMovie(curMovieFilename);
if(!osRecordingMovie->is_open())
{
osd->setLineColor(255, 0, 0);
osd->addLine("Can't save movie file!");
}
//printf("DUMPING MOVIE: %d FRAMES\n",currMovieData.records.size());
currMovieData.dump(osRecordingMovie, false);
movieMode = MOVIEMODE_RECORD;

View File

@ -34,7 +34,9 @@ enum EMOVIEMODE
enum EMOVIECMD
{
MOVIECMD_MIC = 1,
MOVIECMD_RESET = 2,
MOVIECMD_LID = 4,
};
//RLDUTSBAYXWEG
@ -60,8 +62,8 @@ public:
//the disk format will support up to 64bit if necessary
uint8 commands;
bool command_reset() { return (commands&MOVIECMD_RESET)!=0; }
bool command_microphone() { return (commands&1)!=0; }
bool command_lid() { return (commands&4)!=0; }
bool command_microphone() { return (commands&MOVIECMD_MIC)!=0; }
bool command_lid() { return (commands&MOVIECMD_LID)!=0; }
void toggleBit(int bit)
{
@ -189,20 +191,19 @@ extern EMOVIEMODE movieMode; //adelikat: main needs this for frame counter disp
extern MovieData currMovieData; //adelikat: main needs this for frame counter display
extern bool movie_reset_command;
extern bool movie_lid;
bool FCEUI_MovieGetInfo(std::istream* fp, MOVIE_INFO& info, bool skipFrameCount);
void _CDECL_ FCEUI_SaveMovie(const char *fname, std::wstring author, int flag, std::string sramfname);
void _CDECL_ FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe);
void FCEUI_StopMovie();
void FCEUMOV_AddInputState();
void NDS_setTouchFromMovie(void);
void FCEUMOV_HandlePlayback();
void FCEUMOV_HandleRecording();
void mov_savestate(std::ostream* os);
bool mov_loadstate(std::istream* is, int size);
void LoadFM2_binarychunk(MovieData& movieData, std::istream* fp, int size);
bool LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader);
extern bool movie_readonly;
extern bool ShowInputDisplay;
extern int MicButtonPressed;
void FCEUI_MakeBackupMovie(bool dispMessage);
#endif

View File

@ -564,16 +564,16 @@ static FORCEINLINE void pixel(int adr,float r, float g, float b, float invu, flo
FragmentColor shaderOutput;
shader.shade(shaderOutput);
//alpha test (don't have any test cases for this...? is it in the right place...?)
if(gfx3d.enableAlphaTest)
{
if(shaderOutput.a < gfx3d.alphaTestRef)
goto rejected_fragment;
}
//we shouldnt do any of this if we generated a totally transparent pixel
if(shaderOutput.a != 0)
{
//alpha test (don't have any test cases for this...? is it in the right place...?)
if(gfx3d.enableAlphaTest)
{
if(shaderOutput.a < gfx3d.alphaTestRef)
goto rejected_fragment;
}
//handle polyids
bool isOpaquePixel = shaderOutput.a == 31;
if(isOpaquePixel)
@ -970,12 +970,13 @@ static void SoftRastVramReconfigureSignal() {
static void SoftRastFramebufferProcess()
{
// lack of edge marking was bugging me so I took a stab at
// making it more accurate so it could be reenabled.
// the best test case I know of for this feature is Sonic Rush:
// this looks ok although it's still pretty much a hack,
// it needs to be redone with low-level accuracy at some point,
// but that should probably wait until the shape renderer is more accurate.
// a good test case for edge marking is Sonic Rush:
// - the edges are completely sharp/opaque on the very brief title screen intro,
// - the level-start intro gets a pseudo-antialiasing effect around the silhouette,
// - the character edges in-level are clearly smoothed/transparent, but show well through shield powerups
// - the character edges in-level are clearly transparent, and also show well through shield powerups.
if(gfx3d.enableEdgeMarking)
{
//TODO - need to test and find out whether these get grabbed at flush time, or at render time
@ -1003,7 +1004,7 @@ static void SoftRastFramebufferProcess()
// > is used instead of != to prevent double edges
// between overlapping polys of different IDs.
// also note that the edge generally goes on the outside, not the inside,
// also note that the edge generally goes on the outside, not the inside, (maybe needs to change later)
// and that polys with the same edge color can make edges against each other.
FragmentColor edgeColor = edgeMarkColors[self>>3];

View File

@ -40,6 +40,7 @@
#include "readwrite.h"
#include "gfx3d.h"
#include "movie.h"
#include "mic.h"
#include "path.h"
@ -594,7 +595,7 @@ void savestate_slot(int num)
else
{
osd->setLineColor(255, 0, 0);
osd->addLine("Error save to %i slot", num);
osd->addLine("Error saving %i slot", num);
return;
}
@ -627,7 +628,7 @@ void loadstate_slot(int num)
else
{
osd->setLineColor(255, 0, 0);
osd->addLine("Error from load %i slot", num);
osd->addLine("Error loading %i slot", num);
}
}
@ -995,6 +996,7 @@ static void writechunks(std::ostream* os) {
savestate_WriteChunk(os,61,mmu_savestate);
savestate_WriteChunk(os,7,gpu_savestate);
savestate_WriteChunk(os,8,spu_savestate);
savestate_WriteChunk(os,81,mic_savestate);
savestate_WriteChunk(os,90,SF_GFX3D);
savestate_WriteChunk(os,91,gfx3d_savestate);
savestate_WriteChunk(os,100,SF_MOVIE);
@ -1026,6 +1028,7 @@ static bool ReadStateChunks(std::istream* is, s32 totalsize)
case 61: if(!mmu_loadstate(is,size)) ret=false; break;
case 7: if(!gpu_loadstate(is,size)) ret=false; break;
case 8: if(!spu_loadstate(is,size)) ret=false; break;
case 81: if(!mic_loadstate(is,size)) ret=false; break;
case 90: if(!ReadStateChunk(is,SF_GFX3D,size)) ret=false; break;
case 91: if(!gfx3d_loadstate(is,size)) ret=false; break;
case 100: if(!ReadStateChunk(is,SF_MOVIE, size)) ret=false; break;

View File

@ -192,6 +192,18 @@ void WINCLASS::sizingMsg(WPARAM wParam, LPARAM lParam, LONG keepRatio)
rect->top -= rect->bottom - prevBottom;
rect->bottom = prevBottom;
}
// windows screws up the window size if the top of the window goes too high above the top of the screen
if(keepRatio & KEEPY)
{
int titleBarHeight = GetSystemMetrics(SM_CYSIZE);
int topExceeded = -(titleBarHeight + rect->top);
if(topExceeded > 0)
{
rect->top += topExceeded;
rect->bottom += topExceeded;
}
}
}
void WINCLASS::setClientSize(int width, int height)

View File

@ -182,8 +182,8 @@ void HK_StateQuickLoadSlot(int)
HK_StateLoadSlot(lastSaveState);
}
void HK_MicrophoneKeyDown(int) {MicButtonPressed =1;}
void HK_MicrophoneKeyUp(int) {MicButtonPressed =0;}
void HK_MicrophoneKeyDown(int) { NDS_setMic(1); }
void HK_MicrophoneKeyUp(int) { NDS_setMic(0); }
void HK_AutoHoldClearKeyDown(int) {
@ -247,23 +247,23 @@ void HK_StopMovie(int)
void HK_AutoHoldKeyDown(int) {AutoHoldPressed = true;}
void HK_AutoHoldKeyUp(int) {AutoHoldPressed = false;}
void HK_TurboRightKeyDown(int) { Turbo.Right = true; }
void HK_TurboRightKeyUp(int) { Turbo.Right = false; }
void HK_TurboRightKeyDown(int) { Turbo.R = true; }
void HK_TurboRightKeyUp(int) { Turbo.R = false; }
void HK_TurboLeftKeyDown(int) { Turbo.Left = true; }
void HK_TurboLeftKeyUp(int) { Turbo.Left = false; }
void HK_TurboLeftKeyDown(int) { Turbo.L = true; }
void HK_TurboLeftKeyUp(int) { Turbo.L = false; }
void HK_TurboRKeyDown(int) { Turbo.R = true; }
void HK_TurboRKeyUp(int) { Turbo.R = false; }
void HK_TurboRKeyDown(int) { Turbo.E = true; }
void HK_TurboRKeyUp(int) { Turbo.E = false; }
void HK_TurboLKeyDown(int) { Turbo.L = true; }
void HK_TurboLKeyUp(int) { Turbo.L = false; }
void HK_TurboLKeyDown(int) { Turbo.W = true; }
void HK_TurboLKeyUp(int) { Turbo.W = false; }
void HK_TurboDownKeyDown(int) { Turbo.Down = true; }
void HK_TurboDownKeyUp(int) { Turbo.Down = false; }
void HK_TurboDownKeyDown(int) { Turbo.D = true; }
void HK_TurboDownKeyUp(int) { Turbo.D = false; }
void HK_TurboUpKeyDown(int) { Turbo.Up = true; }
void HK_TurboUpKeyUp(int) { Turbo.Up = false; }
void HK_TurboUpKeyDown(int) { Turbo.U = true; }
void HK_TurboUpKeyUp(int) { Turbo.U = false; }
void HK_TurboBKeyDown(int) { Turbo.B = true; }
void HK_TurboBKeyUp(int) { Turbo.B = false; }
@ -277,11 +277,11 @@ void HK_TurboXKeyUp(int) { Turbo.X = false; }
void HK_TurboYKeyDown(int) { Turbo.Y = true; }
void HK_TurboYKeyUp(int) { Turbo.Y = false; }
void HK_TurboStartKeyDown(int) { Turbo.Start = true; }
void HK_TurboStartKeyUp(int) { Turbo.Start = false; }
void HK_TurboStartKeyDown(int) { Turbo.S = true; }
void HK_TurboStartKeyUp(int) { Turbo.S = false; }
void HK_TurboSelectKeyDown(int) { Turbo.Select = true; }
void HK_TurboSelectKeyUp(int) { Turbo.Select = false; }
void HK_TurboSelectKeyDown(int) { Turbo.T = true; }
void HK_TurboSelectKeyUp(int) { Turbo.T = false; }
void HK_NextSaveSlot(int) {
lastSaveState++;

View File

@ -246,6 +246,8 @@ SGuitar DefaultGuitar = { false, 'E', 'R', 'T', 'Y' };
SGuitar Guitar;
u8 guitarState = 0;
bool allowUpAndDown = false;
extern volatile bool paused;
#define MAXKEYPAD 15
@ -412,6 +414,8 @@ static void LoadInputConfig()
DO(A); DO(B); DO(X); DO(Y);
DO(L); DO(R);
#undef DO
allowUpAndDown = GetPrivateProfileInt("Controls","AllowUpAndDown",0,IniName) != 0;
}
static void WriteControl(char* name, WORD val)
@ -429,6 +433,8 @@ static void SaveInputConfig()
DO(A); DO(B); DO(X); DO(Y);
DO(L); DO(R);
#undef DO
WritePrivateProfileInt("Controls","AllowUpAndDown",allowUpAndDown?1:0,IniName);
}
BOOL di_init()
@ -1879,10 +1885,10 @@ void EnableDisableKeyFields (int index, HWND hDlg)
enableUnTurboable = false;
}
EnableWindow(GetDlgItem(hDlg,IDC_UPLEFT), false);
EnableWindow(GetDlgItem(hDlg,IDC_UPRIGHT), false);
EnableWindow(GetDlgItem(hDlg,IDC_DWNRIGHT), false);
EnableWindow(GetDlgItem(hDlg,IDC_DWNLEFT), false);
//EnableWindow(GetDlgItem(hDlg,IDC_UPLEFT), false);
//EnableWindow(GetDlgItem(hDlg,IDC_UPRIGHT), false);
//EnableWindow(GetDlgItem(hDlg,IDC_DWNRIGHT), false);
//EnableWindow(GetDlgItem(hDlg,IDC_DWNLEFT), false);
EnableWindow(GetDlgItem(hDlg,IDC_DEBUG), false);
EnableWindow(GetDlgItem(hDlg,IDC_LID), true);
}
@ -1954,7 +1960,8 @@ switch(msg)
//SendDlgItemMessage(hDlg,IDC_JPCOMBO,CB_SETCURSEL,(WPARAM)0,0);
//SendDlgItemMessage(hDlg,IDC_JPTOGGLE,BM_SETCHECK, Joypad[index].Enabled ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
//SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, Settings.UpAndDown ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
SendDlgItemMessage(hDlg,IDC_ALLOWLEFTRIGHT,BM_SETCHECK, allowUpAndDown ? (WPARAM)BST_CHECKED : (WPARAM)BST_UNCHECKED, 0);
set_buttoninfo(index,hDlg);
@ -2068,7 +2075,7 @@ switch(msg)
break;
case IDOK:
//Settings.UpAndDown = IsDlgButtonChecked(hDlg, IDC_ALLOWLEFTRIGHT);
allowUpAndDown = IsDlgButtonChecked(hDlg, IDC_ALLOWLEFTRIGHT) != 0;
SaveInputConfig();
EndDialog(hDlg,0);
break;
@ -2181,158 +2188,189 @@ void S9xWinScanJoypads ()
for (int J = 0; J < 8; J++)
{
if (Joypad [J].Enabled)
{
// toggle checks
{
PadState = 0;
PadState |= ToggleJoypadStorage[J].Left||TurboToggleJoypadStorage[J].Left ? LEFT_MASK : 0;
PadState |= ToggleJoypadStorage[J].Right||TurboToggleJoypadStorage[J].Right ? RIGHT_MASK : 0;
PadState |= ToggleJoypadStorage[J].Up||TurboToggleJoypadStorage[J].Up ? UP_MASK : 0;
PadState |= ToggleJoypadStorage[J].Down||TurboToggleJoypadStorage[J].Down ? DOWN_MASK : 0;
PadState |= ToggleJoypadStorage[J].Start||TurboToggleJoypadStorage[J].Start ? START_MASK : 0;
PadState |= ToggleJoypadStorage[J].Select||TurboToggleJoypadStorage[J].Select ? SELECT_MASK : 0;
PadState |= ToggleJoypadStorage[J].Lid||TurboToggleJoypadStorage[J].Lid ? LID_MASK : 0;
PadState |= ToggleJoypadStorage[J].Debug||TurboToggleJoypadStorage[J].Debug ? DEBUG_MASK : 0;
PadState |= ToggleJoypadStorage[J].A||TurboToggleJoypadStorage[J].A ? A_MASK : 0;
PadState |= ToggleJoypadStorage[J].B||TurboToggleJoypadStorage[J].B ? B_MASK : 0;
PadState |= ToggleJoypadStorage[J].X||TurboToggleJoypadStorage[J].X ? X_MASK : 0;
PadState |= ToggleJoypadStorage[J].Y||TurboToggleJoypadStorage[J].Y ? Y_MASK : 0;
PadState |= ToggleJoypadStorage[J].L||TurboToggleJoypadStorage[J].L ? L_MASK : 0;
PadState |= ToggleJoypadStorage[J].R||TurboToggleJoypadStorage[J].R ? R_MASK : 0;
}
// auto-hold AND regular key/joystick presses
if(S9xGetState(Joypad[J+8].Left))
{
PadState ^= (!S9xGetState(Joypad[J].R)||!S9xGetState(Joypad[J+8].R)) ? R_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].L)||!S9xGetState(Joypad[J+8].L)) ? L_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].X)||!S9xGetState(Joypad[J+8].X)) ? X_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].A)||!S9xGetState(Joypad[J+8].A)) ? A_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Right)) ? RIGHT_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Right_Up)) ? RIGHT_MASK + UP_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Right_Down)) ? RIGHT_MASK + DOWN_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Left)) ? LEFT_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Left_Up)) ? LEFT_MASK + UP_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Left_Down)) ? LEFT_MASK + DOWN_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Down)) ? DOWN_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Up)) ? UP_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Start)||!S9xGetState(Joypad[J+8].Start)) ? START_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Select)||!S9xGetState(Joypad[J+8].Select)) ? SELECT_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Y)||!S9xGetState(Joypad[J+8].Y)) ? Y_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].B)||!S9xGetState(Joypad[J+8].B)) ? B_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Lid)||!S9xGetState(Joypad[J+8].Lid)) ? LID_MASK : 0;
PadState ^= (!S9xGetState(Joypad[J].Debug)||!S9xGetState(Joypad[J+8].Debug)) ? DEBUG_MASK : 0;
}
bool turbofy = !S9xGetState(Joypad[J+8].Up); // All Mod for turbo
u32 TurboMask = 0;
//handle turbo case! (autofire / auto-fire)
if(turbofy || ((TurboMask&A_MASK))&&(PadState&A_MASK) || !S9xGetState(Joypad[J+8].A )) PadState^=(joypads[J]&A_MASK);
if(turbofy || ((TurboMask&B_MASK))&&(PadState&B_MASK) || !S9xGetState(Joypad[J+8].B )) PadState^=(joypads[J]&B_MASK);
if(turbofy || ((TurboMask&Y_MASK))&&(PadState&Y_MASK) || !S9xGetState(Joypad[J+8].Y )) PadState^=(joypads[J]&Y_MASK);
if(turbofy || ((TurboMask&X_MASK))&&(PadState&X_MASK) || !S9xGetState(Joypad[J+8].X )) PadState^=(joypads[J]&X_MASK);
if(turbofy || ((TurboMask&L_MASK))&&(PadState&L_MASK) || !S9xGetState(Joypad[J+8].L )) PadState^=(joypads[J]&L_MASK);
if(turbofy || ((TurboMask&R_MASK))&&(PadState&R_MASK) || !S9xGetState(Joypad[J+8].R )) PadState^=(joypads[J]&R_MASK);
if(turbofy || ((TurboMask&START_MASK))&&(PadState&START_MASK) || !S9xGetState(Joypad[J+8].Start )) PadState^=(joypads[J]&START_MASK);
if(turbofy || ((TurboMask&SELECT_MASK))&&(PadState&SELECT_MASK) || !S9xGetState(Joypad[J+8].Select)) PadState^=(joypads[J]&SELECT_MASK);
if(turbofy || ((TurboMask&DEBUG_MASK))&&(PadState&DEBUG_MASK) || !S9xGetState(Joypad[J+8].Debug)) PadState^=(joypads[J]&DEBUG_MASK);
if( ((TurboMask&LEFT_MASK))&&(PadState&LEFT_MASK) ) PadState^=(joypads[J]&LEFT_MASK);
if( ((TurboMask&UP_MASK))&&(PadState&UP_MASK) ) PadState^=(joypads[J]&UP_MASK);
if( ((TurboMask&RIGHT_MASK))&&(PadState&RIGHT_MASK) ) PadState^=(joypads[J]&RIGHT_MASK);
if( ((TurboMask&DOWN_MASK))&&(PadState&DOWN_MASK) ) PadState^=(joypads[J]&DOWN_MASK);
if( ((TurboMask&LID_MASK))&&(PadState&LID_MASK) ) PadState^=(joypads[J]&LID_MASK);
if(TurboToggleJoypadStorage[J].A ) PadState^=(joypads[J]&A_MASK);
if(TurboToggleJoypadStorage[J].B ) PadState^=(joypads[J]&B_MASK);
if(TurboToggleJoypadStorage[J].Y ) PadState^=(joypads[J]&Y_MASK);
if(TurboToggleJoypadStorage[J].X ) PadState^=(joypads[J]&X_MASK);
if(TurboToggleJoypadStorage[J].L ) PadState^=(joypads[J]&L_MASK);
if(TurboToggleJoypadStorage[J].R ) PadState^=(joypads[J]&R_MASK);
if(TurboToggleJoypadStorage[J].Start ) PadState^=(joypads[J]&START_MASK);
if(TurboToggleJoypadStorage[J].Select) PadState^=(joypads[J]&SELECT_MASK);
if(TurboToggleJoypadStorage[J].Left ) PadState^=(joypads[J]&LEFT_MASK);
if(TurboToggleJoypadStorage[J].Up ) PadState^=(joypads[J]&UP_MASK);
if(TurboToggleJoypadStorage[J].Right ) PadState^=(joypads[J]&RIGHT_MASK);
if(TurboToggleJoypadStorage[J].Down ) PadState^=(joypads[J]&DOWN_MASK);
if(TurboToggleJoypadStorage[J].Lid ) PadState^=(joypads[J]&LID_MASK);
if(TurboToggleJoypadStorage[J].Debug ) PadState^=(joypads[J]&DEBUG_MASK);
//end turbo case...
// enforce left+right/up+down disallowance here to
// avoid recording unused l+r/u+d that will cause desyncs
// when played back with l+r/u+d is allowed
//if(!Settings.UpAndDown)
//{
// if((PadState[1] & 2) != 0)
// PadState[1] &= ~(1);
// if((PadState[1] & 8) != 0)
// PadState[1] &= ~(4);
//}
{
int PadState = 0;
PadState |= (!S9xGetState(Joypad[J].R)) ? R_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].L)) ? L_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].X)) ? X_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].A)) ? A_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Right)) ? RIGHT_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Right_Up)) ? RIGHT_MASK|UP_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Right_Down)) ? RIGHT_MASK|DOWN_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Left)) ? LEFT_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Left_Up)) ? LEFT_MASK|UP_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Left_Down)) ? LEFT_MASK|DOWN_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Down)) ? DOWN_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Up)) ? UP_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Start)) ? START_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Select)) ? SELECT_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Y)) ? Y_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].B)) ? B_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Lid)) ? LID_MASK : 0;
PadState |= (!S9xGetState(Joypad[J].Debug)) ? DEBUG_MASK : 0;
joypads [J] = PadState | 0x80000000;
}
else
joypads [J] = 0;
}
// input from macro
//for (int J = 0; J < 8; J++)
//{
// if(MacroIsEnabled(J))
// {
// uint16 userPadState = joypads[J] & 0xFFFF;
// uint16 macroPadState = MacroInput(J);
// uint16 newPadState;
// switch(GUI.MacroInputMode)
// {
// case MACRO_INPUT_MOV:
// newPadState = macroPadState;
// break;
// case MACRO_INPUT_OR:
// newPadState = macroPadState | userPadState;
// break;
// case MACRO_INPUT_XOR:
// newPadState = macroPadState ^ userPadState;
// break;
// default:
// newPadState = userPadState;
// break;
// }
// PadState[0] = (uint8) ( newPadState & 0xFF);
// PadState[1] = (uint8) ((newPadState >> 8) & 0xFF);
// // enforce left+right/up+down disallowance here to
// // avoid recording unused l+r/u+d that will cause desyncs
// // when played back with l+r/u+d is allowed
// if(!Settings.UpAndDown)
// {
// if((PadState[1] & 2) != 0)
// PadState[1] &= ~(1);
// if((PadState[1] & 8) != 0)
// PadState[1] &= ~(4);
// }
// joypads [J] = PadState [0] | (PadState [1] << 8) | 0x80000000;
// }
//}
//#ifdef NETPLAY_SUPPORT
// if (Settings.NetPlay)
// {
// // Send joypad position update to server
// S9xNPSendJoypadUpdate (joypads [GUI.NetplayUseJoypad1 ? 0 : NetPlay.Player-1]);
//
// // set input from network
// for (int J = 0; J < NP_MAX_CLIENTS; J++)
// joypads[J] = S9xNPGetJoypad (J);
// }
//#endif
}
}
}
//void S9xOldAutofireAndStuff ()
//{
// // stuff ripped out of Snes9x that's no longer functional, at least for now
// for (int J = 0; J < 8; J++)
// {
// if (Joypad [J].Enabled)
// {
// // toggle checks
// {
// PadState = 0;
// PadState |= ToggleJoypadStorage[J].Left||TurboToggleJoypadStorage[J].Left ? LEFT_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Right||TurboToggleJoypadStorage[J].Right ? RIGHT_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Up||TurboToggleJoypadStorage[J].Up ? UP_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Down||TurboToggleJoypadStorage[J].Down ? DOWN_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Start||TurboToggleJoypadStorage[J].Start ? START_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Select||TurboToggleJoypadStorage[J].Select ? SELECT_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Lid||TurboToggleJoypadStorage[J].Lid ? LID_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Debug||TurboToggleJoypadStorage[J].Debug ? DEBUG_MASK : 0;
// PadState |= ToggleJoypadStorage[J].A||TurboToggleJoypadStorage[J].A ? A_MASK : 0;
// PadState |= ToggleJoypadStorage[J].B||TurboToggleJoypadStorage[J].B ? B_MASK : 0;
// PadState |= ToggleJoypadStorage[J].X||TurboToggleJoypadStorage[J].X ? X_MASK : 0;
// PadState |= ToggleJoypadStorage[J].Y||TurboToggleJoypadStorage[J].Y ? Y_MASK : 0;
// PadState |= ToggleJoypadStorage[J].L||TurboToggleJoypadStorage[J].L ? L_MASK : 0;
// PadState |= ToggleJoypadStorage[J].R||TurboToggleJoypadStorage[J].R ? R_MASK : 0;
// }
// // auto-hold AND regular key/joystick presses
// if(S9xGetState(Joypad[J+8].Left))
// {
// PadState ^= (!S9xGetState(Joypad[J].R)||!S9xGetState(Joypad[J+8].R)) ? R_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].L)||!S9xGetState(Joypad[J+8].L)) ? L_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].X)||!S9xGetState(Joypad[J+8].X)) ? X_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].A)||!S9xGetState(Joypad[J+8].A)) ? A_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Right)) ? RIGHT_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Right_Up)) ? RIGHT_MASK + UP_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Right_Down)) ? RIGHT_MASK + DOWN_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Left)) ? LEFT_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Left_Up)) ? LEFT_MASK + UP_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Left_Down)) ? LEFT_MASK + DOWN_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Down)) ? DOWN_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Up)) ? UP_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Start)||!S9xGetState(Joypad[J+8].Start)) ? START_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Select)||!S9xGetState(Joypad[J+8].Select)) ? SELECT_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Y)||!S9xGetState(Joypad[J+8].Y)) ? Y_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].B)||!S9xGetState(Joypad[J+8].B)) ? B_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Lid)||!S9xGetState(Joypad[J+8].Lid)) ? LID_MASK : 0;
// PadState ^= (!S9xGetState(Joypad[J].Debug)||!S9xGetState(Joypad[J+8].Debug)) ? DEBUG_MASK : 0;
// }
//
// bool turbofy = !S9xGetState(Joypad[J+8].Up); // All Mod for turbo
//
// u32 TurboMask = 0;
//
// //handle turbo case! (autofire / auto-fire)
// if(turbofy || ((TurboMask&A_MASK))&&(PadState&A_MASK) || !S9xGetState(Joypad[J+8].A )) PadState^=(joypads[J]&A_MASK);
// if(turbofy || ((TurboMask&B_MASK))&&(PadState&B_MASK) || !S9xGetState(Joypad[J+8].B )) PadState^=(joypads[J]&B_MASK);
// if(turbofy || ((TurboMask&Y_MASK))&&(PadState&Y_MASK) || !S9xGetState(Joypad[J+8].Y )) PadState^=(joypads[J]&Y_MASK);
// if(turbofy || ((TurboMask&X_MASK))&&(PadState&X_MASK) || !S9xGetState(Joypad[J+8].X )) PadState^=(joypads[J]&X_MASK);
// if(turbofy || ((TurboMask&L_MASK))&&(PadState&L_MASK) || !S9xGetState(Joypad[J+8].L )) PadState^=(joypads[J]&L_MASK);
// if(turbofy || ((TurboMask&R_MASK))&&(PadState&R_MASK) || !S9xGetState(Joypad[J+8].R )) PadState^=(joypads[J]&R_MASK);
// if(turbofy || ((TurboMask&START_MASK))&&(PadState&START_MASK) || !S9xGetState(Joypad[J+8].Start )) PadState^=(joypads[J]&START_MASK);
// if(turbofy || ((TurboMask&SELECT_MASK))&&(PadState&SELECT_MASK) || !S9xGetState(Joypad[J+8].Select)) PadState^=(joypads[J]&SELECT_MASK);
// if(turbofy || ((TurboMask&DEBUG_MASK))&&(PadState&DEBUG_MASK) || !S9xGetState(Joypad[J+8].Debug)) PadState^=(joypads[J]&DEBUG_MASK);
// if( ((TurboMask&LEFT_MASK))&&(PadState&LEFT_MASK) ) PadState^=(joypads[J]&LEFT_MASK);
// if( ((TurboMask&UP_MASK))&&(PadState&UP_MASK) ) PadState^=(joypads[J]&UP_MASK);
// if( ((TurboMask&RIGHT_MASK))&&(PadState&RIGHT_MASK) ) PadState^=(joypads[J]&RIGHT_MASK);
// if( ((TurboMask&DOWN_MASK))&&(PadState&DOWN_MASK) ) PadState^=(joypads[J]&DOWN_MASK);
// if( ((TurboMask&LID_MASK))&&(PadState&LID_MASK) ) PadState^=(joypads[J]&LID_MASK);
//
// if(TurboToggleJoypadStorage[J].A ) PadState^=(joypads[J]&A_MASK);
// if(TurboToggleJoypadStorage[J].B ) PadState^=(joypads[J]&B_MASK);
// if(TurboToggleJoypadStorage[J].Y ) PadState^=(joypads[J]&Y_MASK);
// if(TurboToggleJoypadStorage[J].X ) PadState^=(joypads[J]&X_MASK);
// if(TurboToggleJoypadStorage[J].L ) PadState^=(joypads[J]&L_MASK);
// if(TurboToggleJoypadStorage[J].R ) PadState^=(joypads[J]&R_MASK);
// if(TurboToggleJoypadStorage[J].Start ) PadState^=(joypads[J]&START_MASK);
// if(TurboToggleJoypadStorage[J].Select) PadState^=(joypads[J]&SELECT_MASK);
// if(TurboToggleJoypadStorage[J].Left ) PadState^=(joypads[J]&LEFT_MASK);
// if(TurboToggleJoypadStorage[J].Up ) PadState^=(joypads[J]&UP_MASK);
// if(TurboToggleJoypadStorage[J].Right ) PadState^=(joypads[J]&RIGHT_MASK);
// if(TurboToggleJoypadStorage[J].Down ) PadState^=(joypads[J]&DOWN_MASK);
// if(TurboToggleJoypadStorage[J].Lid ) PadState^=(joypads[J]&LID_MASK);
// if(TurboToggleJoypadStorage[J].Debug ) PadState^=(joypads[J]&DEBUG_MASK);
// //end turbo case...
//
//
// // enforce left+right/up+down disallowance here to
// // avoid recording unused l+r/u+d that will cause desyncs
// // when played back with l+r/u+d is allowed
// //if(!allowUpAndDown)
// //{
// // if((PadState[1] & 2) != 0)
// // PadState[1] &= ~(1);
// // if((PadState[1] & 8) != 0)
// // PadState[1] &= ~(4);
// //}
//
// joypads [J] = PadState | 0x80000000;
// }
// else
// joypads [J] = 0;
// }
//
// // input from macro
// //for (int J = 0; J < 8; J++)
// //{
// // if(MacroIsEnabled(J))
// // {
// // uint16 userPadState = joypads[J] & 0xFFFF;
// // uint16 macroPadState = MacroInput(J);
// // uint16 newPadState;
//
// // switch(GUI.MacroInputMode)
// // {
// // case MACRO_INPUT_MOV:
// // newPadState = macroPadState;
// // break;
// // case MACRO_INPUT_OR:
// // newPadState = macroPadState | userPadState;
// // break;
// // case MACRO_INPUT_XOR:
// // newPadState = macroPadState ^ userPadState;
// // break;
// // default:
// // newPadState = userPadState;
// // break;
// // }
//
// // PadState[0] = (uint8) ( newPadState & 0xFF);
// // PadState[1] = (uint8) ((newPadState >> 8) & 0xFF);
//
// // // enforce left+right/up+down disallowance here to
// // // avoid recording unused l+r/u+d that will cause desyncs
// // // when played back with l+r/u+d is allowed
// // if(!allowUpAndDown)
// // {
// // if((PadState[1] & 2) != 0)
// // PadState[1] &= ~(1);
// // if((PadState[1] & 8) != 0)
// // PadState[1] &= ~(4);
// // }
//
// // joypads [J] = PadState [0] | (PadState [1] << 8) | 0x80000000;
// // }
// //}
//
////#ifdef NETPLAY_SUPPORT
//// if (Settings.NetPlay)
//// {
//// // Send joypad position update to server
//// S9xNPSendJoypadUpdate (joypads [GUI.NetplayUseJoypad1 ? 0 : NetPlay.Player-1]);
////
//// // set input from network
//// for (int J = 0; J < NP_MAX_CLIENTS; J++)
//// joypads[J] = S9xNPGetJoypad (J);
//// }
////#endif
//}
void input_feedback(BOOL enable)
{
if (!Feedback) return;
@ -2357,43 +2395,82 @@ void input_init()
FeedbackON = input_feedback;
}
void input_process()
// TODO: maybe some of this stuff should move back to NDSSystem.cpp?
// I don't know which is the better place for it.
static void StepManualTurbo();
static void ApplyAntipodalRestriction(buttonstruct<bool>& pad);
static void SetManualTurbo(buttonstruct<bool>& pad);
static void RunAntipodalRestriction(const buttonstruct<bool>& pad);
// may run multiple times per frame.
// gets the user input and puts in a request with NDSSystem about it,
// and updates input-related state that needs to update even while paused.
void input_acquire()
{
u32 oldInput = joypads[0];
S9xWinScanJoypads();
//not appropriate right now in desmume
//if (paused) return;
buttonstruct<bool> buttons = {};
buttons.R = (joypads[0] & RIGHT_MASK)!=0;
buttons.L = (joypads[0] & LEFT_MASK)!=0;
buttons.D = (joypads[0] & DOWN_MASK)!=0;
buttons.U = (joypads[0] & UP_MASK)!=0;
buttons.S = (joypads[0] & START_MASK)!=0;
buttons.T = (joypads[0] & SELECT_MASK)!=0;
buttons.B = (joypads[0] & B_MASK)!=0;
buttons.A = (joypads[0] & A_MASK)!=0;
buttons.Y = (joypads[0] & Y_MASK)!=0;
buttons.X = (joypads[0] & X_MASK)!=0;
buttons.W = (joypads[0] & L_MASK)!=0;
buttons.E = (joypads[0] & R_MASK)!=0;
buttons.G = (joypads[0] & DEBUG_MASK)!=0;
buttons.F = (joypads[0] & LID_MASK)!=0;
bool R = (joypads[0] & RIGHT_MASK)!=0;
bool L = (joypads[0] & LEFT_MASK)!=0;
bool D = (joypads[0] & DOWN_MASK)!=0;
bool U = (joypads[0] & UP_MASK)!=0;
bool T = (joypads[0] & START_MASK)!=0;
bool S = (joypads[0] & SELECT_MASK)!=0;
bool B = (joypads[0] & B_MASK)!=0;
bool A = (joypads[0] & A_MASK)!=0;
bool Y = (joypads[0] & Y_MASK)!=0;
bool X = (joypads[0] & X_MASK)!=0;
bool W = (joypads[0] & L_MASK)!=0;
bool E = (joypads[0] & R_MASK)!=0;
bool G = (joypads[0] & DEBUG_MASK)!=0;
bool F = (joypads[0] & LID_MASK)!=0;
// take care of toggling the auto-hold flags.
if(AutoHoldPressed)
{
if(buttons.R && !(oldInput & RIGHT_MASK)) AutoHold.R ^= true;
if(buttons.L && !(oldInput & LEFT_MASK)) AutoHold.L ^= true;
if(buttons.D && !(oldInput & DOWN_MASK)) AutoHold.D ^= true;
if(buttons.U && !(oldInput & UP_MASK)) AutoHold.U ^= true;
if(buttons.S && !(oldInput & START_MASK)) AutoHold.S ^= true;
if(buttons.T && !(oldInput & SELECT_MASK)) AutoHold.T ^= true;
if(buttons.B && !(oldInput & B_MASK)) AutoHold.B ^= true;
if(buttons.A && !(oldInput & A_MASK)) AutoHold.A ^= true;
if(buttons.Y && !(oldInput & Y_MASK)) AutoHold.Y ^= true;
if(buttons.X && !(oldInput & X_MASK)) AutoHold.X ^= true;
if(buttons.W && !(oldInput & L_MASK)) AutoHold.W ^= true;
if(buttons.E && !(oldInput & R_MASK)) AutoHold.E ^= true;
}
if(AutoHoldPressed && R) AutoHold.Right ^= true;
if(AutoHoldPressed && L) AutoHold.Left ^= true;
if(AutoHoldPressed && D) AutoHold.Down ^= true;
if(AutoHoldPressed && U) AutoHold.Up ^= true;
if(AutoHoldPressed && T) AutoHold.Select ^= true;
if(AutoHoldPressed && S) AutoHold.Start ^= true;
if(AutoHoldPressed && B) AutoHold.B ^= true;
if(AutoHoldPressed && A) AutoHold.A ^= true;
if(AutoHoldPressed && Y) AutoHold.Y ^= true;
if(AutoHoldPressed && X) AutoHold.X ^= true;
if(AutoHoldPressed && W) AutoHold.L ^= true;
if(AutoHoldPressed && E) AutoHold.R ^= true;
// update upAndDown timers
RunAntipodalRestriction(buttons);
NDS_setPad( R, L, D, U, T, S, B, A, Y, X, W, E, G, F);
// apply any autofire that requires the user to be
// actively holding a button in order to trigger it
SetManualTurbo(buttons);
// let's actually apply auto-hold here too,
// even though this is supposed to be the "raw" user input,
// since things seem to work out better this way (more useful input display, for one thing),
// and it kind of makes sense to think of auto-held keys as
// a direct extension of what the user is physically trying to press.
for(int i = 0; i < ARRAY_SIZE(buttons.array); i++)
buttons.array[i] ^= AutoHold.array[i];
// set initial input request
NDS_setPad(
buttons.R, buttons.L, buttons.D, buttons.U,
buttons.T, buttons.S, buttons.B, buttons.A,
buttons.Y, buttons.X, buttons.W, buttons.E,
buttons.G, buttons.F);
// TODO: this part hasn't been revised yet,
// but guitarGrip_setKey should only request a change (like NDS_setPad does)
if (Guitar.Enabled)
{
bool gG=!S9xGetState(Guitar.GREEN);
@ -2404,6 +2481,74 @@ void input_process()
}
}
// only runs once per frame (always after input_acquire has been called at least once).
// applies transformations to the user's input,
// and updates input-related state that needs to update once per frame.
void input_process()
{
UserButtons& input = NDS_getProcessingUserInput().buttons;
// prevent left+right/up+down if that option is set to not allow it
ApplyAntipodalRestriction(input);
// step turbo frame timers
StepManualTurbo();
// TODO: things like macros or "hands free" turbo/autofire
// should probably be applied here.
}
static bool turbo[4] = {true, false, true, false};
static void StepManualTurbo()
{
for (int i = 0; i < ARRAY_SIZE(TurboTime.array); i++)
{
TurboTime.array[i]++;
if(!Turbo.array[i] || TurboTime.array[i] >= (int)ARRAY_SIZE(turbo))
TurboTime.array[i] = 0; // reset timer if the button isn't pressed or we overran
}
}
static void SetManualTurbo(buttonstruct<bool>& pad)
{
for (int i = 0; i < ARRAY_SIZE(pad.array); i++)
if(Turbo.array[i])
pad.array[i] = turbo[TurboTime.array[i]];
}
static buttonstruct<int> cardinalHeldTime = {0};
static void RunAntipodalRestriction(const buttonstruct<bool>& pad)
{
if(allowUpAndDown)
return;
pad.U ? (cardinalHeldTime.U++) : (cardinalHeldTime.U=0);
pad.D ? (cardinalHeldTime.D++) : (cardinalHeldTime.D=0);
pad.L ? (cardinalHeldTime.L++) : (cardinalHeldTime.L=0);
pad.R ? (cardinalHeldTime.R++) : (cardinalHeldTime.R=0);
}
static void ApplyAntipodalRestriction(buttonstruct<bool>& pad)
{
if(allowUpAndDown)
return;
// give preference to whichever direction was most recently pressed
if(pad.U && pad.D)
if(cardinalHeldTime.U < cardinalHeldTime.D)
pad.D = false;
else
pad.U = false;
if(pad.L && pad.R)
if(cardinalHeldTime.L < cardinalHeldTime.R)
pad.R = false;
else
pad.L = false;
}
static void set_hotkeyinfo(HWND hDlg)
{
HotkeyPage page = (HotkeyPage) SendDlgItemMessage(hDlg,IDC_HKCOMBO,CB_GETCURSEL,0,0);

View File

@ -110,6 +110,7 @@ extern SJoypad TurboToggleJoypadStorage[8];
void RunInputConfig();
void RunHotkeyConfig();
void input_acquire();
void input_process();
struct SGuitar {

View File

@ -439,26 +439,44 @@ void SetMinWindowSize()
MainWindow->setMinSize(video.rotatedwidthgap(), video.rotatedheightgap());
}
void translateXY(s32& x, s32& y)
// input x,y should be windows client-space coords already at 1x scaling.
// output is in pixels relative to the top-left of the chosen screen.
// the gap between screens (if any) is subtracted away from the output y.
void ToDSScreenRelativeCoords(s32& x, s32& y, bool bottomScreen)
{
s32 tx=x, ty=y;
int gapSize = video.screengap / video.ratio();
// first deal with rotation
switch(video.rotation)
{
case 90:
x = ty;
y = 191-tx;
y = (383+gapSize)-tx;
break;
case 180:
x = 255-tx;
y = 383-ty;
y -= 192;
y = (383+gapSize)-ty;
break;
case 270:
x = 255-ty;
y = (tx-192-(video.screengap/video.ratio()));
y = tx;
break;
}
// then deal with screen gap
if(y > 191 + gapSize)
y -= gapSize;
else if(y > 191 + gapSize/2)
y = 192;
else if(y > 191)
y = 191;
// finally, make it relative to the correct screen
if(bottomScreen)
y -= 192;
}
// END Rotation definitions
void UpdateRecentRomsMenu()
@ -784,7 +802,7 @@ static void DD_DoDisplay()
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags=DDSD_ALL;
res = lpBackSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
res = lpBackSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (res==DDERR_SURFACELOST)
{
@ -1056,9 +1074,16 @@ DWORD WINAPI run()
{
while(execute)
{
input_process();
CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
FCEUMOV_AddInputState();
// the order of these function calls is very important
input_acquire();
NDS_beginProcessingInput();
{
input_process();
FCEUMOV_HandlePlayback();
CallRegisteredLuaFunctions(LUACALL_BEFOREEMULATION);
}
NDS_endProcessingInput();
FCEUMOV_HandleRecording();
{
Lock lock;
@ -2511,6 +2536,8 @@ bool first;
void FrameAdvance(bool state)
{
if(!romloaded)
return;
if(state) {
if(first) {
execute = TRUE;
@ -2656,8 +2683,8 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
DesEnableMenuItem(mainMenu, IDM_CHEATS_SEARCH, romloaded);
//DesEnableMenuItem(mainMenu, IDM_WIFISETTINGS, romloaded);
DesEnableMenuItem(mainMenu, IDM_RECORD_MOVIE, (romloaded && movieMode == MOVIEMODE_INACTIVE));
DesEnableMenuItem(mainMenu, IDM_PLAY_MOVIE, (romloaded && movieMode == MOVIEMODE_INACTIVE));
DesEnableMenuItem(mainMenu, IDM_RECORD_MOVIE, (romloaded /*&& movieMode == MOVIEMODE_INACTIVE*/));
DesEnableMenuItem(mainMenu, IDM_PLAY_MOVIE, (romloaded /*&& movieMode == MOVIEMODE_INACTIVE*/));
DesEnableMenuItem(mainMenu, IDM_STOPMOVIE, (romloaded && movieMode != MOVIEMODE_INACTIVE));
DesEnableMenuItem(mainMenu, ID_RAM_WATCH, romloaded);
@ -2929,6 +2956,8 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
break;
case WM_KEYDOWN:
if(paused)
input_acquire();
if(wParam != VK_PAUSE)
break;
case WM_SYSKEYDOWN:
@ -2940,6 +2969,8 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
break;
}
case WM_KEYUP:
if(paused)
input_acquire();
if(wParam != VK_PAUSE)
break;
case WM_SYSKEYUP:
@ -3060,16 +3091,14 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
x = x/video.ratio();
y = y/video.ratio();
if(HudEditorMode) {
if(HudEditorMode)
{
ToDSScreenRelativeCoords(x,y,false);
EditHud(x,y, &Hud);
}
else {
//translate for rotation
if (video.rotation != 0)
translateXY(x,y);
else
y-=192+(video.screengap/video.ratio());
else
{
ToDSScreenRelativeCoords(x,y,true);
if(x<0) x = 0; else if(x>255) x = 255;
if(y<0) y = 0; else if(y>192) y = 192;
NDS_setTouchPos(x, y);

View File

@ -8,15 +8,16 @@
Note : I added these notes because the microphone isn't
documented on GBATek.
*/
#include <windows.h>
#include "NDSSystem.h"
#include "../types.h"
#include "../debug.h"
#include "../mic.h"
#include "../movie.h"
#include "readwrite.h"
#include <iostream>
#include <fstream>
int MicDisplay;
int MicButtonPressed=0;
int SampleLoaded=0;
#define MIC_CHECKERR(hr) if(hr != MMSYSERR_NOERROR) return FALSE;
@ -31,6 +32,8 @@ static u16 Mic_BufPos;
static u8 Mic_WriteBuf;
static u8 Mic_PlayBuf;
static int micReadSamplePos=0;
static HWAVEIN waveIn;
static WAVEHDR waveHdr;
@ -150,6 +153,8 @@ void Mic_Reset()
Mic_WriteBuf = 0;
Mic_PlayBuf = 1;
micReadSamplePos = 0;
}
void Mic_DeInit()
@ -167,7 +172,6 @@ static const int random[32] = {0xB1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x28, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9};
static int x=0;
u8 Mic_ReadSample()
{
@ -177,28 +181,40 @@ u8 Mic_ReadSample()
u8 ret;
u8 tmp;
if(MicButtonPressed) {
if(NDS_getFinalUserInput().mic.micButtonPressed) {
if(SampleLoaded) {
//use a sample
tmp = samplebuffer[x >> 1];
x++;
if(x == samplebuffersize*2)
x=0;
//TODO: what if a movie is active?
// for now I'm going to hope that if anybody records a movie with a sample loaded,
// either they know what they're doing and plan to distribute the sample,
// or they're playing a game where it doesn't even matter or they never press the mic button.
tmp = samplebuffer[micReadSamplePos >> 1];
micReadSamplePos++;
if(micReadSamplePos == samplebuffersize*2)
micReadSamplePos=0;
} else {
//use the "random" values
tmp = random[x >> 1];
tmp = random[micReadSamplePos >> 1];
//tmp = rand()&0xFF;
x++;
if(x == ARRAY_SIZE(random)*2)
x=0;
micReadSamplePos++;
if(micReadSamplePos == ARRAY_SIZE(random)*2)
micReadSamplePos=0;
}
}
else {
//normal mic behavior
tmp = (u8)Mic_Buffer[Mic_PlayBuf][Mic_BufPos >> 1];
if(movieMode != MOVIEMODE_INACTIVE)
{
//normal mic behavior
tmp = (u8)Mic_Buffer[Mic_PlayBuf][Mic_BufPos >> 1];
}
else
{
//since we're not recording Mic_Buffer to the movie, use silence
tmp = 0;
}
//reset mic button buffer pos if not pressed
x=0;
micReadSamplePos=0;
}
if(Mic_BufPos & 0x1)
@ -220,4 +236,34 @@ u8 Mic_ReadSample()
}
return ret;
}
}
// maybe a bit paranoid...
void mic_savestate(std::ostream* os)
{
//version
write32le(0,os);
assert(MIC_BUFSIZE == 4096); // else needs new version
os->write((char*)Mic_Buffer[0], MIC_BUFSIZE);
os->write((char*)Mic_Buffer[1], MIC_BUFSIZE);
write16le(Mic_BufPos,os);
write8le(Mic_WriteBuf,os); // seems OK to save...
write8le(Mic_PlayBuf,os);
write32le(micReadSamplePos,os);
}
bool mic_loadstate(std::istream* is, int size)
{
int version;
if(read32le(&version,is) != 1) return false;
if(version > 0) { is->seekg(size-4, std::ios::cur); return true; }
is->read((char*)Mic_Buffer[0], MIC_BUFSIZE);
is->read((char*)Mic_Buffer[1], MIC_BUFSIZE);
read16le(&Mic_BufPos,is);
read8le(&Mic_WriteBuf,is);
read8le(&Mic_PlayBuf,is);
read32le(&micReadSamplePos,is);
return true;
}

View File

@ -25,11 +25,80 @@ inline std::string GetDlgItemText(HWND hDlg, int nIDDlgItem) {
}
// tests if a file is readable at the given location
// without changing whatever is there
static BOOL IsFileReadable(char* filePath)
{
if(!filePath || GetFileAttributes(filePath) == 0xFFFFFFFF)
return false;
FILE* file = fopen(filePath, "rb");
if(file)
fclose(file);
return file != 0;
}
// tests if a file is writable at the given location
// without changing whatever is there
static BOOL IsFileWritable(char* filePath)
{
if(!filePath)
return false;
bool didNotExist = GetFileAttributes(filePath) == 0xFFFFFFFF;
FILE* file = fopen(filePath, "ab");
if(file)
{
fclose(file);
if(didNotExist)
unlink(filePath);
return true;
}
return false;
}
// if there's no directory (only a filename), make it an absolute path,
// otherwise the user won't have any clue where the file actually is...
void FixRelativeMovieFilename(HWND hwndDlg, DWORD dlgItem)
{
char tempfname [MAX_PATH];
char fullfname [MAX_PATH];
GetDlgItemText(hwndDlg,dlgItem,tempfname,MAX_PATH);
// NOTE: if this puts the wrong path in, then the solution is to call SetCurrentDirectory beforehand,
// since if it's wrong then even without this code that's the wrong place it would get saved to.
// also, single-letter filenames are passed by here in case the user is deleting the path from the right and goes from "c:" to "c"
if(tempfname[0] && tempfname[1] && !strchr(tempfname, '/') && !strchr(tempfname, '\\') && !strchr(tempfname, ':')
&& GetFullPathName(tempfname,MAX_PATH-4,fullfname,NULL))
{
// store cursor position
int sel1=-1, sel2=0;
SendMessage(GetDlgItem(hwndDlg, dlgItem), EM_GETSEL, (WPARAM)&sel1, (LPARAM)&sel2);
// add dsm if no extension
if(!strchr(fullfname,'.'))
strcat(fullfname, ".dsm");
// replace text with the absolute path + extension
SetDlgItemText(hwndDlg, dlgItem, fullfname);
// keep cursor where user was typing
char* match = fullfname;
while(strstr(match+1, tempfname)) match = strstr(match+1, tempfname); // strrstr
if(match > fullfname)
{
sel1 += match - fullfname;
sel2 += match - fullfname;
SendMessage(GetDlgItem(hwndDlg, dlgItem), EM_SETSEL, sel1, sel2);
}
}
}
static char playfilename[MAX_PATH] = "";
void Describe(HWND hwndDlg)
{
std::fstream fs (playfilename);
std::fstream fs (playfilename, std::ios_base::in);
MovieData md;
LoadFM2(md, &fs, INT_MAX, false);
fs.close();
@ -47,7 +116,6 @@ void Describe(HWND hwndDlg)
SetDlgItemText(hwndDlg,IDC_MLENGTH,tmp);
SetDlgItemInt(hwndDlg,IDC_MFRAMES,num_frames,FALSE);
SetDlgItemText(hwndDlg, PM_FILENAME, playfilename);
SetDlgItemInt(hwndDlg,IDC_MRERECORDCOUNT,md.rerecordCount,FALSE);
SetDlgItemText(hwndDlg,IDC_MROM,md.romSerial.c_str());
}
@ -62,6 +130,7 @@ INT_PTR CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
switch(uMsg)
{
case WM_INITDIALOG:
{
SendDlgItemMessage(hwndDlg, IDC_CHECK_READONLY, BM_SETCHECK, replayreadonly?BST_CHECKED:BST_UNCHECKED, 0);
//Clear fields
@ -69,7 +138,16 @@ INT_PTR CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
SetWindowText(GetDlgItem(hwndDlg, IDC_MFRAMES), "");
SetWindowText(GetDlgItem(hwndDlg, IDC_MRERECORDCOUNT), "");
SetWindowText(GetDlgItem(hwndDlg, IDC_MROM), "");
return FALSE;
extern char curMovieFilename[512];
strncpy(playfilename, curMovieFilename, MAX_PATH);
playfilename[MAX_PATH-1] = '\0';
SetWindowText(GetDlgItem(hwndDlg, PM_FILENAME), playfilename);
SetFocus(GetDlgItem(hwndDlg, PM_FILENAME));
SendMessage(GetDlgItem(hwndDlg, PM_FILENAME), EM_SETSEL, 0, -1); // select all
} return FALSE;
case WM_COMMAND:
int wID = LOWORD(wParam);
@ -79,7 +157,7 @@ INT_PTR CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = MainWindow->getHWnd();
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile = filename;
@ -87,13 +165,12 @@ INT_PTR CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "dsm";
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
GetOpenFileName(&ofn);
strcpy(playfilename, filename);
Describe(hwndDlg);
if(GetOpenFileName(&ofn))
SetDlgItemText(hwndDlg, PM_FILENAME, filename);
return true;
case IDC_CHECK_READONLY:
replayreadonly ^= 1;
replayreadonly = IsDlgButtonChecked(hwndDlg, IDC_CHECK_READONLY) != 0;
return true;
case IDOK:
@ -106,11 +183,43 @@ INT_PTR CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
ZeroMemory(&playfilename, sizeof(playfilename));
EndDialog(hwndDlg, 0);
return true;
case PM_FILENAME:
switch(HIWORD(wParam))
{
case EN_CHANGE:
{
FixRelativeMovieFilename(hwndDlg, PM_FILENAME);
// disable the OK button if we can't read the file
char filename [MAX_PATH];
GetDlgItemText(hwndDlg,PM_FILENAME,filename,MAX_PATH);
EnableWindow(GetDlgItem(hwndDlg, IDOK), IsFileReadable(filename));
strcpy(playfilename, filename);
Describe(hwndDlg);
// force read-only to be checked if we can't write the file
if(!IsFileWritable(filename))
{
CheckDlgButton(hwndDlg, IDC_CHECK_READONLY, BST_CHECKED);
EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_READONLY), FALSE);
}
else
{
EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK_READONLY), TRUE);
}
}
break;
}
break;
}
}
return false;
}
int flag=0;
std::string sramfname;
@ -123,10 +232,11 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
int x; //temp vairable
switch(uMsg)
{
case WM_INITDIALOG:
CheckDlgButton(hwndDlg, IDC_START_FROM_SRAM, ((flag == 1) ? BST_CHECKED : BST_UNCHECKED));
case WM_INITDIALOG:
CheckDlgButton(hwndDlg, IDC_START_FROM_SRAM, ((flag == 1) ? BST_CHECKED : BST_UNCHECKED));
SetFocus(GetDlgItem(hwndDlg, IDC_EDIT_FILENAME));
return false;
return false;
case WM_COMMAND:
switch(LOWORD(wParam))
{
@ -139,7 +249,7 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
EndDialog(hwndDlg, 0);
}
return true;
}
}
case IDCANCEL:
EndDialog(hwndDlg, 0);
@ -149,26 +259,29 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
{
OPENFILENAME ofn;
char szChoice[MAX_PATH]={0};
GetDlgItemText(hwndDlg,IDC_EDIT_FILENAME,szChoice,MAX_PATH);
// browse button
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = MainWindow->getHWnd();
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = "Desmume Movie File (*.dsm)\0*.dsm\0All files(*.*)\0*.*\0\0";
ofn.lpstrFile = szChoice;
ofn.lpstrTitle = "Record a new movie";
ofn.lpstrDefExt = "dsm";
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
GetSaveFileName(&ofn);
//If user did not specify an extension, add .dsm for them
fname = szChoice;
x = fname.find_last_of(".");
if (x < 0)
fname.append(".dsm");
SetDlgItemText(hwndDlg, IDC_EDIT_FILENAME, fname.c_str());
if(GetSaveFileName(&ofn))
{
fname = szChoice;
/* // windows does this automatically, since lpstrDefExt is set
//If user did not specify an extension, add .dsm for them
x = fname.find_last_of(".");
if (x < 0)
fname.append(".dsm");
*/
SetDlgItemText(hwndDlg, IDC_EDIT_FILENAME, fname.c_str());
}
//if(GetSaveFileName(&ofn))
// UpdateRecordDialogPath(hwndDlg,szChoice);
@ -182,28 +295,46 @@ static INT_PTR CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
// browse button
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = MainWindow->getHWnd();
ofn.hwndOwner = hwndDlg;
ofn.lpstrFilter = "Desmume SRAM File (*.dsv)\0*.dsv\0All files(*.*)\0*.*\0\0";
ofn.lpstrFile = szChoice;
ofn.lpstrTitle = "Choose SRAM";
ofn.lpstrDefExt = "dsv";
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
GetOpenFileName(&ofn);
//If user did not specify an extension, add .dsm for them
fname = szChoice;
if(GetOpenFileName(&ofn))
{
fname = szChoice;
/* // windows does this automatically, since lpstrDefExt is set
//If user did not specify an extension, add .dsv for them
x = fname.find_last_of(".");
if (x < 0)
fname.append(".dsv");
SetDlgItemText(hwndDlg, IDC_EDIT_SRAMFILENAME, fname.c_str());
sramfname=(std::string)fname;
*/
SetDlgItemText(hwndDlg, IDC_EDIT_SRAMFILENAME, fname.c_str());
sramfname=(std::string)fname;
}
//if(GetSaveFileName(&ofn))
// UpdateRecordDialogPath(hwndDlg,szChoice);
return true;
}
case IDC_EDIT_FILENAME:
switch(HIWORD(wParam))
{
case EN_CHANGE:
{
FixRelativeMovieFilename(hwndDlg, IDC_EDIT_FILENAME);
// disable the OK button if we can't write to the file
char filename [MAX_PATH];
GetDlgItemText(hwndDlg,IDC_EDIT_FILENAME,filename,MAX_PATH);
EnableWindow(GetDlgItem(hwndDlg, IDOK), IsFileWritable(filename));
}
break;
}
break;
}
}

Binary file not shown.