|
-
Dec 31st, 2011, 05:55 PM
#1
Thread Starter
Member
DOS Game Emulator
I was thinking about making a DOS game emulator in VB 2008. Is that even possible, and if it is would someone give help making it. I have used Dosbox lot. But I want to make simpler emulator.
Thanks
Hece
-
Dec 31st, 2011, 09:48 PM
#2
Re: DOS Game Emulator
Personally I think your only good language to pull this off would be in C++ cause DOS games to be emulated would require a good knowledge of Assembly, and C++ is best for it. Rom files are in binary format and have numerical instructions. Those instructions get processed either by a console system or through an emulator. Then the emulator emulates the instructions and processes it through a graphical API such as DirectX or OpenGL.
READ THIS ABOUT HOW TO WRITE A COMPUTER EMULATOR
You can download Visual C++ 2010 express edition for free if you don't have it:
Visual C++ 2010 Express Edition
Also there's Visual C++ 2008 you can download as well Visual C++ 2008 Express Edition
Next you are gonna wanna install the DirectX 9.0c SDK
Start a new project. Goto Source Files, right click it and Add New Item. Create a new cpp file and call it whatever you want such as Main.
A simple window created as an example:
c++ Code:
#include <windows.h> HWND hWnd; MSG msg; bool Running; LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_VREDRAW|CS_HREDRAW|CS_OWNDC, WindowProcedure, 0, 0, hInstance, NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, "FORM", NULL}; RegisterClassEx(&wc); hWnd = CreateWindowEx (0, "FORM", "Form1", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 330, 250, HWND_DESKTOP, NULL, hInstance, NULL); ShowWindow (hWnd, nCmdShow); Running = true; while (Running == true) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE) > 0) { if (WM_QUIT == msg.message) break; TranslateMessage (&msg); DispatchMessage (&msg); } //Render code here } return msg.wParam; } LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: Running = false; PostQuitMessage (0); HANDLE Process; Process = OpenProcess(PROCESS_ALL_ACCESS , true , GetCurrentProcessId()); TerminateProcess(Process , 0); break; case WM_KEYDOWN: if(wParam == VK_ESCAPE) { DestroyWindow(hWnd); return(0); } default: return DefWindowProc (hWnd, msg, wParam, lParam); } return 0; }
For the first time of working with DirectX9, you'll only need to do this part once ever. On the left where your project name is within Solution Explorer, right click it and goto Properties. Then goto Configuration Properties > VC++ Directories and goto Include Directories and click it to reveal a [v]. Click it and goto <Edit...>. If you do not see $(DXSDK_DIR)Include, manually put it in and click Ok. Next goto Library Directories and click it to reveal a [v]. Click it and goto <Edit...>. If you do not see $(DXSDK_DIR)Lib\x86, manually put it in and click OK. You no longer need to do that with Include and Library.
Now with every new project you will need to do this: On the left where your project name is within Solution Explorer, right click it and goto Properties. Goto Configuration Properties and goto > Linker > Input. Towards the right where it says Additional Dependencies, click it to reveal a [v] and goto <Edit...>. On top in the listbox add d3d9.lib. You are welcome to adding more dx librarys for what ever you need to do such as d3dx9.lib, dsound.lib, dplay.lib, etc. Now you are ready to code DirectX9.
Note: VC++ 2010 seems to have issues with long project path's and you will probably receive errors such as Source File Not Found even on the simplest projects. To fix this, just put your project in a new location where the file path won't be huge.
Then try this as a sample project
c++ Code:
#include <windows.h> #include <d3d9.h> struct CUSTOM_VERTEX { float X, Y, Z, RHW; DWORD Color; }; #define CUSTOM_VERTEX_FORMAT (D3DFVF_XYZRHW | D3DFVF_DIFFUSE) const D3DFORMAT COLOR_DEPTH_16_BIT = D3DFMT_R5G6B5; const D3DFORMAT COLOR_DEPTH_24_BIT = D3DFMT_A8R8G8B8; const D3DFORMAT COLOR_DEPTH_32_BIT = D3DFMT_X8R8G8B8; LPDIRECT3D9 Direct3D = NULL; LPDIRECT3DDEVICE9 Direct3D_Device = NULL; D3DDISPLAYMODE Display_Mode; D3DPRESENT_PARAMETERS Direct3D_Window; HWND hWnd; MSG msg; bool Fullscreen_Enabled; bool Running; CUSTOM_VERTEX Vertex_List[3]; CUSTOM_VERTEX Create_TLVertex(); void Create_Polygon(); void Draw_Polygon(); void Render(); void Game_Loop(); void Main(); void Shutdown(); void DirectX9_Initialize(); LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); CUSTOM_VERTEX Create_Custom_Vertex(float X, float Y, float Z, float RHW, DWORD Color) { CUSTOM_VERTEX Vertex; Vertex.X = X; Vertex.Y = Y; Vertex.Z = Z; Vertex.RHW = RHW; Vertex.Color = Color; return Vertex; } void DirectX9_Initialize() { Direct3D = Direct3DCreate9(D3D_SDK_VERSION); memset(&Direct3D_Window, 0, sizeof(D3DPRESENT_PARAMETERS)); if (Fullscreen_Enabled == true) { Display_Mode.Width = 800; Display_Mode.Height = 600; Display_Mode.Format = COLOR_DEPTH_16_BIT; Direct3D_Window.Windowed = FALSE; Direct3D_Window.BackBufferCount = 1; Direct3D_Window.BackBufferWidth = Display_Mode.Width; Direct3D_Window.BackBufferHeight = Display_Mode.Height; Direct3D_Window.hDeviceWindow = hWnd; } else { Direct3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &Display_Mode); Direct3D_Window.Windowed = TRUE; } Direct3D_Window.SwapEffect = D3DSWAPEFFECT_COPY; Direct3D_Window.BackBufferFormat = Display_Mode.Format; Direct3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &Direct3D_Window, &Direct3D_Device); } void Create_Polygon() { Vertex_List[0] = Create_Custom_Vertex(0, 0, 0, 1, D3DCOLOR_RGBA(255, 255, 255, 255)); Vertex_List[1] = Create_Custom_Vertex(100, 0, 0, 1, D3DCOLOR_RGBA(255, 255, 255, 255)); Vertex_List[2] = Create_Custom_Vertex(0, 100, 0, 1, D3DCOLOR_RGBA(255, 255, 255, 255)); Vertex_List[3] = Create_Custom_Vertex(100, 100, 0, 1, D3DCOLOR_RGBA(255, 255, 255, 255)); } void Draw_Polygon() { Direct3D_Device->SetFVF(CUSTOM_VERTEX_FORMAT); Direct3D_Device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, Vertex_List, sizeof(CUSTOM_VERTEX)); } void Render() { Direct3D_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0, 0, 0, 255), 1.0f, 0); // clear frame Direct3D_Device->BeginScene(); Create_Polygon(); Draw_Polygon(); Direct3D_Device->EndScene(); Direct3D_Device->Present(NULL, NULL, NULL, NULL); } void Game_Loop() { while (Running == true) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE) > 0) { if (WM_QUIT == msg.message) break; TranslateMessage (&msg); DispatchMessage (&msg); } else Render(); } } void Main() { DirectX9_Initialize(); Running = true; } void Shutdown() { Running = false; Direct3D_Device->Release(); Direct3D->Release(); PostQuitMessage (0); HANDLE Process; Process = OpenProcess(PROCESS_ALL_ACCESS , true , GetCurrentProcessId()); TerminateProcess(Process , 0); } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_VREDRAW|CS_HREDRAW|CS_OWNDC, WindowProcedure, 0, 0, hInstance, NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, "DX_TUT", NULL}; RegisterClassEx(&wc); if (MessageBox(hWnd, "Click Yes to go to fullscreen (Recommended)", "", MB_ICONQUESTION | MB_YESNO) == IDYES) Fullscreen_Enabled = true; if (Fullscreen_Enabled == true) hWnd = CreateWindowEx (0, "DX_TUT", "DirectX Tutorial", WS_VISIBLE | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 330, 250, HWND_DESKTOP, NULL, hInstance, NULL); else hWnd = CreateWindowEx (0, "DX_TUT", "DirectX Tutorial", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 330, 250, HWND_DESKTOP, NULL, hInstance, NULL); ShowWindow (hWnd, nCmdShow); Main(); Game_Loop(); return msg.wParam; } LRESULT CALLBACK WindowProcedure (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: Shutdown(); break; case WM_KEYDOWN: if(wParam == VK_ESCAPE) { DestroyWindow(hWnd); return(0); } default: return DefWindowProc (hWnd, msg, wParam, lParam); } return 0; }
Once you have a good understanding of C++, Win32, and the ins and outs of DOS programs, you should be able to emulate it using assembly commands. As for assembly, you are gonna wanna learn that as well over at
The Art of Assembly. A simple assembly instruction can be like so:
Code:
int add(int a, int b)
{
__asm
{
mov eax, a
mov ebx, b
add eax, ebx
}
}
This takes 2 values and adds em together. It puts a in the 32 bit register called eax. Then b in the 2nd 32 bit register called ebx. And add adds them together and sticks it back into eax. eax automatically returns the value into the function add();
Another cool thing you can do with assembly:
Code:
#include <stdio.h>
inline void Mem_Set_QUAD(void *dest, unsigned int data, int count)
{
_asm
{
mov edi, dest ;edi points to destination memory
mov ecx, count ;number of 32-bit words to move
mov eax, data ;32-bit data
rep stosd ;move data
}
}
int main(void)
{
int a[5] = {0};
Mem_Set_QUAD(a, 100, sizeof(int) * 5);
for (int i = 0; i<5; i++)
printf("%d\n", a[i]);
return 0;
}
This takes a 32 bit array and fills the entire array with a value instantly! No for loops required. Inline assembly is a little faster cause it acts as if the function wasn't called but hardcoded instead. Function calls take a microbite of speed for every call.
Last edited by Jacob Roman; Dec 31st, 2011 at 10:33 PM.
-
Dec 31st, 2011, 10:05 PM
#3
Re: DOS Game Emulator
Had to make a new post:
A Visual Basic comparison can be done with a simple exponent function. Here's the C++ method:
c++ Code:
inline int Exponent(int n, int exp) { __asm { mov eax, n ; num mov ebx, n ; exp mov ecx, exp ; counter cmp ecx, 0 je retOne cmp ecx, 1 je retVal loopstart: imul eax, ebx dec ecx cmp ecx, 1 jg loopstart jmp retVal retOne: mov eax, 1 retVal: } }
Ok before I explain what the code does, I'll talk about the registers.
eax - accumulator register (commonly used for arithmetic and is the fastest)
ebx - base address register
ecx - counter register
edx - data register
And as you may already know, these are 32 bit registers. You can actually store the data in any register you want pretty much.
Here is a VB 2008 example:
vb.net Code:
Private eax As Integer, ebx As Integer, ecx As Integer Private Function Exponent(n As Integer, exp As Integer) As Integer eax = n ebx = n ecx = exp If ecx = 0 Then Goto retOne If ecx = 1 Then Goto retVal loopstart: eax = eax * ebx ecx = ecx - 1 If ecx > 1 Then Goto loopstart Goto retVal retOne: eax = 1 retVal: Return = eax End Function
-
Jan 1st, 2012, 04:13 AM
#4
Thread Starter
Member
-
Jan 1st, 2012, 11:39 AM
#5
Re: DOS Game Emulator
Dude actually. It was all me 
You'll also need a way of making the DOS games an ISO or bin file and use a disassembler or something to understand what makes them tick.
-
Jan 2nd, 2012, 03:20 AM
#6
Thread Starter
Member
Re: DOS Game Emulator
Oh sorry, my bad. Btw you have helped me in probably every question : )
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|