- 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:
parent
bb7d9f16a4
commit
c20c88bdbc
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 [] =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -110,6 +110,7 @@ extern SJoypad TurboToggleJoypadStorage[8];
|
|||
|
||||
void RunInputConfig();
|
||||
void RunHotkeyConfig();
|
||||
void input_acquire();
|
||||
void input_process();
|
||||
|
||||
struct SGuitar {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
Loading…
Reference in New Issue