initial commit

This commit is contained in:
R-type
2015-12-14 14:00:35 +01:00
commit 5a96c0ca66
377 changed files with 149124 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
atari.res
+25
View File
@@ -0,0 +1,25 @@
/*
* atari.rc - Win32 port specific code
*
* Copyright (C) 2000 Krzysztof Nikiel
* Copyright (C) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
Icon1 ICON win32/atari1.ico
Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
#ifndef _ATARI_WIN32_H_
#define _ATARI_WIN32_H_
#define DIRECTINPUT_VERSION 0x0500
#include <dinput.h>
#include "akey.h"
#define MAXKEYNAMELENGTH 40
/* keyboard code key-value pairs */
/* for use in joystick button mapping */
typedef struct {
int keyvalue;
char* keyname;
} _keyref;
/* Set of keys that may be mapped to joystick/gamepad buttons */
/* If you add to this list, be sure to TEST them, not all keys work the same */
/* and may require additional code support. */
static const _keyref keyref[] = {
{AKEY_0, "0"}, {AKEY_1, "1"}, {AKEY_2, "2"}, {AKEY_3, "3"}, {AKEY_4, "4"},
{AKEY_5, "5"}, {AKEY_6, "6"}, {AKEY_7, "7"}, {AKEY_8, "8"}, {AKEY_9, "9"},
{AKEY_a, "a"}, {AKEY_b, "b"}, {AKEY_c, "c"}, {AKEY_d, "d"}, {AKEY_e, "e"},
{AKEY_f, "f"}, {AKEY_g, "g"}, {AKEY_h, "h"}, {AKEY_i, "i"}, {AKEY_j, "j"},
{AKEY_k, "k"}, {AKEY_l, "l"}, {AKEY_m, "m"}, {AKEY_n, "n"}, {AKEY_o, "o"},
{AKEY_p, "p"}, {AKEY_q, "q"}, {AKEY_r, "r"}, {AKEY_s, "s"}, {AKEY_t, "t"},
{AKEY_u, "u"}, {AKEY_v, "v"}, {AKEY_w, "w"}, {AKEY_x, "x"}, {AKEY_y, "y"},
{AKEY_z, "z"}, {AKEY_A, "A"}, {AKEY_B, "B"}, {AKEY_C, "C"}, {AKEY_D, "D"},
{AKEY_E, "E"}, {AKEY_F, "F"}, {AKEY_G, "G"}, {AKEY_H, "H"}, {AKEY_I, "I"},
{AKEY_J, "J"}, {AKEY_K, "K"}, {AKEY_L, "L"}, {AKEY_M, "M"}, {AKEY_N, "N"},
{AKEY_O, "O"}, {AKEY_P, "P"}, {AKEY_Q, "Q"}, {AKEY_R, "R"}, {AKEY_S, "S"},
{AKEY_T, "T"}, {AKEY_U, "U"}, {AKEY_V, "V"}, {AKEY_W, "W"}, {AKEY_X, "X"},
{AKEY_Y, "Y"}, {AKEY_Z, "Z"}, {AKEY_START, "START"}, {AKEY_SELECT, "SELECT"},
{AKEY_OPTION, "OPTION"}, {AKEY_RETURN, "RETURN"}, {AKEY_SPACE, "SPACE"}
};
static const int MAXKEYREFS = sizeof(keyref)/sizeof(*keyref);
/* keypad mode joydefs */
static const UBYTE joydefs[] =
{
DIK_NUMPAD0, /* fire */
DIK_NUMPAD7, /* up/left */
DIK_NUMPAD8, /* up */
DIK_NUMPAD9, /* up/right */
DIK_NUMPAD4, /* left */
DIK_NUMPAD6, /* right */
DIK_NUMPAD1, /* down/left */
DIK_NUMPAD2, /* down */
DIK_NUMPAD3, /* down/right */
};
/* keypad mode joymask */
static const UBYTE joymask[] =
{
INPUT_STICK_CENTRE, /* not used */
INPUT_STICK_UL, /* up/left */
INPUT_STICK_FORWARD, /* up */
INPUT_STICK_UR, /* up/right */
INPUT_STICK_LEFT, /* left */
INPUT_STICK_RIGHT, /* right */
INPUT_STICK_LL, /* down/left */
INPUT_STICK_BACK, /* down */
INPUT_STICK_LR, /* down/right */
};
/* keypad plus mode joydefs */
static const UBYTE joydefs_plus[] =
{
DIK_NUMPAD0, /* fire */
DIK_NUMPAD7, /* up/left */
DIK_NUMPAD8, /* up */
DIK_NUMPAD9, /* up/right */
DIK_NUMPAD4, /* left */
DIK_NUMPAD6, /* right */
DIK_NUMPAD1, /* down/left */
DIK_NUMPAD2, /* down */
DIK_NUMPAD5, /* duplicate down on 5 key for inverted T */
DIK_NUMPAD3, /* down/right */
};
/* keypad plus mode joymask */
static const UBYTE joymask_plus[] =
{
INPUT_STICK_CENTRE, /* not used */
INPUT_STICK_UL, /* up/left */
INPUT_STICK_FORWARD, /* up */
INPUT_STICK_UR, /* up/right */
INPUT_STICK_LEFT, /* left */
INPUT_STICK_RIGHT, /* right */
INPUT_STICK_LL, /* down/left */
INPUT_STICK_BACK, /* down */
INPUT_STICK_BACK, /* duplicate down on 5 key for inverted T */
INPUT_STICK_LR, /* down/right */
};
/* arrow mode joydefs */
static const UBYTE joydefs_arrow[] =
{
DIK_NUMPAD0,
DIK_UP,
DIK_LEFT,
DIK_RIGHT,
DIK_DOWN,
};
/* arrow mod joymask */
static const UBYTE joymask_arrow[] =
{
INPUT_STICK_CENTRE, /* not used */
INPUT_STICK_FORWARD, /* up */
INPUT_STICK_LEFT, /* left */
INPUT_STICK_RIGHT, /* right */
INPUT_STICK_BACK, /* down */
};
int getkeyvalue(char *name);
void getkeyname(int value, char *name);
void Win32_Init(void);
#endif /* _ATARI_WIN32_H_ */
+244
View File
@@ -0,0 +1,244 @@
/*
* joystick.c - Win32 port specific code
*
* Copyright (C) 2005 James Wilkinson
* Copyright (C) 2005-2010 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define DIRECTINPUT_VERSION 0x0500
#include "config.h"
#include <windows.h>
#include <dinput.h>
#include "atari.h"
#include "input.h"
#include "log.h"
#include "joystick.h"
#include "main.h"
HRESULT
SetDIDwordProperty(LPDIRECTINPUTDEVICE pdev, REFGUID guidProperty,
DWORD dwObject, DWORD dwHow, DWORD dwValue);
tjoystat joystat;
static LPDIRECTINPUTDEVICE2 dijoy[NUM_STICKS] = {NULL};
int joyreacquire(int num)
{
if (!dijoy[num])
return 1;
if (IDirectInputDevice_Acquire(dijoy[num]) >= 0)
return 0;
else
return 1;
}
int procjoy(int num)
{
DIJOYSTATE js;
HRESULT hRes;
int i;
if (!dijoy[num])
return 1;
IDirectInputDevice2_Poll(dijoy[num]);
hRes = IDirectInputDevice_GetDeviceState(dijoy[num], sizeof(DIJOYSTATE), &js);
if (hRes != DI_OK)
{
if (hRes == DIERR_INPUTLOST)
joyreacquire(num);
return 1;
}
/* process trigger */
joystat.trig = (js.rgbButtons[ 0 ] & 0x80) ? 1 : 0;
/* process programmable buttons */
for (i = 0; i < MAX_PROG_BUTTONS; i++) {
joystat.jsbutton[num][i][STATE] = (js.rgbButtons[ i + 1 ] & 0x80) ? 1 : 0;
}
/* process primary joystick. X and Y joystick axis*/
if (js.lX == 0)
{
if (js.lY == 0) joystat.stick = INPUT_STICK_CENTRE;
else if (js.lY < 0) joystat.stick = INPUT_STICK_FORWARD;
else joystat.stick = INPUT_STICK_BACK;
}
else if (js.lX < 0)
{
if (js.lY == 0) joystat.stick = INPUT_STICK_LEFT;
else if (js.lY < 0) joystat.stick = INPUT_STICK_UL;
else joystat.stick = INPUT_STICK_LL;
}
else
{
if (js.lY == 0) joystat.stick = INPUT_STICK_RIGHT;
else if (js.lY < 0) joystat.stick = INPUT_STICK_UR;
else joystat.stick = INPUT_STICK_LR;
}
/* process second joystick on the same gamepad (for dual stick
games like Robotron). Second stick must use Z-axis (throttle)
and Z-axis rotation (rudder) for it's X and Y motions. */
if (alternateJoystickMode == JOY_DUAL_MODE)
{
if (js.lZ == 0)
{
if (js.lRz == 0) joystat.stick_1 = INPUT_STICK_CENTRE;
else if (js.lRz < 0) joystat.stick_1 = INPUT_STICK_FORWARD;
else joystat.stick_1 = INPUT_STICK_BACK;
}
else if (js.lZ < 0)
{
if (js.lRz == 0) joystat.stick_1 = INPUT_STICK_LEFT;
else if (js.lRz < 0) joystat.stick_1 = INPUT_STICK_UL;
else joystat.stick_1 = INPUT_STICK_LL;
}
else
{
if (js.lRz == 0) joystat.stick_1 = INPUT_STICK_RIGHT;
else if (js.lRz < 0) joystat.stick_1 = INPUT_STICK_UR;
else joystat.stick_1 = INPUT_STICK_LR;
}
}
/* end dual stick processing */
return 0;
}
static BOOL CALLBACK joycallback(LPCDIDEVICEINSTANCE pdevinst, LPVOID pv)
{
DIPROPRANGE dipr;
HRESULT hRes;
LPDIRECTINPUTDEVICE pdev;
LPDIRECTINPUT lpdi = pv;
static int i = 0;
if (i > 1) return DIENUM_STOP;
if (IDirectInput_CreateDevice(lpdi, &pdevinst->guidInstance, &pdev, NULL) != DI_OK)
{
return DIENUM_STOP;
}
if (IDirectInputDevice_SetDataFormat(pdev, &c_dfDIJoystick) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
if (IDirectInputDevice_SetCooperativeLevel(pdev, hWndMain,
DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
dipr.diph.dwSize = sizeof(dipr);
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
dipr.diph.dwObj = DIJOFS_X;
dipr.diph.dwHow = DIPH_BYOFFSET;
dipr.lMin = -1000;
dipr.lMax = 1000;
if (IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &dipr.diph) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
dipr.diph.dwObj = DIJOFS_Y;
if (IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &dipr.diph) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_X, DIPH_BYOFFSET, 5000) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
if (SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Y, DIPH_BYOFFSET, 5000) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return DIENUM_STOP;
}
/* Initialize the Z and Z-Rotation axis for dual stick mode */
/* No reason to stop if these fail, even if GetCapabilities says they should not */
dipr.diph.dwObj = DIJOFS_Z;
IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &dipr.diph);
dipr.diph.dwObj = DIJOFS_RZ;
IDirectInputDevice_SetProperty(pdev, DIPROP_RANGE, &dipr.diph);
SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_Z, DIPH_BYOFFSET, 5000);
SetDIDwordProperty(pdev, DIPROP_DEADZONE, DIJOFS_RZ, DIPH_BYOFFSET, 5000);
/* End Z and Z-Rotation axis initialization */
hRes = IDirectInputDevice_QueryInterface(pdev, &IID_IDirectInputDevice2,
(LPVOID*) &dijoy[i]);
IDirectInputDevice_Release(pdev);
if (hRes < 0)
return DIENUM_STOP;
joyreacquire(i);
Log_print("joystick %d found!", i);
i ++;
return DIENUM_CONTINUE;
}
int initjoystick(void)
{
LPDIRECTINPUT pdi;
HRESULT hRes;
if (DirectInputCreate(myInstance, DIRECTINPUT_VERSION, &pdi, NULL) != DI_OK)
{
return 1;
}
hRes = IDirectInput_EnumDevices(pdi, DIDEVTYPE_JOYSTICK, joycallback, pdi, DIEDFL_ATTACHEDONLY);
IDirectInput_Release(pdi);
if(!dijoy[0]/*hRes != DI_OK*/)
{
return 1;
}
return 0;
}
void uninitjoystick(void)
{
int i;
for (i = 0; i < NUM_STICKS; i ++)
{
if (dijoy[i])
{
IDirectInputDevice_Unacquire(dijoy[i]);
IDirectInputDevice_Release(dijoy[i]);
dijoy[i] = NULL;
}
}
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef JOYSTICK_H_
#define JOYSTICK_H_
#define NUM_STICKS 2
#define MAX_PROG_BUTTONS 9
#define STATE 0
#define ASSIGN 1
#define STICK1 0
#define STICK2 1
/* keyboard joystick modes */
typedef enum KEYJOYMODE_ {
KEYPAD_MODE,
KEYPAD_PLUS_MODE,
ARROW_MODE
} KEYJOYMODE;
/* alternate joystick modes */
typedef enum ALTJOYMODE_ {
JOY_NORMAL_MODE,
JOY_DUAL_MODE,
JOY_SHARED_MODE
} ALTJOYMODE;
int procjoy(int num);
int joyreacquire(int num);
int initjoystick(void);
void uninitjoystick(void);
void clearjoy(void);
typedef struct
{
int trig;
/* holds stick id, button state, and button assignment */
int jsbutton[NUM_STICKS][MAX_PROG_BUTTONS][2];
int stick;
int stick_1;
} tjoystat;
extern tjoystat joystat;
extern KEYJOYMODE keyboardJoystickMode;
extern ALTJOYMODE alternateJoystickMode;
#endif /* JOYSTICK_H_ */
+181
View File
@@ -0,0 +1,181 @@
/*
* keyboard.c - Win32 port specific code
*
* Copyright (C) 2000 Krzysztof Nikiel
* Copyright (C) 2000-2005 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#define DIRECTINPUT_VERSION 0x0500
#include <windows.h>
#include <dinput.h>
#include "atari.h"
#include "main.h"
#include "keyboard.h"
#define KEYBUFSIZE 0x40
static LPDIRECTINPUTDEVICE2 dikb0 = NULL;
int pause_hit;
int kbcode;
UBYTE kbhits[KBCODES];
int kbreacquire(void)
{
if (!dikb0)
return 1;
if (IDirectInputDevice_Acquire(dikb0) >= 0)
return 0;
else
return 1;
}
int prockb(void)
{
DIDEVICEOBJECTDATA que[KEYBUFSIZE];
DWORD dwEvents;
DWORD i;
HRESULT hRes;
dwEvents = KEYBUFSIZE;
hRes = IDirectInputDevice_GetDeviceData(dikb0,
sizeof(DIDEVICEOBJECTDATA),
que, &dwEvents, 0);
if (hRes != DI_OK)
{
if ((hRes == DIERR_INPUTLOST))
kbreacquire();
return 1;
}
for (i = 0; i < dwEvents; i++)
{
#if 0
printf("%02x(%02x)\n", que[i].dwOfs, que[i].dwData);
#endif
if (que[i].dwOfs >= KBCODES)
continue;
if (que[i].dwOfs == DIK_PAUSE)
{
if (que[i].dwData)
pause_hit = 1;
continue;
}
if (que[i].dwData)
kbhits[kbcode = que[i].dwOfs] = 1;
else
{
kbhits[kbcode = que[i].dwOfs] = 0;
kbcode |= 0x100;
}
}
return 0;
}
void uninitinput(void)
{
if (dikb0)
{
IDirectInputDevice_Unacquire(dikb0);
IDirectInputDevice_Release(dikb0);
dikb0 = NULL;
}
}
HRESULT
SetDIDwordProperty(LPDIRECTINPUTDEVICE pdev, REFGUID guidProperty,
DWORD dwObject, DWORD dwHow, DWORD dwValue)
{
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(dipdw);
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
dipdw.diph.dwObj = dwObject;
dipdw.diph.dwHow = dwHow;
dipdw.dwData = dwValue;
return pdev->lpVtbl->SetProperty(pdev, guidProperty, &dipdw.diph);
}
static int initkb(LPDIRECTINPUT pdi)
{
LPDIRECTINPUTDEVICE pdev;
HRESULT hRes;
if (IDirectInput_CreateDevice(pdi,
&GUID_SysKeyboard, &pdev, NULL) != DI_OK)
{
return 1;
}
if (IDirectInputDevice_SetDataFormat(pdev, &c_dfDIKeyboard) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return 1;
}
if (IDirectInputDevice_SetCooperativeLevel(pdev, hWndMain,
DISCL_NONEXCLUSIVE |
DISCL_FOREGROUND) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return 1;
}
if (SetDIDwordProperty(pdev, DIPROP_BUFFERSIZE, 0, DIPH_DEVICE,
KEYBUFSIZE) != DI_OK)
{
IDirectInputDevice_Release(pdev);
return 1;
}
hRes = pdev->lpVtbl->QueryInterface(pdev, &IID_IDirectInputDevice2,
(LPVOID *) (void*) & dikb0);
if (hRes < 0)
return 1;
IDirectInputDevice_Release(pdev);
kbreacquire();
return 0;
}
int initinput(void)
{
int i;
LPDIRECTINPUT pdi;
if (DirectInputCreate(myInstance, DIRECTINPUT_VERSION, &pdi, NULL) != DI_OK)
{
return 1;
}
i = initkb(pdi);
IDirectInput_Release(pdi);
if (i)
return i;
return 0;
}
void clearkb(void)
{
int i;
for (i = 0; i < KBCODES; i++)
kbhits[i] = 0;
pause_hit = 0;
kbcode = 0;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef KEYBOARD_H_
#define KEYBOARD_H_
#define SHOWKBCODES 0
#define KBCODES 0x100
#include <dinput.h>
extern int pause_hit;
extern int kbcode;
extern UBYTE kbhits[KBCODES];
int prockb(void);
int kbreacquire(void);
int initinput(void);
void uninitinput(void);
void clearkb(void);
HRESULT
SetDIDwordProperty(LPDIRECTINPUTDEVICE pdev, REFGUID guidProperty,
DWORD dwObject, DWORD dwHow, DWORD dwValue);
#endif /* KEYBOARD_H_ */
+536
View File
@@ -0,0 +1,536 @@
/*
* main.cpp - Win32 port specific code
*
* Copyright (C) 2000 Krzysztof Nikiel
* Copyright (C) 2000-2014 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define MOUSE_CENTER_X 100
#define MOUSE_CENTER_Y 100
#define WM_MOUSEHWHEEL 0x020E
#include "config.h"
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <process.h>
extern "C" {
#include "atari.h"
#include "input.h"
#include "platform.h"
#include "screen.h"
#include "sound.h"
#include "ui.h"
#include "ui_basic.h"
#include "log.h"
#include "config.h"
#include "main_menu.h"
#include "main.h"
#include "screen_win32.h"
#include "atari_win32.h"
#include "keyboard.h"
#include "joystick.h"
}
char *myname = "Atari800";
HWND hWndMain = NULL;
HINSTANCE myInstance = NULL;
FILE *stdout_stream;
// menus
HMENU hMainMenu = NULL;
HMENU hFileMenu = NULL;
HMENU hManageMenu = NULL;
HMENU hSystemMenu = NULL;
HMENU hDisplayMenu = NULL;
HMENU hHelpMenu = NULL;
static int bActive = 0; /* activity indicator */
static bool quit_ok = TRUE;
static keycommand_t keycommand = {AKEY_NONE, -1};
bool help_only = FALSE;
BOOL useconsole = FALSE;
#if 1
void exit(int code)
{
if (useconsole)
{
FreeConsole();
}
else
{
fclose(stdout_stream);
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ExitProcess(code);
}
#endif
// Used where necessary to keep UI
// responsive to system events
void DoEvents()
{
MSG msg;
msg.message = WM_NULL;
PLATFORM_DisplayScreen();
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage(10);
Atari800_Exit(FALSE);
exit(0);
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
// Used by PLATFORM_Keyboard to retrieve a menu command
void GetCommandKey(keycommand_t *kc)
{
if (keycommand.keystroke != AKEY_NONE) {
kc->keystroke = keycommand.keystroke;
kc->function = keycommand.function;
keycommand.keystroke = AKEY_NONE;
keycommand.function = -1;
}
else {
kc->keystroke = AKEY_NONE;
kc->function = -1;
}
}
void SuppressNextQuitMessage()
{
quit_ok = FALSE;
}
void OnSize(HWND hWnd, UINT state, int cx, int cy)
{
refreshframe(); // handled in screen_win32.c
}
void OnActivateApp(HWND hWnd, BOOL fActivate, DWORD dwThreadId)
{
bActive = fActivate;
if (bActive) {
kbreacquire();
#ifdef SOUND
Sound_Continue();
#endif
}
}
HWND OnSysChar(HWND hWnd, TCHAR ch, int cRepeat)
{
/* empty function suppresses beep on alt-key shortcuts */
return(0);
}
void OnClose(HWND hWnd)
{
Atari800_Exit(FALSE);
}
void OnDestroy(HWND hWnd)
{
if (quit_ok)
PostQuitMessage(10);
quit_ok = TRUE;
}
void OnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify)
{
switch (id) {
// File Menu
case ID_RUN_ATARI_PROGRAM:
if (UI_current_function != UI_MENU_RUN) {
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_RUN;
}
break;
case ID_RESET:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_RESETW;
break;
case ID_REBOOT:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_RESETC;
break;
case ID_CONFIGURATION:
keycommand.keystroke = AKEY_UI;
break;
case ID_SAVE_CONFIG:
if (UI_is_active) {
keycommand.keystroke = AKEY32_MENU_SAVE_CONFIG;
}
else {
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_SAVE_CONFIG;
}
break;
case ID_BACK:
keycommand.keystroke = AKEY_ESCAPE;
keycommand.function = -1;
break;
case ID_EXIT:
keycommand.keystroke = AKEY_EXIT;
keycommand.function = -1;
break;
// Manage Menu
case ID_DISK_MANAGEMENT:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_DISK;
break;
case ID_CART_MANAGEMENT:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_CARTRIDGE;
break;
case ID_TAPE_MANAGEMENT:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_CASSETTE;
break;
case ID_EMULATOR_BIOS:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_SETTINGS;
break;
// System Menu
case ID_NTSC:
//CheckMenuItem(hSystemMenu, ID_NTSC, MF_CHECKED);
//CheckMenuItem(hSystemMenu, ID_PAL, MF_UNCHECKED);
Atari800_SetTVMode(Atari800_TV_NTSC);
Atari800_InitialiseMachine();
break;
case ID_PAL:
//CheckMenuItem(hSystemMenu, ID_PAL, MF_CHECKED);
//CheckMenuItem(hSystemMenu, ID_NTSC, MF_UNCHECKED);
Atari800_SetTVMode(Atari800_TV_PAL);
Atari800_InitialiseMachine();
break;
case ID_SELECT_MACHINE:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_SYSTEM;
break;
#ifdef SOUND
case ID_SOUND:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_SOUND;
break;
#endif
case ID_CONTROLLERS:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_CONTROLLER;
break;
// Display Menu
case ID_FULLSCREEN:
togglewindowstate();
break;
case ID_WINDOW_SIZE_UP:
changewindowsize(STEPUP, 50);
break;
case ID_WINDOW_SIZE_DOWN:
changewindowsize(STEPDOWN, 50);
break;
case ID_ATARI_DISPLAY:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_DISPLAY;
break;
case ID_WINDOWS_DISPLAY:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_WINDOWS;
break;
// Help Menu
case ID_ABOUT_ATARI800:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_ABOUT;
break;
case ID_FUNCTION_KEY_HELP:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_FUNCT_KEY_HELP;
break;
case ID_HOT_KEY_HELP:
keycommand.keystroke = AKEY_UI;
keycommand.function = UI_MENU_HOT_KEY_HELP;
break;
}
}
// set the PAL/NTSC mode - called in atari.c
void SetTVModeMenuItem(int mode)
{
if (mode == Atari800_TV_NTSC) {
CheckMenuItem(hSystemMenu, ID_NTSC, MF_CHECKED);
CheckMenuItem(hSystemMenu, ID_PAL, MF_UNCHECKED);
}
else {
CheckMenuItem(hSystemMenu, ID_PAL, MF_CHECKED);
CheckMenuItem(hSystemMenu, ID_NTSC, MF_UNCHECKED);
}
}
extern "C" LRESULT CALLBACK Atari_WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int nx, ny;
switch (message) {
HANDLE_MSG(hWnd, WM_SIZE, OnSize);
HANDLE_MSG(hWnd, WM_ACTIVATEAPP, OnActivateApp);
HANDLE_MSG(hWnd, WM_SYSCHAR, OnSysChar);
HANDLE_MSG(hWnd, WM_CLOSE, OnClose);
HANDLE_MSG(hWnd, WM_DESTROY, OnDestroy);
HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
INPUT_mouse_buttons = ((wParam & MK_LBUTTON) ? 1 : 0)
| ((wParam & MK_RBUTTON) ? 2 : 0)
| ((wParam & MK_MBUTTON) ? 4 : 0);
// handle mouse clicks in the config UI
if (UI_is_active) {
switch (INPUT_mouse_buttons) {
case 1:
getnativecoords(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), &nx, &ny);
SetMouseIndex(nx, ny);
keycommand.keystroke = AKEY32_UI_MOUSE_CLICK;
break;
case 2:
keycommand.keystroke = AKEY_ESCAPE;
keycommand.function = -1;
break;
case 4:
keycommand.keystroke = AKEY_RETURN;
keycommand.function = -1;
break;
}
}
break;
case WM_LBUTTONDBLCLK:
if (UI_is_active && UI_mouse_click.y != -1) {
keycommand.keystroke = AKEY_RETURN;
keycommand.function = -1;
}
break;
case WM_MOUSEWHEEL:
if (UI_is_active) {
if (GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA > 0)
keycommand.keystroke = AKEY_UP;
else if (GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA < 0)
keycommand.keystroke = AKEY_DOWN;
}
break;
case WM_MOUSEHWHEEL:
if (UI_is_active) {
if (GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA > 0)
keycommand.keystroke = AKEY_RIGHT;
else if (GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA < 0)
keycommand.keystroke = AKEY_LEFT;
}
break;
case WM_SETCURSOR:
if (GetRenderMode() == DIRECTDRAW) {
SetCursor(NULL);
return TRUE;
}
break;
case WM_ENTERMENULOOP:
Sound_Pause();
break;
case WM_EXITMENULOOP:
if (!UI_is_active)
Sound_Continue();
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE hprevinstance,
LPSTR lpcmdline,
int nshowcmd)
{
//***********************************************
// Convert WinMain() style command line arguments
// to main() style arguments (argc, *argv[])
// This maintains compatibility with the former
// main() entry point's parameters.
//***********************************************
char **argv = NULL;
int argc = 1;
char *app_path = new char[MAX_PATH];
strcpy(app_path, GetCommandLine());
if (app_path[0] == '\"')
{
app_path = (app_path+1);
char *lastdit = strchr(app_path, '\"');
*lastdit = '\x0';
}
if ( *lpcmdline != '\x0' )
{
char *cmdlinecopy = new char[strlen(lpcmdline)+1];
strcpy(cmdlinecopy, lpcmdline);
char *c = cmdlinecopy;
while(c)
{
++argc;
c = strchr((c+1),' ');
}
argv = new char*[argc];
argv[0] = app_path;
if(argc > 1)
{
argv[1] = cmdlinecopy;
char *c = strchr(cmdlinecopy, ' ');
int n = 2;
while(c)
{
*c = '\x0';
argv [n] = (c+1);
++n;
c = strchr((c+1), ' ');
}
}
}
else
{
argv = new char *[1];
argv[0] = app_path;
}
//*********************************************
// Process commandline and activate console
// if -console switch is set.
//*********************************************
int i,j;
for (i = j = 1; i < argc; i++) {
if (strcmp(argv[i], "-console") == 0) {
useconsole = TRUE;
}
else if (strcmp(argv[i], "-help") == 0) {
help_only = TRUE;
}
}
if (useconsole || help_only) {
AllocConsole(); // start a console window
freopen("CONIN$","rb",stdin); // reopen stdin handle as console window input
freopen("CONOUT$","wb",stdout); // reopen stout handle as console window output
freopen("CONOUT$","wb",stderr); // reopen stderr handle as console window output
}
else // not using console
{
// console is supressed, so stream console output to a file
stdout_stream = freopen("atari800.txt", "w", stdout);
if (stdout_stream == NULL)
fprintf(stdout, "Error opening atari800.txt\n");
}
//*********************************************
// Begin main processing
//*********************************************
MSG msg;
POINT mouse;
Win32_Init();
myInstance = GetModuleHandle(NULL);
if (help_only) {
/* initialize the Atari800 for help only */
Atari800_Initialise(&argc, argv);
Log_print("\t-console Show the Atari800 console window");
Log_print("\n");
system("PAUSE");
return 0;
}
/* initialise Atari800 core for use */
if (!Atari800_Initialise(&argc, argv))
return 3;
msg.message = WM_NULL;
/* main loop */
for (;;) {
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
break;
if (!bActive)
continue;
INPUT_key_code = PLATFORM_Keyboard();
// support mouse device modes
// only supported in fullscreen modes for now
if (GetScreenMode() == FULLSCREEN)
{
GetCursorPos(&mouse);
INPUT_mouse_delta_x = mouse.x - MOUSE_CENTER_X;
INPUT_mouse_delta_y = mouse.y - MOUSE_CENTER_Y;
if (INPUT_mouse_delta_x | INPUT_mouse_delta_y)
SetCursorPos(MOUSE_CENTER_X, MOUSE_CENTER_Y);
}
Atari800_Frame();
if (Atari800_display_screen)
PLATFORM_DisplayScreen();
}
return msg.wParam;
}
+30
View File
@@ -0,0 +1,30 @@
#ifndef MAIN_H_
#define MAIN_H_
extern char *myname;
extern HWND hWndMain;
extern HINSTANCE myInstance;
extern BOOL useconsole;
extern int internalkey;
extern HMENU hMainMenu;
extern HMENU hFileMenu;
extern HMENU hManageMenu;
extern HMENU hSystemMenu;
extern HMENU hDisplayMenu;
extern HMENU hHelpMenu;
LRESULT CALLBACK Atari_WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void SuppressNextQuitMessage(void);
void DoEvents(void);
void SetTVModeMenuItem(int mode);
typedef struct {
int keystroke;
int function;
} keycommand_t;
void GetCommandKey(keycommand_t *keycommand);
#endif /* MAIN_H_ */
+34
View File
@@ -0,0 +1,34 @@
#ifndef _MAIN_MENU_H_
#define _MAIN_MENU_H_
#define ID_FILE 101
#define ID_RUN_ATARI_PROGRAM 102
#define ID_RESET 103
#define ID_REBOOT 104
#define ID_CONFIGURATION 105
#define ID_SAVE_CONFIG 106
#define ID_BACK 107
#define ID_EXIT 108
#define ID_MANAGE 201
#define ID_DISK_MANAGEMENT 202
#define ID_CART_MANAGEMENT 203
#define ID_TAPE_MANAGEMENT 204
#define ID_EMULATOR_BIOS 205
#define ID_SYSTEM 301
#define ID_NTSC 302
#define ID_PAL 303
#define ID_SELECT_MACHINE 304
#define ID_SOUND 305
#define ID_CONTROLLERS 306
#define ID_DISPLAY 401
#define ID_FULLSCREEN 402
#define ID_WINDOW_SIZE_UP 403
#define ID_WINDOW_SIZE_DOWN 404
#define ID_ATARI_DISPLAY 405
#define ID_WINDOWS_DISPLAY 406
#define ID_HELP 901
#define ID_ABOUT_ATARI800 902
#define ID_FUNCTION_KEY_HELP 903
#define ID_HOT_KEY_HELP 904
#endif /* _MENU_H_ */
+93
View File
@@ -0,0 +1,93 @@
# Makefile for Microsoft NMAKE + CL
# Invoke with:
# nmake /f win32\msc\Makefile
# from the "src" directory.
# Compile using DirectX 9.0 SDK (Summer 2004)
CC = cl
RC = rc
DEFS =
LIBS = \
libpng.lib zlib.lib \
ddraw.lib dinput.lib dsound.lib dxguid.lib gdi32.lib gdiplus.lib d3d9.lib d3dx9.lib \
user32.lib winmm.lib advapi32.lib
TARGET = atari800.exe
CFLAGS = /nologo /O2 /GS- /W3 /wd4996 /I win32\msc /I .
CPPFLAGS = /nologo /O2 /GS- /W3 /wd4996 /I win32\msc /I ./
LDFLAGS = /nologo
OBJS = \
afile.obj \
antic.obj \
artifact.obj \
atari.obj \
binload.obj \
cartridge.obj \
cassette.obj \
cfg.obj \
colours.obj \
colours_external.obj \
colours_ntsc.obj \
colours_pal.obj \
compfile.obj \
cpu.obj \
crc32.obj \
cycle_map.obj \
devices.obj \
emuos.obj \
esc.obj \
gtia.obj \
img_tape.obj \
input.obj \
log.obj \
memory.obj \
monitor.obj \
mzpokeysnd.obj \
pbi.obj \
pbi_xld.obj \
pia.obj \
pokey.obj \
pokeysnd.obj \
remez.obj \
rtime.obj \
screen.obj \
sio.obj \
sndsave.obj \
statesav.obj \
sysrom.obj \
ui.obj \
ui_basic.obj \
util.obj \
votrax.obj \
votraxsnd.obj \
win32\atari_win32.obj \
win32\joystick.obj \
win32\keyboard.obj \
win32\main.obj \
win32\screen_win32.obj \
win32\render_gdi.obj \
win32\render_gdiplus.obj \
win32\render_directdraw.obj \
win32\render_direct3d.obj \
win32\sound.obj \
win32\atari.res
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) /Fe$(TARGET) $(LDFLAGS) $(OBJS) $(LIBS)
# the default .c.obj rule would place the object files in the src directory
{win32\}.c{win32\}.obj:
$(CC) $(CFLAGS) /c /Fo$@ $**
{win32\}.cpp{win32\}.obj:
$(CC) $(CPPFLAGS) /c /Fo$@ $**
clean:
del *.obj
del win32\*.obj
del win32\atari.res
del $(TARGET)
+551
View File
@@ -0,0 +1,551 @@
/* config.h for DirectX version of Atari800 compiled with MSVC 6. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */
/* The Austin Franklin 80 column card. */
/* #undef AF80 */
/* Target: Android */
/* #undef ANDROID */
/* Target: standard I/O. */
/* #undef BASIC */
/* Define to use buffered debug output. */
/* #undef BUFFERED_LOG */
/* Define to allow sound clipping. */
/* #undef CLIP_SOUND */
/* Define to 1 if the `closedir' function returns void instead of `int'. */
/* #undef CLOSEDIR_VOID */
/* Define to allow console sound (keyboard clicks). */
#define CONSOLE_SOUND 1
/* Define to activate crash menu after CIM instruction. */
#define CRASH_MENU 1
/* Define to disable bitmap graphics emulation in CURSES target. */
/* #undef CURSES_BASIC */
/* Alternate config filename due to 8+3 fs limit. */
#define DEFAULT_CFG_NAME "atari800.cfg"
/* Target: Windows with DirectX. */
#define DIRECTX 1
/* Define to use dirty screen partial repaints. */
/* #undef DIRTYRECT */
/* Define to use back slash as directory separator. */
#define DIR_SEP_BACKSLASH 1
/* Target: DOS VGA. */
/* #undef DOSVGA */
/* Define to enable DOS style drives support. */
#define DOS_DRIVES 1
/* Define to enable event recording. */
/* #undef EVENT_RECORDING */
/* Target: Atari Falcon system. */
/* #undef FALCON */
/* Define to use m68k assembler CPU core for Falcon target. */
/* #undef FALCON_CPUASM */
/* Define to 1 if you have the <arpa/inet.h> header file. */
/* #undef HAVE_ARPA_INET_H */
/* Define to 1 if you have the `atexit' function. */
#define HAVE_ATEXIT 1
/* Define to 1 if you have the `chmod' function. */
/* #undef HAVE_CHMOD */ /* it is in <io.h> */
/* Define to 1 if you have the `clock' function. */
#define HAVE_CLOCK 1
/* Define to 1 if you have the <direct.h> header file. */
#define HAVE_DIRECT_H 1
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_DIRENT_H */
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
/* #undef HAVE_DOPRNT */
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fdopen' function. */
#define HAVE_FDOPEN 1
/* Define to 1 if you have the `fflush' function. */
#define HAVE_FFLUSH 1
/* Define to 1 if you have the <file.h> header file. */
/* #undef HAVE_FILE_H */
/* Define to 1 if you have the `floor' function. */
#define HAVE_FLOOR 1
/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
/* #undef HAVE_FSEEKO */
/* Define to 1 if you have the `fstat' function. */
#define HAVE_FSTAT 1
/* Define to 1 if you have the `getcwd' function. */
#define HAVE_GETCWD 1
/* Define to 1 if you have the `gethostbyaddr' function. */
/* #undef HAVE_GETHOSTBYADDR */
/* Define to 1 if you have the `gethostbyname' function. */
/* #undef HAVE_GETHOSTBYNAME */
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `inet_ntoa' function. */
/* #undef HAVE_INET_NTOA */
/* Define to 1 if you have the <inttypes.h> header file. */
/* #undef HAVE_INTTYPES_H */
/* Define to 1 if you have the `gem' library (-lgem). */
/* #undef HAVE_LIBGEM */
/* Define to 1 if you have the `png' library (-lpng). */
#define HAVE_LIBPNG 1
/* Define to 1 if you have the `z' library (-lz). */
#define HAVE_LIBZ 1
/* Define to 1 if you have the `localtime' function. */
#define HAVE_LOCALTIME 1
/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if you have the `mkdir' function. */
#define HAVE_MKDIR 1
/* Define to 1 if you have the `mkstemp' function. */
/* #undef HAVE_MKSTEMP */
/* Define to 1 if you have the `mktemp' function. */
#define HAVE_MKTEMP 1
/* Define to 1 if you have the `modf' function. */
#define HAVE_MODF 1
/* Define to 1 if you have the `nanosleep' function. */
/* #undef HAVE_NANOSLEEP */
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
/* #undef HAVE_NDIR_H */
/* Define to 1 if you have the <netdb.h> header file. */
/* #undef HAVE_NETDB_H */
/* Define to 1 if you have the <netinet/in.h> header file. */
/* #undef HAVE_NETINET_IN_H */
/* Define to 1 if you have the `opendir' function. */
/* #undef HAVE_OPENDIR */
/* Support for OpenGL graphics acceleration. */
/* #undef HAVE_OPENGL */
/* Define to 1 if you have the <readline/readline.h> header file. */
/* #undef HAVE_READLINE_READLINE_H */
/* Define to 1 if you have the `rename' function. */
#define HAVE_RENAME 1
/* Define to 1 if you have the `rewind' function. */
#define HAVE_REWIND 1
/* Define to 1 if you have the `rmdir' function. */
#define HAVE_RMDIR 1
/* Define to 1 if you have the `select' function. */
/* #undef HAVE_SELECT */
/* Define to 1 if you have the `signal' function. */
#define HAVE_SIGNAL 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the `snprintf' function. */
/* #undef HAVE_SNPRINTF */
/* Define to 1 if you have the `socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if you have the `stat' function. */
#define HAVE_STAT 1
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if you have the <stdint.h> header file. */
/* #undef HAVE_STDINT_H */
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strcasecmp' function. */
/* #undef HAVE_STRCASECMP */
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
/* #undef HAVE_STRINGS_H */
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strncpy' function. */
/* #undef HAVE_STRNCPY */
/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1
/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1
/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1
/* Define to 1 if you have the `system' function. */
#define HAVE_SYSTEM 1
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_DIR_H */
/* Define to 1 if you have the <sys/ioctl.h> header file. */
/* #undef HAVE_SYS_IOCTL_H */
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_NDIR_H */
/* Define to 1 if you have the <sys/select.h> header file. */
/* #undef HAVE_SYS_SELECT_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define to 1 if you have the <sys/soundcard.h> header file. */
/* #undef HAVE_SYS_SOUNDCARD_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
/* #undef HAVE_SYS_TIME_H */
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <termios.h> header file. */
/* #undef HAVE_TERMIOS_H */
/* Define to 1 if you have the `time' function. */
#define HAVE_TIME 1
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define to 1 if you have the `tmpfile' function. */
#define HAVE_TMPFILE 1
/* Define to 1 if you have the `tmpnam' function. */
#define HAVE_TMPNAM 1
/* Define to 1 if you have the `uclock' function. */
/* #undef HAVE_UCLOCK */
/* Define to 1 if you have the <unistd.h> header file. */
/* #undef HAVE_UNISTD_H */
/* Define to 1 if you have the <unixio.h> header file. */
/* #undef HAVE_UNIXIO_H */
/* Define to 1 if you have the `unlink' function. */
#define HAVE_UNLINK 1
/* Define to 1 if you have the `usleep' function. */
/* #undef HAVE_USLEEP */
/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1
/* Define to 1 if you have the `vsnprintf' function. */
/* #undef HAVE_VSNPRINTF */
/* Define to 1 if you have the <windows.h> header file. */
#define HAVE_WINDOWS_H 1
/* Define to 1 if you have the <winsock2.h> header file. */
#define HAVE_WINSOCK2_H 1
/* Define to 1 if you have the `_mkdir' function. */
/* #undef HAVE__MKDIR */
/* Define to add IDE harddisk emulation. */
/* #undef IDE */
/* Define to allow sound interpolation. */
#define INTERPOLATE_SOUND 1
/* Target: Java NestedVM. */
/* #undef JAVANVM */
/* Define to use LINUX joystick. */
/* #undef LINUX_JOYSTICK */
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
/* Define if mkdir takes only one argument. */
#define MKDIR_TAKES_ONE_ARG 1
/* Define to activate assembler in monitor. */
#define MONITOR_ASSEMBLER 1
/* Define to activate code breakpoints and execution history. */
#define MONITOR_BREAK 1
/* Define to activate user-defined breakpoints. */
/* #undef MONITOR_BREAKPOINTS */
/* Define to activate hints in disassembler. */
#define MONITOR_HINTS 1
/* Define to activate 6502 opcode profiling. */
/* #undef MONITOR_PROFILE */
/* Define to activate readline support in monitor. */
/* #undef MONITOR_READLINE */
/* Define to activate TRACE command in monitor. */
/* #undef MONITOR_TRACE */
/* Target: X11 with Motif. */
/* #undef MOTIF */
/* Define to allow color changes inside a scanline. */
#define NEW_CYCLE_EXACT 1
/* Define to use nonlinear POKEY mixing. */
/* #undef NONLINEAR_MIXING */
/* Use NTSC video filter. */
/* #undef NTSC_FILTER */
/* Define to the address where bug reports for this package should be sent. */
/* #undef PACKAGE_BUGREPORT */
/* Define to the full name of this package. */
/* #undef PACKAGE_NAME */
/* Define to the full name and version of this package. */
/* #undef PACKAGE_STRING */
/* Define to the one symbol short name of this package. */
/* #undef PACKAGE_TARNAME */
/* Define to the home page for this package. */
/* #undef PACKAGE_URL */
/* Define to the version of this package. */
/* #undef PACKAGE_VERSION */
/* Define to use page-based attribute array. */
/* #undef PAGED_ATTRIB */
/* Define to emulate the Black Box. */
/* #undef PBI_BB */
/* Define to emulate the MIO board. */
/* #undef PBI_MIO */
/* A prototype 80 column card for the 1090 expansion box. */
/* #undef PBI_PROTO80 */
/* Define to emulate the 1400XL/1450XLD. */
/* #undef PBI_XLD */
/* Target: Sony PlayStation 2. */
/* #undef PS2 */
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to use R: device. */
/* #undef R_IO_DEVICE */
/* Define to use IP network connection with the R: device. */
/* #undef R_NETWORK */
/* Define to use the host serial port with the R: device. */
/* #undef R_SERIAL */
/* Target: SDL library. */
/* #undef SDL */
/* Define to the type of arg 1 for `select'. */
/* #undef SELECT_TYPE_ARG1 */
/* Define to the type of args 2, 3 and 4 for `select'. */
/* #undef SELECT_TYPE_ARG234 */
/* Define to the type of arg 5 for `select'. */
/* #undef SELECT_TYPE_ARG5 */
/* Define to allow serial in/out sound. */
/* #undef SERIO_SOUND */
/* Target: X11 with shared memory extensions. */
/* #undef SHM */
/* Define to activate sound support. */
#define SOUND 1
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to allow stereo sound. */
/* #undef STEREO_SOUND */ /* TODO */
/* Can change video modes on the fly. */
/* #undef SUPPORTS_CHANGE_VIDEOMODE */
/* Save additional config file options. */
#define SUPPORTS_PLATFORM_CONFIGSAVE
/* Additional config file options. */
#define SUPPORTS_PLATFORM_CONFIGURE
/* Update the Palette if it changed. */
#define SUPPORTS_PLATFORM_PALETTEUPDATE 1
/* Platform-specific sleep function. */
/* #undef SUPPORTS_PLATFORM_SLEEP */
/* Can display the screen rotated sideways. */
/* #undef SUPPORTS_ROTATE_VIDEOMODE */
/* Reinitialise the sound system. */
/* #undef SUPPORTS_SOUND_REINIT */
/* Define to use synchronized sound. */
/* #undef SYNCHRONIZED_SOUND */
/* Alternate system-wide config file for non-Unix OS. */
#define SYSTEM_WIDE_CFG_FILE "c:\\atari800.cfg"
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
/* #undef TIME_WITH_SYS_TIME */
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
/* #undef TM_IN_SYS_TIME */
/* Target: Curses-compatible library. */
/* #undef USE_CURSES */
/* Define for using cursor/ctrl keys for keyboard joystick. */
/* #undef USE_CURSORBLOCK */
/* Target: Ncurses library. */
/* #undef USE_NCURSES */
/* Define to use very slow computer support (faster -refresh). */
/* #undef VERY_SLOW */
/* Define to emulate the Alien Group Voice Box. */
/* #undef VOICEBOX */
/* Define to allow volume only sound. */
#define VOL_ONLY_SOUND 1
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
# define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
/* # undef WORDS_BIGENDIAN */
# endif
#endif
/* Define if unaligned word access is ok. */
#define WORDS_UNALIGNED_OK 1
/* Target: Standard X11. */
/* #undef X11 */
/* Emulate the XEP80. */
/* #undef XEP80_EMULATION */
/* Target: X11 with XView. */
/* #undef XVIEW */
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
/* #undef _LARGEFILE_SOURCE */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#define inline __inline
/* Define to `unsigned' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
/* #undef volatile */
/***************************************************************************/
/* use our exit() instead of libc's */
#define exit main_exit
+404
View File
@@ -0,0 +1,404 @@
#include "config.h"
#include "screen.h"
#include "render_direct3d.h"
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
extern "C" HWND hWndMain;
extern "C" {
#include "colours.h"
#include "log.h"
}
typedef D3DXMATRIX* (WINAPI* D3DXMatrixLookAtLHFunc)(D3DXMATRIX*, CONST D3DXVECTOR3*, CONST D3DXVECTOR3*, CONST D3DXVECTOR3*);
typedef D3DXMATRIX* (WINAPI* D3DXMatrixPerspectiveFovLHFunc)(D3DXMATRIX*, FLOAT, FLOAT, FLOAT, FLOAT);
typedef D3DXMATRIX* (WINAPI* D3DXMatrixRotationYFunc)(D3DXMATRIX*, FLOAT);
// D3D declarations
static LPDIRECT3D9 d3d;
static LPDIRECT3DDEVICE9 d3d_device;
static LPDIRECT3DVERTEXBUFFER9 vertex_buffer = NULL;
static LPDIRECT3DTEXTURE9 texture_buffer = NULL;
static D3DPRESENT_PARAMETERS d3dpp;
struct CUSTOMVERTEX {FLOAT X, Y, Z; DWORD COLOR; FLOAT U, V;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
static float const pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862f;
static float texturehorizclip = 0.0f;
static float texturevertclip = 0.0f;
static HMODULE hD3DX = NULL;
static D3DXMatrixLookAtLHFunc D3DXMatrixLookAtLHPtr = NULL;
static D3DXMatrixPerspectiveFovLHFunc D3DXMatrixPerspectiveFovLHPtr = NULL;
static D3DXMatrixRotationYFunc D3DXMatrixRotationYPtr = NULL;
extern "C" void startupdirect3d(int screenwidth, int screenheight, BOOL windowed, FRAMEPARAMS *fp)
{
// look for the newest, oldest, then generic versions
if ((hD3DX = LoadLibrary("d3dx9_42.dll")) != NULL || (hD3DX = LoadLibrary("d3dx9_24.dll")) != NULL || (hD3DX = LoadLibrary("d3dx9.dll")) != NULL)
{
D3DXMatrixLookAtLHPtr = (D3DXMatrixLookAtLHFunc) GetProcAddress(hD3DX, "D3DXMatrixLookAtLH");
D3DXMatrixPerspectiveFovLHPtr = (D3DXMatrixPerspectiveFovLHFunc) GetProcAddress(hD3DX, "D3DXMatrixPerspectiveFovLH");
D3DXMatrixRotationYPtr = (D3DXMatrixRotationYFunc) GetProcAddress(hD3DX, "D3DXMatrixRotationY");
// unlikely failure to load function pointers
if (D3DXMatrixLookAtLHPtr == NULL || D3DXMatrixPerspectiveFovLHPtr == NULL || D3DXMatrixRotationYPtr == NULL)
{
FreeLibrary(hD3DX);
hD3DX = NULL;
Log_print("Extended Direct3D functions disabled - load failure");
}
}
else
{
Log_print("Extended Direct3D functions disabled - updated DirectX runtime needed");
}
d3d = Direct3DCreate9(D3D_SDK_VERSION);
initpresentparams(screenwidth, screenheight, windowed);
// create the D3D device
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWndMain,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3d_device);
initdevice(fp);
return;
}
// Function used when we need to change present params
void resetdevice(int screenwidth, int screenheight, BOOL windowed, FRAMEPARAMS *fp)
{
texture_buffer->Release(); // close and release the texture
initpresentparams(screenwidth, screenheight, windowed);
d3d_device->Reset(&d3dpp);
initdevice(fp);
return;
}
void initpresentparams(int screenwidth, int screenheight, BOOL windowed)
{
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = windowed;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWndMain;
d3dpp.BackBufferWidth = screenwidth;
d3dpp.BackBufferHeight = screenheight;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// Only need this in fullscreen mode.
if (!windowed) {
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
}
return;
}
void initdevice(FRAMEPARAMS *fp)
{
UINT texturesize;
D3DTEXTUREFILTERTYPE filtertype;
// compute a horizontal & vertical offset
// with compensation for possible cropping & stretching
int clip_width = fp->view.right - fp->view.left;
int clip_height = fp->view.bottom - fp->view.top;
// set the type of interpolation filtering selected by the user
// only bilinear or none are available.
if (fp->filter == BILINEAR)
filtertype = D3DTEXF_LINEAR;
else
filtertype = D3DTEXF_POINT;
d3d_device->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3d_device->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
d3d_device->SetSamplerState( 0, D3DSAMP_MAGFILTER, filtertype);
d3d_device->SetFVF(CUSTOMFVF);
// In Direct3D we paint the Atari screen onto a texture that overlays a vertex buffer polygon.
// Although most newer graphics cards support rectangular textures of variable size,
// for compatibility and performance reasons, it is better that the texture be square with
// sides that are a power of two. Since the size of the bitmap changes depending
// on the scanline mode, we set that here. We also set the clipping parameters here
// that we'll use in the vertex buffer init to only map the drawn portion of the
// texture to the vertex buffer.
switch (fp->scanlinemode)
{
case NONE: // we are just mapping the standard 320x240 Atari screen bitmap.
texturesize = 512;
texturehorizclip = clip_width / (float)texturesize;
texturevertclip = clip_height / (float)texturesize;
break;
case LOW: // LOW res scanlines produces a 320x480 pixel bitmap
texturesize = 512;
texturehorizclip = clip_width / (float)texturesize;
texturevertclip = (clip_height * 2 + 1) / (float)texturesize;
break;
case MEDIUM: // MEDIUM res scanlines produces a 320x720 pixel bitmap
texturesize = 1024;
texturehorizclip = clip_width / (float)texturesize;
texturevertclip = (clip_height * 3 + 2) / (float)texturesize;
break;
case HIGH: // HIGH res canlines produces a 320x960 pixel bitmap
texturesize = 1024;
texturehorizclip = clip_width / (float)texturesize;
texturevertclip = (clip_height * 4 + 3) / (float)texturesize;
break;
}
// now lets go ahead and create a blank texture of the appropriate dimensions
d3d_device->CreateTexture(texturesize, texturesize, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &texture_buffer, NULL );
return;
}
// this function creates the 2D vertex buffer polygon and attaches the texture to it
void init_vertices(float x, float y, float z)
{
// Create the vertices.
// What we're actually doing here is specifying two right triangles
// attached to one another to form a wireframe rectangle. We also specify
// that our texture (the screen) should be mapped to extend to the edges
// of this rectangle. This is basically how we create a 2D surface with
// a 3D toolset.
struct CUSTOMVERTEX vertex_def[] =
{
{-x, y, z, 0xffffffff, 0, 0,},
{x, y, z, 0xffffffff, texturehorizclip, 0,},
{-x, -y, -z, 0xffffffff, 0, texturevertclip,},
{x, -y, -z, 0xffffffff, texturehorizclip, texturevertclip,},
};
d3d_device->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX),
0,
CUSTOMFVF,
D3DPOOL_MANAGED,
&vertex_buffer,
NULL);
VOID* pVoid; // a void pointer
// lock vertex_buffer and load the vertices into it
vertex_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertex_def, sizeof(vertex_def));
vertex_buffer->Unlock();
return;
}
// this is the function used to render each frame
void refreshv_direct3d(UBYTE *scr_ptr, FRAMEPARAMS *fp)
{
// clear the contents of the vertex buffer polygon and make it black
d3d_device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3d_device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
// If the caller has set fp->d3dRefresh to true it means that the vertex
// buffer has changed (usually because the window or texture size has changed).
// In these cases we will re-init the vertices prior to building the frame.
if (fp->d3dRefresh)
{
if (hD3DX != NULL)
{
init_vertices(fp->d3dWidth, 0, fp->d3dHeight);
}
else
{
init_vertices(fp->d3dWidth, fp->d3dHeight, 0);
}
fp->d3dRefresh = FALSE;
}
// We can now unlock the backbuffer and start to draw our frame
d3d_device->BeginScene();
// refresh the texture buffer for the frame
// this function call actually draws the contents of the Atari screen buffer
// to the Direct3D backbuffer.
refresh_frame(scr_ptr, fp);
// set the texture
d3d_device->SetTexture(0, texture_buffer);
// select the vertex buffer to display
d3d_device->SetStreamSource(0, vertex_buffer, 0, sizeof(CUSTOMVERTEX));
//***********************************************************************
// This next section supports the 3D screensaver and tilt functions by
// using some simple matrix tranformations on the vertex buffer polygon.
// Note: If you want to remove this 3D screensaver effect and operate
// in a more purely 2D view, change the init_vertices statement above to
// init_vertices(fp->d3dWidth, fp->d3dHeight, 0);
// and remove all statements from here to the end of this
// 3D Matrix Transformations section.
//***********************************************************************
if (hD3DX != NULL)
{
D3DXMATRIX matView;
static float index = pi; // rotation amount
static float cy = 2.41f; // amount of zoom
static float cz = 0.00001f; // amount of tilt
static float by = 0.0;
if (fp->screensaver)
{
fp->tiltlevel = TILTLEVEL0; // make sure tiltlevel is disabled
// this transformation creates and animates the 3D screensaver
if (cy > 1.5f)
cy -= 0.002f; // zoom
if (cz < 2.2)
cz += 0.005f; // tilt
index+=0.005f; // rotation index
}
else if (fp->tiltlevel != TILTLEVEL0)
{
index = pi;
switch (fp->tiltlevel)
{
case TILTLEVEL1:
if (cz < 1.0)
cz += 0.012f; // tilt
if (by > -0.2f)
by -= 0.003f; // slide up
break;
case TILTLEVEL2:
if (cz < 1.5)
cz += 0.016f; // tilt
if (cy > 2.3f)
cy -= 0.004f; // zoom
break;
case TILTLEVEL3:
if (cz < 1.8)
cz += 0.012f; // tilt
if (cy > 2.1f)
cy -= 0.008f; // zoom
if (by > -0.25f)
by -= 0.002f; // slide up
break;
}
}
else
{
// this transformation creates a standard 2D view
index = pi;
cy = 2.41f;
cz = 0.00001f;
by = 0.0;
}
// Create the transform matView
D3DXMatrixLookAtLHPtr(&matView,
&D3DXVECTOR3 (0.0f, cy, cz), // tilt & zoom the camera
&D3DXVECTOR3 (0.0f, by, 0.0f), // raise & lower the camera
&D3DXVECTOR3 (0.0f, 1.0, 0.0f)); // flip the camera
d3d_device->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLHPtr(&matProjection,
D3DXToRadian(45), // the horizontal field of view
1.0f, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3d_device->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
// set the world transform
D3DXMATRIX matRotateY; // a matrix to store the rotation for each triangle
D3DXMatrixRotationYPtr(&matRotateY, index); // the rotation matrix
d3d_device->SetTransform(D3DTS_WORLD, &(matRotateY)); // set the world transform
}
//***********************************************************************
// End 3D transformations
//***********************************************************************
// draw the fully rendered and transformed surface to the backbuffer
d3d_device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
// We now lock the backbuffer
d3d_device->EndScene();
// Now tell Direct3D to flip the image to the screen.
d3d_device->Present(NULL, NULL, NULL, NULL);
return;
}
// shutdown the Direct3D engine
extern "C" void shutdowndirect3d(void)
{
vertex_buffer->Release(); // close and release the vertex buffer
texture_buffer->Release(); // close and release the texture
d3d_device->Release(); // close and release the 3D device
d3d->Release(); // close and release Direct3D
if (hD3DX != NULL)
{
FreeLibrary(hD3DX);
hD3DX = NULL;
}
return;
}
// Copy the raw screen buffer data to the texture buffer
void refresh_frame(UBYTE *scr_ptr, FRAMEPARAMS *fp)
{
int pixel = 0;
int i, x, y;
int texturewidth;
// calculate texture width
int viewwidth = fp->view.right - fp->view.left;
D3DLOCKED_RECT d3dlr;
texture_buffer->LockRect(0, &d3dlr, 0, 0);
DWORD* pixels = (DWORD*)d3dlr.pBits;
texturewidth = d3dlr.Pitch / 4;
// copy screen buffer to the texture
scr_ptr += fp->view.top * Screen_WIDTH + fp->view.left;
for (y = fp->view.top; y < fp->view.bottom; y++) {
for (x = fp->view.left; x < fp->view.right; x++) {
if (y < 0 || y >= Screen_HEIGHT || x < 0 || x >= Screen_WIDTH)
pixels[pixel] = Colours_table[0];
else
pixels[pixel] = Colours_table[*scr_ptr];
for (i = 0; i < fp->scanlinemode; i++) {
pixels[pixel + i * texturewidth] = pixels[pixel];
}
scr_ptr++;
pixel++;
}
scr_ptr += Screen_WIDTH - viewwidth;
pixel += texturewidth - viewwidth;
pixel += texturewidth * fp->scanlinemode;
}
texture_buffer->UnlockRect(0);
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef _RENDER_DIRECT3D_H_
#define _RENDER_DIRECT3D_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "atari.h"
#include "screen_win32.h"
void startupdirect3d(int screenwidth, int screenheight, BOOL windowed, FRAMEPARAMS *fp);
void shutdowndirect3d(void);
void refreshv_direct3d(UBYTE *scr_ptr, FRAMEPARAMS *fp);
void init_vertices(float x, float y, float z);
void refresh_frame(UBYTE *scr_ptr, FRAMEPARAMS *fp);
void initpresentparams(int screenwidth, int screenheight, BOOL windowed);
void resetdevice(int screenwidth, int screenheight, BOOL windowed, FRAMEPARAMS *fp);
void initdevice(FRAMEPARAMS *fp);
#ifdef __cplusplus
}
#endif
#endif
+272
View File
@@ -0,0 +1,272 @@
#include "render_directdraw.h"
#include "main.h"
#include "colours.h"
#include "screen_win32.h"
#include "screen.h"
#include <ddraw.h>
#include <stdio.h>
#define MAX_CLR 0x100
static PALETTEENTRY pal[MAX_CLR]; /* palette */
static LPDIRECTDRAW4 lpDD = NULL;
static LPDIRECTDRAWSURFACE4 lpDDSPrimary = NULL;
static LPDIRECTDRAWSURFACE4 lpDDSBack = NULL;
static LPDIRECTDRAWSURFACE4 lpDDSsrc = NULL;
static LPDIRECTDRAWPALETTE lpDDPal = NULL;
static int linesize = 0;
static int scrwidth = SCREENWIDTH;
static int scrheight = SCREENHEIGHT;
static UBYTE *scraddr = NULL;
/* Platform-specific function to update the palette if it changed */
void PLATFORM_PaletteUpdate(void)
{
if(lpDDPal != NULL) {
int i;
for (i = 0; i < MAX_CLR; i++) {
palette(i, Colours_GetR(i), Colours_GetG(i), Colours_GetB(i));
}
palupd(0, MAX_CLR);
}
}
static int initFail(HWND hwnd, const char *func, HRESULT hr)
{
char txt[256];
sprintf(txt, "DirectDraw Init FAILED: %s returned 0x%x", func, (unsigned int)hr);
MessageBox(hwnd, txt, myname, MB_OK);
groff();
DestroyWindow(hwnd);
return 1;
}
void palupd(int beg, int cnt)
{
IDirectDrawPalette_SetEntries(lpDDPal, 0, beg, cnt, pal);
}
void palette(int ent, UBYTE r, UBYTE g, UBYTE b)
{
if (ent >= MAX_CLR)
return;
pal[ent].peRed = r;
pal[ent].peGreen = g;
pal[ent].peBlue = b;
pal[ent].peFlags = 0;
}
/* Platform-specific function to update the palette if it changed */
void Atari_PaletteUpdate(void)
{
if(lpDDPal != NULL) {
int i;
for (i = 0; i < MAX_CLR; i++) {
palette(i, Colours_GetR(i), Colours_GetG(i), Colours_GetB(i));
}
palupd(0, MAX_CLR);
}
}
int startupdirectdraw(BOOL bltgfx, INT width)
{
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
HRESULT ddrval;
int i;
if (width > 0) {
scrwidth = width;
scrheight = width * 3 / 4;
}
ddrval = DirectDrawCreate(NULL, (void *) &lpDD, NULL);
if (FAILED(ddrval))
return initFail(hWndMain, "DirectDrawCreate", ddrval);
ddrval = IDirectDraw4_QueryInterface(lpDD, &IID_IDirectDraw4, (void *) &lpDD);
if (FAILED(ddrval))
return initFail(hWndMain, "QueryInterface", ddrval);
ddrval = IDirectDraw4_SetCooperativeLevel(lpDD, hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (FAILED(ddrval))
return initFail(hWndMain, "SetCooperativeLevel", ddrval);
if (bltgfx) {
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddrval = IDirectDraw4_GetDisplayMode(lpDD, &ddsd);
if (FAILED(ddrval))
return initFail(hWndMain, "GetDisplayMode", ddrval);
ddrval = IDirectDraw4_SetDisplayMode(lpDD, ddsd.dwWidth, ddsd.dwHeight, 32, 0, 0);
}
else {
ddrval = IDirectDraw4_SetDisplayMode(lpDD, scrwidth, scrheight, 8, 0, 0);
}
if (FAILED(ddrval)) {
if ((ddrval == DDERR_INVALIDMODE || ddrval == DDERR_UNSUPPORTED) && !bltgfx && width != 640) {
/* 320x240 results in DDERR_INVALIDMODE on my Win98SE / Radeon 9000 */
/* 320x240 results in DDERR_UNSUPPORTED on my WinXP / Toshiba laptop */
MessageBox(hWndMain,
"DirectDraw does not support the requested display mode.\n"
"Try running with \"-blt\" or \"-width 640\" on the command line.",
myname, MB_OK);
groff();
DestroyWindow(hWndMain);
return 1;
}
return initFail(hWndMain, "SetDisplayMode", ddrval);
}
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddrval = IDirectDraw4_CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL);
if (FAILED(ddrval))
return initFail(hWndMain, "CreateSurface", ddrval);
memset(&ddscaps, 0, sizeof(ddscaps));
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = IDirectDrawSurface4_GetAttachedSurface(lpDDSPrimary, &ddscaps, &lpDDSBack);
if (FAILED(ddrval))
return initFail(hWndMain, "GetAttachedSurface", ddrval);
if (bltgfx) {
ddrval = IDirectDraw4_GetDisplayMode(lpDD, &ddsd);
if (FAILED(ddrval))
return initFail(hWndMain, "GetDisplayMode", ddrval);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
ddsd.dwWidth = 336;
ddsd.dwHeight = 252;
ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
ddrval = IDirectDraw4_CreateSurface(lpDD, &ddsd, &lpDDSsrc, NULL);
if (FAILED(ddrval))
return initFail(hWndMain, "CreateSurface", ddrval);
ddrval = IDirectDrawSurface4_Lock(lpDDSsrc, NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL);
if (FAILED(ddrval))
return initFail(hWndMain, "Lock", ddrval);
memset(ddsd.lpSurface, 0, ddsd.lPitch * ddsd.dwHeight);
ddrval = IDirectDrawSurface4_Unlock(lpDDSsrc, NULL);
}
else {
for (i = 0; i < MAX_CLR; i++)
palette(i, Colours_GetR(i), Colours_GetG(i), Colours_GetB(i));
IDirectDraw4_CreatePalette(lpDD, DDPCAPS_8BIT, pal, &lpDDPal, NULL);
if (lpDDPal)
IDirectDrawSurface4_SetPalette(lpDDSPrimary, lpDDPal);
}
return 0;
}
void shutdowndirectdraw(void)
{
if (lpDD != NULL) {
if (lpDDSsrc != NULL) {
IDirectDrawSurface4_Release(lpDDSsrc);
lpDDSsrc = NULL;
}
if (lpDDSPrimary != NULL) {
IDirectDrawSurface4_Release(lpDDSPrimary);
lpDDSPrimary = NULL;
}
if (lpDDPal != NULL) {
IDirectDrawPalette_Release(lpDDPal);
lpDDPal = NULL;
}
IDirectDraw4_Release(lpDD);
lpDD = NULL;
}
}
void refreshv_directdraw(UBYTE *scr_ptr, BOOL bltgfx)
{
DDSURFACEDESC2 desc0;
int err;
int x, y;
UBYTE *srcb;
ULONG *srcl;
ULONG *dst;
int h, w;
DDBLTFX ddbltfx;
desc0.dwSize = sizeof(desc0);
err = IDirectDrawSurface4_Lock(bltgfx ? lpDDSsrc : lpDDSBack,
NULL, &desc0, DDLOCK_WRITEONLY | DDLOCK_WAIT ,NULL);
if (err == DD_OK) {
linesize = desc0.lPitch;
scrwidth = desc0.dwWidth;
scrheight = desc0.dwHeight;
scraddr = (UBYTE *) desc0.lpSurface + (bltgfx ? linesize * 6 : 0);
if (bltgfx) {
for (y = 0; y < Screen_HEIGHT; y++) {
dst = (ULONG *) (scraddr + y * linesize);
srcb = scr_ptr + y * Screen_WIDTH;
for (x = 0; x < scrwidth; x++)
*dst++ = Colours_table[*srcb++];
}
}
else {
w = (scrwidth - 336) / 2;
h = (scrheight - Screen_HEIGHT) / 2;
if (w > 0)
scraddr += w;
else if (w < 0)
scr_ptr -= w;
if (h > 0)
scraddr += linesize * h;
for (y = 0; y < Screen_HEIGHT; y++) {
dst = (ULONG *) (scraddr + y * linesize);
srcl = (ULONG *) (scr_ptr + y * Screen_WIDTH);
for (x = (w >= 0) ? (336 >> 2) : (scrwidth >> 2); x > 0; x--)
*dst++ = *srcl++;
}
}
IDirectDrawSurface4_Unlock(bltgfx ? lpDDSsrc : lpDDSBack, NULL);
linesize = 0;
scrwidth = 0;
scrheight = 0;
scraddr = 0;
}
else if (err == DDERR_SURFACELOST)
err = IDirectDrawSurface4_Restore(bltgfx ? lpDDSsrc : lpDDSBack);
else {
char txt[256];
sprintf(txt, "DirectDraw error 0x%x", err);
MessageBox(hWndMain, txt, myname, MB_OK);
/* printf("error: %x\n", err); */
exit(1);
}
if (bltgfx) {
memset(&ddbltfx, 0, sizeof(ddbltfx));
ddbltfx.dwSize = sizeof(ddbltfx);
err = IDirectDrawSurface4_Blt(lpDDSBack, NULL, lpDDSsrc,
NULL, DDBLT_WAIT, &ddbltfx);
if (err == DDERR_SURFACELOST)
err = IDirectDrawSurface4_Restore(lpDDSBack);
}
#if (SHOWFRAME > 0)
palette(0, 0x20, 0x20, 0);
palupd(CLR_BACK, 1);
#endif
err = IDirectDrawSurface4_Flip(lpDDSPrimary, NULL, DDFLIP_WAIT);
/* err = IDirectDrawSurface3_Flip(lpDDSPrimary, NULL, 0); */
if (err == DDERR_SURFACELOST)
err = IDirectDrawSurface4_Restore(lpDDSPrimary);
#if (SHOWFRAME > 0)
palette(0, 0x0, 0x20, 0x20);
palupd(CLR_BACK, 1);
#endif
#if (SHOWFRAME > 0)
palette(0, 0x0, 0x0, 0x0);
palupd(CLR_BACK, 1);
#endif
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef _RENDER_DIRECTDRAW_H_
#define _RENDER_DIRECTDRAW_H_
#include "screen_win32.h"
int startupdirectdraw(BOOL bltgfx, INT width);
void shutdowndirectdraw(void);
void refreshv_directdraw(UBYTE *scr_ptr, BOOL bltgfx);
#endif
+83
View File
@@ -0,0 +1,83 @@
#include "render_gdi.h"
#include "screen_win32.h"
#include "colours.h"
#include "screen.h"
extern HWND hWndMain;
extern char *myname;
// GDI specific rendering code
void refreshv_gdi(UBYTE *scr_ptr, FRAMEPARAMS *fp)
{
HDC hCdc;
BITMAPINFO bi;
HBITMAP hBitmap;
DWORD *pixels = NULL;
int pixel = 0;
int i, x, y;
int v_adj = 0;
// calculate bitmap height & width
int bmWidth = fp->view.right - fp->view.left;
int bmHeight = fp->view.bottom - fp->view.top;
bmHeight *= fp->scanlinemode + 1;
// GDI specific window fill adjustment
if (!fp->scanlinemode) {
v_adj = (int) fp->height / bmHeight;
}
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = bmWidth;
bi.bmiHeader.biHeight = bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = 0;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
hCdc = CreateCompatibleDC(fp->hdc);
hBitmap = CreateDIBSection(hCdc, &bi, DIB_RGB_COLORS, (void *)&pixels, NULL, 0);
if (!hBitmap) {
MessageBox(hWndMain, "Could not create bitmap", myname, MB_OK);
DestroyWindow(hWndMain);
return;
}
// copy screen buffer to the bitmap
scr_ptr += fp->view.top * Screen_WIDTH + fp->view.left;
for (y = fp->view.top; y < fp->view.bottom; y++) {
for (x = fp->view.left; x < fp->view.right; x++) {
if (y < 0 || y >= Screen_HEIGHT || x < 0 || x >= Screen_WIDTH)
pixels[pixel] = Colours_table[0];
else
pixels[pixel] = Colours_table[*scr_ptr];
for (i = 0; i < fp->scanlinemode; i++) {
pixels[pixel + i * bmWidth] = pixels[pixel];
}
scr_ptr++;
pixel++;
}
scr_ptr += Screen_WIDTH - bmWidth;
pixel += bmWidth * fp->scanlinemode;
}
SelectObject(hCdc, hBitmap);
// Draw the bitmap on the screen. The image must be flipped vertically
if (!StretchBlt(fp->hdc, fp->x_origin, fp->y_origin, fp->width, fp->height + v_adj,
hCdc, 0, bi.bmiHeader.biHeight, bi.bmiHeader.biWidth, -bi.bmiHeader.biHeight, SRCCOPY))
{
MessageBox(hWndMain, "Could not StretchBlt", myname, MB_OK);
DestroyWindow(hWndMain);
}
DeleteDC(hCdc);
DeleteObject(hBitmap);
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef _RENDER_GDI_H_
#define _RENDER_GDI_H_
#include "screen_win32.h"
void refreshv_gdi(UBYTE *scr_ptr, FRAMEPARAMS *fp);
#endif
+113
View File
@@ -0,0 +1,113 @@
#include "config.h"
#include "render_gdiplus.h"
#include "screen.h"
// GDI+ used to support interpolated filtering
#include <gdiplus.h>
using namespace Gdiplus;
extern "C" {
#include "colours.h"
}
// GDI+ startup stuff
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// End GDI+ startup stuff
// Required startup function call for the GDI+ engine
extern "C" void startupgdiplus(void)
{
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}
// Shutdown the GDI+ engine
extern "C" void shutdowngdiplus(void)
{
GdiplusShutdown(gdiplusToken);
}
// GDI+ specific frame rendering code
extern "C" void refreshv_gdiplus(UBYTE *scr_ptr, FRAMEPARAMS *fp)
{
UINT* pixels;
int pixel = 0;
int i, x, y;
int scanlinelength;
InterpolationMode im;
int h_adj = 0;
int v_adj = 0;
// calculate bitmap height & width
int bmWidth = fp->view.right - fp->view.left;
int bmHeight = fp->view.bottom - fp->view.top;
bmHeight *= fp->scanlinemode + 1;
// gdiplus specific window fill adjustment
if (!fp->scanlinemode) {
v_adj = 1;
h_adj = 1;
}
// Choose the appropriate interpolation filter
switch (fp->filter)
{
case NEARESTNEIGHBOR:
im = InterpolationModeNearestNeighbor;
break;
case BILINEAR:
im = InterpolationModeBilinear;
break;
case BICUBIC:
im = InterpolationModeBicubic;
break;
case HQBILINEAR:
im = InterpolationModeHighQualityBilinear;
break;
case HQBICUBIC:
im = InterpolationModeHighQualityBicubic;
break;
default:
im = InterpolationModeNearestNeighbor;
}
Rect r(0, 0 , bmWidth, bmHeight);
Bitmap* bitmap = new Bitmap(bmWidth, bmHeight, PixelFormat32bppRGB);
BitmapData bitmapData;
bitmap->LockBits(&r, ImageLockModeWrite, PixelFormat32bppRGB, &bitmapData);
pixels = (UINT*)bitmapData.Scan0;
scanlinelength = bitmapData.Stride / 4;
// copy screen buffer to the bitmap
scr_ptr += fp->view.top * Screen_WIDTH + fp->view.left;
for (y = fp->view.top; y < fp->view.bottom; y++) {
for (x = fp->view.left; x < fp->view.right; x++) {
if (y < 0 || y >= Screen_HEIGHT || x < 0 || x >= Screen_WIDTH)
pixels[pixel] = Colours_table[0];
else
pixels[pixel] = Colours_table[*scr_ptr];
for (i = 0; i < fp->scanlinemode; i++) {
pixels[pixel + i * scanlinelength] = pixels[pixel];
}
scr_ptr++;
pixel++;
}
scr_ptr += Screen_WIDTH - bmWidth;
pixel += scanlinelength * fp->scanlinemode;
}
bitmap->UnlockBits(&bitmapData);
Graphics* graphics = new Graphics(fp->hdc);
graphics->SetInterpolationMode(im);
graphics->DrawImage(bitmap, fp->x_origin, fp->y_origin, fp->width + h_adj, fp->height + v_adj);
delete graphics;
delete bitmap;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef _RENDER_GDIPLUS_H_
#define _RENDER_GDIPLUS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "screen_win32.h"
void startupgdiplus(void);
void shutdowngdiplus(void);
void refreshv_gdiplus(UBYTE *scr_ptr, FRAMEPARAMS *fp);
#ifdef __cplusplus
}
#endif
#endif /* _RENDER_GDIPLUS_H_ */
File diff suppressed because it is too large Load Diff
+143
View File
@@ -0,0 +1,143 @@
#ifndef _SCREEN_WIN32_H_
#define _SCREEN_WIN32_H_
#include "atari.h"
#define SCREENWIDTH 336
#define SCREENHEIGHT 240
#define CROPPEDWIDTH 320
#define STD_CROP 8
#define STD_INDENT 24
#define CLR_BACK 0x44
typedef enum CHANGEWINDOWSIZE_ {
STEPUP,
STEPDOWN,
SET,
RESET
} CHANGEWINDOWSIZE;
typedef enum TILTLEVEL_ {
TILTLEVEL0,
TILTLEVEL1,
TILTLEVEL2,
TILTLEVEL3
} TILTLEVEL;
typedef enum SCANLINEMODE_ {
NONE,
LOW,
MEDIUM,
HIGH
} SCANLINEMODE;
typedef enum ASPECTMODE_ {
OFF,
NORMAL,
SIMPLE,
ADAPTIVE
} ASPECTMODE;
typedef enum ASPECTRATIO_ {
AUTO,
WIDE,
CROPPED,
COMPRESSED
} ASPECTRATIO;
typedef enum RENDERMODE_ {
DIRECTDRAW,
GDI,
GDIPLUS,
DIRECT3D
} RENDERMODE;
typedef enum FILTER_ {
NEARESTNEIGHBOR,
BILINEAR,
BICUBIC,
HQBILINEAR,
HQBICUBIC
} FILTER;
typedef enum DISPLAYMODE_ {
GDI_NEARESTNEIGHBOR,
GDIPLUS_NEARESTNEIGHBOR,
GDIPLUS_BILINEAR,
GDIPLUS_HQBILINEAR,
GDIPLUS_HQBICUBIC,
DIRECT3D_NEARESTNEIGHBOR,
DIRECT3D_BILINEAR,
GDIPLUS_BICUBIC
} DISPLAYMODE;
typedef enum SCREENMODE_ {
FULLSCREEN,
WINDOW
} SCREENMODE;
typedef enum FSRESOLUTION_ {
DESKTOP, /* Current Desktop Resolution */
VGA, /* 4:3 [640x480] (2x) */
SXGA, /* 4:3 [1280x960] (4x) */
UXGA /* 4:3 [1600x1200] (5x) */
} FSRESOLUTION;
typedef struct FRAMEPARAMS_ {
HDC hdc;
RECT view; /* viewport frame relative to the screen buffer */
int width; /* window width */
int height; /* window height */
int x_origin; /* x origin within the window */
int y_origin; /* y origin within the window */
float d3dWidth; /* specialized width for use by direct3d only */
float d3dHeight; /* specialized height for use by direct3d only */
BOOL d3dRefresh; /* determines whether vertex buffer should be refreshed */
SCANLINEMODE scanlinemode; /* scanline mode */
FILTER filter; /* render mode filter, i.e. bilinear, etc. */
TILTLEVEL tiltlevel; /* level of 3D tilt */
BOOL screensaver; /* 3D screensaver on/off */
} FRAMEPARAMS;
typedef struct CROP_ {
int horizontal;
int vertical;
} CROP;
typedef struct OFFSET_ {
int horizontal;
int vertical;
} OFFSET;
extern BOOL checkparamarg(char arg[]);
BOOL getres(char res[], int *width, int *height);
int gron(int *argc, char *argv[]);
void groff(void);
void palupd(int beg, int cnt);
void palette(int ent, UBYTE r, UBYTE g, UBYTE b);
void refreshv(UBYTE * scr_ptr);
void togglewindowstate(void);
void changewindowsize(CHANGEWINDOWSIZE, int);
void getscaledrect(RECT *rect);
void refreshframe(void);
void changescanlinemode(void);
void togglescreensaver(void);
void changetiltlevel(void);
void getcenteredcoords(RECT rect, int* x, int* y);
void setcursor(void);
void destroymenu(void);
void initmenu(void);
void setmenu(void);
void restoremenu(void);
void togglemenustate(void);
void getnativecoords(int mx, int my, int* nx, int* ny);
RENDERMODE GetRenderMode(void);
DISPLAYMODE GetDisplayMode(void);
DISPLAYMODE GetActiveDisplayMode(void);
SCREENMODE GetScreenMode(void);
void SetDisplayMode(DISPLAYMODE dm);
void GetDisplayModeName(char *name);
#endif /* _SCREEN_WIN32_H_ */
+553
View File
@@ -0,0 +1,553 @@
/*
* sound.c - Win32 port specific code
*
* Copyright (C) 2000 Krzysztof Nikiel
* Copyright (C) 2000-2003 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#ifdef SOUND
#include <windows.h>
#ifdef DIRECTX
# define DIRECTSOUND_VERSION 0x0500
# include <dsound.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "sound.h"
#include "main.h"
#include "pokeysnd.h"
#include "atari.h"
#include "log.h"
#define MIXBUFSIZE 0x1000
#define WAVSHIFT 9
#define WAVSIZE (1 << WAVSHIFT)
int buffers = 0;
enum {SOUND_NONE, SOUND_DX, SOUND_WAV};
static int usesound = TRUE;
static int issound = SOUND_NONE;
static int dsprate = 44100;
static int snddelay = 40; /* delay in milliseconds */
static int snddelaywav = 100;
static int bit16 = FALSE;
static HANDLE event;
static HWAVEOUT wout;
static WAVEHDR *waves;
#ifdef DIRECTX
static int wavonly = FALSE;
static DWORD sbufsize = 0;
static int samples = 0; /* #samples to be in play buffer */
static UBYTE mixbuf[MIXBUFSIZE];
static DWORD bufpos = 0;
static LPDIRECTSOUND lpDS = NULL;
static LPDIRECTSOUNDBUFFER pDSB = NULL;
static int initsound_dx(void)
{
DWORD i;
int err;
DSBUFFERDESC dsBD =
{0};
WAVEFORMATEX wfx;
DSBCAPS bc;
LPVOID pMem1, pMem2;
DWORD dwSize1, dwSize2;
if (issound != SOUND_NONE)
return 0;
if ((err = DirectSoundCreate(NULL, &lpDS, NULL)) < 0)
return err;
if ((err = IDirectSound_SetCooperativeLevel(lpDS, hWndMain,
DSSCL_EXCLUSIVE)) < 0)
goto end;
dsBD.dwSize = sizeof(dsBD);
dsBD.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
dsBD.dwBufferBytes = 0x4000;
dsBD.lpwfxFormat = &wfx;
wfx.wFormatTag = WAVE_FORMAT_PCM;
#ifdef STEREO_SOUND
wfx.nChannels = POKEYSND_stereo_enabled ? 2 : 1;
#else
wfx.nChannels = 1;
#endif /* STEREO_SOUND */
wfx.nSamplesPerSec = dsprate;
wfx.nAvgBytesPerSec = dsprate * wfx.nChannels * (bit16 ? 2 : 1);
wfx.nBlockAlign = wfx.nChannels * (bit16 ? 2 : 1);
wfx.wBitsPerSample = bit16 ? 16 : 8;
wfx.cbSize = 0;
if ((err = IDirectSound_CreateSoundBuffer(lpDS, &dsBD, &pDSB, NULL)) < 0)
goto end;
bc.dwSize = sizeof(bc);
IDirectSoundBuffer_GetCaps(pDSB, &bc);
sbufsize = bc.dwBufferBytes;
if ((err = IDirectSoundBuffer_Lock(pDSB, 0, sbufsize,
&pMem1, &dwSize1, &pMem2, &dwSize2,
DSBLOCK_FROMWRITECURSOR)) < 0)
goto end;
for (i = 0; i < dwSize1 >> 1; i++)
*((short *) pMem1 + i) = 0;
for (i = 0; i < dwSize2 >> 1; i++)
*((short *) pMem2 + i) = 0;
IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2);
IDirectSoundBuffer_Play(pDSB, 0, 0, DSBPLAY_LOOPING);
POKEYSND_Init(POKEYSND_FREQ_17_EXACT, (UWORD) dsprate, (UBYTE) wfx.nChannels, (bit16 ? POKEYSND_BIT16 : 0));
samples = dsprate * snddelay / 1000;
IDirectSoundBuffer_GetCurrentPosition(pDSB, 0, &bufpos);
issound = SOUND_DX;
return 0;
end:
MessageBox(hWndMain, "DirectSound Init FAILED", myname, MB_OK);
Sound_Exit();
return err;
}
static void uninitsound_dx(void)
{
if (issound != SOUND_DX)
return;
if (lpDS)
{
if (pDSB)
{
IDirectSoundBuffer_Stop(pDSB);
IDirectSoundBuffer_Release(pDSB);
pDSB = NULL;
}
IDirectSound_Release(lpDS);
lpDS = NULL;
}
issound = SOUND_NONE;
}
static void sound_update_dx(void)
{
DWORD wc;
int d1;
LPVOID pMem1, pMem2;
DWORD dwSize1, dwSize2;
signed short *p1s;
signed short *p2s;
UBYTE *p1b;
UBYTE *p2b;
signed short *pbufs;
UBYTE *pbufb;
int s1, s2;
int err;
int i;
int samplesize = bit16 ? 2 : 1;
#ifdef STEREO_SOUND
if (POKEYSND_stereo_enabled) samplesize *= 2;
#endif
if (issound != SOUND_DX)
return;
IDirectSoundBuffer_GetCurrentPosition(pDSB, 0, &wc);
d1 = (wc - bufpos);
if ((DWORD) abs(d1) > (sbufsize >> 1)) {
if (d1 < 0)
d1 += sbufsize;
else
d1 -= sbufsize;
}
if (d1 < (-samples * samplesize)) // there is more than necessary bytes filled?
return;
d1 = (samples * samplesize) + d1; // bytes to fill
d1 = (d1 / samplesize) * samplesize; //round to a sample pair
if (d1 > (sizeof(mixbuf) / sizeof(mixbuf[0])))
{
d1 = (sizeof(mixbuf) / sizeof(mixbuf[0]));
}
if ((err = IDirectSoundBuffer_Lock(pDSB,
bufpos,
d1,
&pMem1, &dwSize1,
&pMem2, &dwSize2,
0)) < 0)
{
if (err == DSERR_BUFFERLOST)
Sound_Continue();
return;
}
s1 = dwSize1;
s2 = dwSize2;
p1s = (signed short *)pMem1;
p2s = (signed short *)pMem2;
p1b = (UBYTE *)pMem1;
p2b = (UBYTE *)pMem2;
bufpos += (s1 + s2);
if (bufpos >= sbufsize)
bufpos -= sbufsize;
if (bit16)
{
s1 /= 2;
s2 /= 2;
}
i = s1 + s2;
POKEYSND_Process(mixbuf, i);
pbufs = (signed short *)mixbuf;
pbufb = (UBYTE *)mixbuf;
if (s1)
{
if (bit16)
for (; s1; s1--)
*p1s++ = *pbufs++;
else
for (; s1; s1--)
*p1b++ = *pbufb++;
}
if (s2)
{
if (bit16)
for (; s2; s2--)
*p2s++ = *pbufs++;
else
for (; s2; s2--)
*p2b++ = *pbufb++;
}
IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2);
return;
}
#endif /* DIRECTX */
static void uninitsound_wav(void)
{
int i;
MMRESULT err;
if (issound != SOUND_WAV)
return;
l0:
for (i = 0; i < buffers; i++)
{
if (!(waves[i].dwFlags & WHDR_DONE))
{
WaitForSingleObject(event, 5000);
ResetEvent(event);
goto l0;
}
}
waveOutReset (wout);
for (i = 0; i < buffers; i++)
{
err = waveOutUnprepareHeader(wout, &waves[i], sizeof (waves[i]));
if (err != MMSYSERR_NOERROR)
{
fprintf(stderr, "warning: cannot unprepare wave header (%x)\n", err);
}
free(waves[i].lpData);
}
free(waves);
waveOutClose(wout);
CloseHandle(event);
issound = SOUND_NONE;
}
static int initsound_wav(void)
{
int i;
WAVEFORMATEX wfx;
MMRESULT err;
event = CreateEvent(NULL, TRUE, FALSE, NULL);
memset(&wfx, 0, sizeof(wfx));
wfx.wFormatTag = WAVE_FORMAT_PCM;
#ifdef STEREO_SOUND
wfx.nChannels = POKEYSND_stereo_enabled ? 2 : 1;
#else
wfx.nChannels = 1;
#endif /* STEREO_SOUND */
wfx.nSamplesPerSec = dsprate;
wfx.nAvgBytesPerSec = dsprate * wfx.nChannels * (bit16 ? 2 : 1);
wfx.nBlockAlign = wfx.nChannels * (bit16 ? 2 : 1);
wfx.wBitsPerSample = bit16 ? 16 : 8;
wfx.cbSize = 0;
err = waveOutOpen(&wout, WAVE_MAPPER, &wfx, (int)event, 0, CALLBACK_EVENT);
if (err == WAVERR_BADFORMAT)
{
Log_print("wave output parameters unsupported\n");
exit(1);
}
if (err != MMSYSERR_NOERROR)
{
Log_print("cannot open wave output (%x)\n", err);
exit(1);
}
buffers = ((wfx.nAvgBytesPerSec * snddelaywav / 1000) >> WAVSHIFT) + 1;
waves = (WAVEHDR *)malloc(buffers * sizeof(*waves));
for (i = 0; i < buffers; i++)
{
memset(&waves[i], 0, sizeof (waves[i]));
if (!(waves[i].lpData = (LPSTR)malloc(WAVSIZE)))
{
Log_print("could not get wave buffer memory\n");
exit(1);
}
waves[i].dwBufferLength = WAVSIZE;
err = waveOutPrepareHeader(wout, &waves[i], sizeof(waves[i]));
if (err != MMSYSERR_NOERROR)
{
Log_print("cannot prepare wave header (%x)\n", err);
exit(1);
}
waves[i].dwFlags |= WHDR_DONE;
}
POKEYSND_Init(POKEYSND_FREQ_17_EXACT, (UWORD) dsprate, (UBYTE) wfx.nChannels, (bit16 ? POKEYSND_BIT16 : 0));
issound = SOUND_WAV;
return 0;
}
int Sound_Initialise(int *argc, char *argv[])
{
int i, j;
int help = FALSE;
if (issound != SOUND_NONE)
return TRUE;
for (i = j = 1; i < *argc; i++)
{
int i_a = (i + 1 < *argc); /* is argument available? */
int a_m = FALSE; /* error, argument missing! */
if (strcmp(argv[i], "-sound") == 0)
usesound = TRUE;
else if (strcmp(argv[i], "-nosound") == 0)
usesound = FALSE;
else if (strcmp(argv[i], "-audio16") == 0)
bit16 = TRUE;
else if (strcmp(argv[i], "-dsprate") == 0)
{
if (i_a)
sscanf(argv[++i], "%d", &dsprate);
else a_m = TRUE;
}
else if (strcmp(argv[i], "-snddelay") == 0)
{
if (i_a)
{
sscanf(argv[++i], "%d", &snddelay);
snddelaywav = snddelay;
}
else a_m = TRUE;
}
else if (strcmp(argv[i], "-quality") == 0) {
if (i_a) {
int quality;
sscanf(argv[++i], "%d", &quality);
if (quality > 1) {
POKEYSND_SetMzQuality(quality - 1);
POKEYSND_enable_new_pokey = 1;
}
else
POKEYSND_enable_new_pokey = 0;
}
else a_m = TRUE;
}
#ifdef DIRECTX
else if (strcmp(argv[i], "-wavonly") == 0)
wavonly = TRUE;
#endif
else
{
if (strcmp(argv[i], "-help") == 0)
{
Log_print("\t-sound Enable sound\n"
"\t-nosound Disable sound\n"
#ifdef DIRECTX
"\t-wavonly Disable direct sound\n"
#endif
"\t-dsprate <rate> Set dsp rate\n"
"\t-snddelay <ms> Set sound delay\n"
"\t-audio16 Use 16 bit mixing\n"
"\t-quality <level> Set sound quality"
);
help = TRUE;
}
argv[j++] = argv[i];
}
if (a_m) {
Log_print("Missing argument for '%s'", argv[i]);
usesound = FALSE;
return FALSE;
}
}
*argc = j;
if (help || !usesound) {
usesound = FALSE;
return TRUE;
}
#ifdef DIRECTX
if (!wavonly)
{
i = initsound_dx();
if (!i)
return TRUE;
}
#endif
initsound_wav();
return TRUE;
}
void Sound_Reinit(void)
{
if (usesound)
{
Sound_Exit();
#ifdef DIRECTX
if (!wavonly)
{
int i = initsound_dx();
if (!i)
return;
}
#endif
initsound_wav();
}
return;
}
void Sound_Exit(void)
{
#ifdef DIRECTX
if (issound == SOUND_DX)
uninitsound_dx();
#endif
if (issound == SOUND_WAV)
uninitsound_wav();
issound = SOUND_NONE;
}
static WAVEHDR *getwave(void)
{
int i;
for (i = 0; i < buffers; i++)
{
if (waves[i].dwFlags & WHDR_DONE)
{
waves[i].dwFlags &= ~WHDR_DONE;
return &waves[i];
}
}
return NULL;
}
void Sound_Update(void)
{
MMRESULT err;
WAVEHDR *wh;
switch (issound)
{
case SOUND_WAV:
while ((wh = getwave()))
{
POKEYSND_Process(wh->lpData, wh->dwBufferLength >> (bit16 ? 1 : 0));
err = waveOutWrite(wout, wh, sizeof(*wh));
if (err != MMSYSERR_NOERROR)
{
Log_print("cannot write wave output (%x)\n", err);
return;
}
}
break;
#ifdef DIRECTX
case SOUND_DX:
sound_update_dx();
#endif
}
}
void Sound_Pause(void)
{
#ifdef DIRECTX
if (issound != SOUND_DX)
return;
if (!pDSB)
return;
IDirectSoundBuffer_Stop(pDSB);
#endif
}
void Sound_Continue(void)
{
#ifdef DIRECTX
if (issound != SOUND_DX)
return;
if (!pDSB)
return;
IDirectSoundBuffer_Restore(pDSB);
IDirectSoundBuffer_Play(pDSB, 0, 0, DSBPLAY_LOOPING);
IDirectSoundBuffer_GetCurrentPosition(pDSB, 0, &bufpos);
#endif
}
#endif /* SOUND */