Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


SteveHatcher

Member Since 27 Nov 2013
Online Last Active Today, 10:26 AM

Topics I've Started

Question about win32 window templates

Today, 07:58 AM

I have been working through Microsoft's "Learn to Program for Windows in C++" articles found here

 

Learn to Program for Windows in C++

 

http://msdn.microsoft.com/en-us/library/windows/desktop/ff381399%28v=vs.85%29.aspx

 

and have a question about the end of module 1: http://msdn.microsoft.com/en-us/library/windows/desktop/ff381400%28v=vs.85%29.aspx

 

In their sample they derive a window from a base class, where the base class is as follows:

template <class DERIVED_TYPE>
class BaseWindow
{
public:
    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        DERIVED_TYPE *pThis = NULL;
...etc

I am just trying to understand why this is created as a template. My understanding of class templates is to allow us to write a class, and use that class for any data type we want. Eg MyVector<int> or MyVector<double>

 

In this case I cant understand why they have used a template class. Can they just have gone

class MainWindow : public BaseWindow

Instead they have used

class MainWindow : public BaseWindow<MainWindow>

I just cant understand what other kinds of windows can be "derived" from this base case? I can understand in the case of calling a function with an int or a float, and needing a template there, but not in this case.

 

Thanks for your time


Text dissapearing when resizing or minimizing window.

18 November 2014 - 08:25 AM

Hello all,

 

I have a simple win32 window that opens a window and accepts some user input based on this code

 

http://msdn.microsoft.com/en-us/library/windows/desktop/ms648398%28v=vs.85%29.aspx

 

The last section "Processing Keyboard Input" contains the code I used.

 

It all appears to be working fine, except whenever the window is resized, or minimized, any text that has been entered disappears. I have been searching for a long time on how to fix this but cannot figure it out.

 

The full program I am using is below. This program can be copied into visual studio and compiled, make sure the character set is set to "Use Multi-Byte". Any help would be greatly appreciated. Thanks.

// Program to allow a user to type into a window

#define WIN32_LEAN_AND_MEAN
#define BUFSIZE 65535 
#define SHIFTED 0x8000 

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <Strsafe.h>

// Function prototypes
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
bool CreateMainWindow(HINSTANCE, int);
LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);

// Global variables
HINSTANCE hInst;
HDC hdc;                          // device context  
RECT rect;					// output rectangle for DrawText
PAINTSTRUCT ps;                   // client area paint info 

// Constants
static TCHAR CLASS_NAME[] = _T("win32app");
static TCHAR APP_TITLE[] = _T("Win32 Guided Tour Application");	// title bar text
const int WINDOW_WIDTH = 400;									// width of window
const int WINDOW_HEIGHT = 400;									// height of window

#define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x) 

//=============================================================================
// Application entry point
//=============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;

	// Create the window
	if (!CreateMainWindow(hInstance, nCmdShow))
		return false;

	// Main message loop
	int done = 0;
	while (!done)
	{
		// Look for quit message
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				done = 1;

			// Decode and pass messages on to WndProc
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	return (int)msg.wParam;
}

//=============================================================================
// Window event callback function
//=============================================================================
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

	HBITMAP hCaret;                   // caret bitmap 

	static char *pTextMatrix = nullptr;  // points to text matrix 
	static int  nCharX,               // width of char. in logical units 
		nCharY,               // height of char. in logical units 
		nWindowX,             // width of client area 
		nWindowY,             // height of client area 
		nWindowCharsX,        // width of client area 
		nWindowCharsY,        // height of client area 
		nCaretPosX,           // x-position of caret 
		nCaretPosY;           // y-position of caret 
	static UINT uOldBlink;            // previous blink rate 
	int x, y;                         // coordinates for text matrix 
	TEXTMETRIC tm;                    // font information 

	switch (msg)
	{
	case WM_CREATE:
		// Select a fixed-width system font, and get its text metrics.

		hdc = GetDC(hwnd);
		SelectObject(hdc,
			GetStockObject(SYSTEM_FIXED_FONT));
		GetTextMetrics(hdc, &tm);
		ReleaseDC(hwnd, hdc);

		// Save the avg. width and height of characters. 

		nCharX = tm.tmAveCharWidth;
		nCharY = tm.tmHeight;

		return 0;

	case WM_SIZE:
		// Determine the width of the client area, in pixels 
		// and in number of characters. 

		nWindowX = LOWORD(lParam);
		nWindowCharsX = max(1, nWindowX / nCharX);

		// Determine the height of the client area, in 
		// pixels and in number of characters. 

		nWindowY = HIWORD(lParam);
		nWindowCharsY = max(1, nWindowY / nCharY);

		// Clear the buffer that holds the text input. 

		if (pTextMatrix != NULL)
			free(pTextMatrix);

		// If there is enough memory, allocate space for the 
		// text input buffer. 

		pTextMatrix = (char*)malloc(nWindowCharsX * nWindowCharsY);

		if (pTextMatrix == NULL)
			//ErrorHandler("Not enough memory.");
			break;
		else
		for (y = 0; y < nWindowCharsY; y++)
		for (x = 0; x < nWindowCharsX; x++)
			TEXTMATRIX(x, y) = ' ';

		// Move the caret to the origin. 

		SetCaretPos(0, 0);

		return 0;

	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_HOME:       // Home 
			nCaretPosX = 0;
			break;

		case VK_END:        // End 
			nCaretPosX = nWindowCharsX - 1;
			break;

		case VK_PRIOR:      // Page Up 
			nCaretPosY = 0;
			break;

		case VK_NEXT:       // Page Down 
			nCaretPosY = nWindowCharsY - 1;
			break;

		case VK_LEFT:       // Left arrow 
			nCaretPosX = max(nCaretPosX - 1, 0);
			break;

		case VK_RIGHT:      // Right arrow 
			nCaretPosX = min(nCaretPosX + 1, nWindowCharsX - 1);
			break;

		case VK_UP:         // Up arrow 
			nCaretPosY = max(nCaretPosY - 1, 0);
			break;

		case VK_DOWN:       // Down arrow 
			nCaretPosY = min(nCaretPosY + 1, nWindowCharsY - 1);
			break;

		case VK_DELETE:     // Delete 

			// Move all the characters that followed the 
			// deleted character (on the same line) one 
			// space back (to the left) in the matrix. 

			for (x = nCaretPosX; x < nWindowCharsX; x++)
				TEXTMATRIX(x, nCaretPosY) = TEXTMATRIX(x + 1, nCaretPosY);

			// Replace the last character on the 
			// line with a space. 

			TEXTMATRIX(nWindowCharsX - 1, nCaretPosY) = ' ';

			// The application will draw outside the 
			// WM_PAINT message processing, so hide the caret. 

			HideCaret(hwnd);

			// Redraw the line, adjusted for the 
			// deleted character. 

			hdc = GetDC(hwnd);
			SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

			TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), nWindowCharsX - nCaretPosX);

			ReleaseDC(hwnd, hdc);

			// Display the caret. 

			ShowCaret(hwnd);

			break;
		}

		// Adjust the caret position based on the 
		// virtual-key processing. 

		SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY);

		return 0;

	case WM_CHAR:
		switch (wParam)
		{
		case 0x08:          // Backspace 
			// Move the caret back one space, and then 
			// process this like the DEL key. 

			if (nCaretPosX > 0)
			{
				nCaretPosX--;
				SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1L);
			}
			break;

		case 0x09:          // Tab 
			// Tab stops exist every four spaces, so add 
			// spaces until the user hits the next tab. 

			do
			{
				SendMessage(hwnd, WM_CHAR, ' ', 1L);
			} while (nCaretPosX % 4 != 0);
			break;

		case 0x0D:          // Carriage return 
			// Go to the beginning of the next line. 
			// The bottom line wraps around to the top. 

			nCaretPosX = 0;

			if (++nCaretPosY == nWindowCharsY)
				nCaretPosY = 0;
			break;

		case 0x1B:        // Escape 
		case 0x0A:        // Linefeed 
			MessageBeep((UINT)-1);
			break;

		default:
			// Add the character to the text buffer. 

			TEXTMATRIX(nCaretPosX, nCaretPosY) = (char)wParam;

			// The application will draw outside the 
			// WM_PAINT message processing, so hide the caret. 

			HideCaret(hwnd);

			// Draw the character on the screen. 

			hdc = GetDC(hwnd);
			SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

			TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), 1);
			InvalidateRect(hwnd, NULL, TRUE);
			ReleaseDC(hwnd, hdc);

			// Display the caret. 

			ShowCaret(hwnd);

			// Prepare to wrap around if you reached the 
			// end of the line. 

			if (++nCaretPosX == nWindowCharsX)
			{
				nCaretPosX = 0;
				if (++nCaretPosY == nWindowCharsY)
					nCaretPosY = 0;
			}
			InvalidateRect(hwnd, NULL, TRUE);
			break;
		}

		// Adjust the caret position based on the 
		// character processing. 

		SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY);

		return 0;

	case WM_PAINT:
		// Draw all the characters in the buffer, line by line. 

		hdc = BeginPaint(hwnd, &ps);

		SelectObject(hdc,
			GetStockObject(SYSTEM_FIXED_FONT));

		for (y = 0; y < nWindowCharsY; y++)
			TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y),
			nWindowCharsX);

		EndPaint(hwnd, &ps);

	case WM_SETFOCUS:
		// The window has the input focus. Load the 
		// application-defined caret resource. 

		hCaret = LoadBitmap(hInst, MAKEINTRESOURCE(120));

		// Create the caret. 

		//CreateCaret(hwnd, hCaret, 0, 0);
		CreateCaret(hwnd, (HBITMAP)NULL, 2, nCharY);

		// Adjust the caret position. 

		SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY);

		// Display the caret. 

		ShowCaret(hwnd);

		break;

	case WM_KILLFOCUS:
		// The window is losing the input focus, 
		// so destroy the caret. 

		DestroyCaret();

		break;

	case WM_DESTROY:
		PostQuitMessage(0);

		// Free the input buffer

		GlobalFree((HGLOBAL)pTextMatrix);
		UnregisterHotKey(hwnd, 0xAAAA);

		break;

	default:
		return DefWindowProc(hwnd, msg, wParam, lParam);

	}

	return NULL;
}


bool CreateMainWindow(HINSTANCE hInstance, int nCmdShow)
{
	WNDCLASSEX wcex;
	HWND hwnd;

	// Fill in the window class structure with parameters that describe the main window
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = CLASS_NAME;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

	// Register the window class. 
	// RegisterClassEx returns 0 on error.
	if (!RegisterClassEx(&wcex))
	{
		MessageBox(NULL,
			_T("Call to RegisterClassEx failed!"),
			_T("Win32 Guided Tour"),
			NULL);

		return 1;
	}

	//hInst = hInstance; // Store instance handle in our global variable

	// Create window
	hwnd = CreateWindow(
		CLASS_NAME,
		APP_TITLE,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		CW_USEDEFAULT,
		WINDOW_WIDTH,
		WINDOW_HEIGHT,
		NULL,
		NULL,
		hInstance,
		NULL
		);

	if (!hwnd)
	{
		MessageBox(NULL,
			_T("Call to CreateWindow failed!"),
			_T("Win32 Guided Tour"),
			NULL);

		return false;
	}

	// The parameters to ShowWindow explained:
	// hwnd: the value returned from CreateWindow
	// nCmdShow: the fourth parameter from WinMain
	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	return true;
}

Understanding the purpose of a code snippet from Diredt3D tutorial, and some terminology

11 October 2014 - 10:56 AM

I am learning how to implement graphics using DirectX 11 using the following tutorial series:

 

https://code.msdn.microsoft.com/Direct3D-Tutorial-Win32-829979ef

 

I cannot for the life of me understand what this portion of code is doing (Tutorial01.cpp):

    // Obtain DXGI factory from device (since we used nullptr for pAdapter above)
    IDXGIFactory1* dxgiFactory = nullptr;
    {
        IDXGIDevice* dxgiDevice = nullptr;
        hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );
        if (SUCCEEDED(hr))
        {
            IDXGIAdapter* adapter = nullptr;
            hr = dxgiDevice->GetAdapter(&adapter);
            if (SUCCEEDED(hr))
            {
                hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );
                adapter->Release();
            }
            dxgiDevice->Release();
        }
    }
    if (FAILED(hr))
        return hr;

    // Create swap chain
    IDXGIFactory2* dxgiFactory2 = nullptr;
    hr = dxgiFactory->QueryInterface( __uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2) );
    if ( dxgiFactory2 )
    {
        // DirectX 11.1 or later
        hr = g_pd3dDevice->QueryInterface( __uuidof(ID3D11Device1), reinterpret_cast<void**>(&g_pd3dDevice1) );
        if (SUCCEEDED(hr))
        {
            (void) g_pImmediateContext->QueryInterface( __uuidof(ID3D11DeviceContext1), reinterpret_cast<void**>(&g_pImmediateContext1) );
        }

        DXGI_SWAP_CHAIN_DESC1 sd;
        ZeroMemory(&sd, sizeof(sd));
        sd.Width = width;
        sd.Height = height;
        sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.BufferCount = 1;

        hr = dxgiFactory2->CreateSwapChainForHwnd( g_pd3dDevice, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1 );
        if (SUCCEEDED(hr))
        {
            hr = g_pSwapChain1->QueryInterface( __uuidof(IDXGISwapChain), reinterpret_cast<void**>(&g_pSwapChain) );
        }

        dxgiFactory2->Release();
    }
    else
    {
        // DirectX 11.0 systems
        DXGI_SWAP_CHAIN_DESC sd;
        ZeroMemory(&sd, sizeof(sd));
        sd.BufferCount = 1;
        sd.BufferDesc.Width = width;
        sd.BufferDesc.Height = height;
        sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        sd.BufferDesc.RefreshRate.Numerator = 60;
        sd.BufferDesc.RefreshRate.Denominator = 1;
        sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        sd.OutputWindow = g_hWnd;
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
        sd.Windowed = TRUE;

        hr = dxgiFactory->CreateSwapChain( g_pd3dDevice, &sd, &g_pSwapChain );
    }

    dxgiFactory->Release();

I would be grateful if you could bear with me through my thought process, and clear up some of my confusions.

 

They start by defining

    IDXGIFactory1* dxgiFactory = nullptr;

so I jump on the msdn to read about IDXGIFactory1...

"The IDXGIFactory1 interface implements methods for generating DXGI objects."

okay, so what exactly is this DXGI they talk about?

"Microsoft DirectX Graphics Infrastructure (DXGI) handles enumerating graphics adapters, enumerating display modes,..."

 

Question 1. What is the physical meaning of "enumerating graphics adapters", and "enumerating display modes"?

Question 2. With this in mind, what exactly are DXGI objects?

 

Then they create a...

    IDXGIDevice* dxgiDevice = nullptr;

where a IDXGIDevice is defined as:

"An IDXGIDevice interface implements a derived class for DXGI objects that produce image data."

 

Question 3. Can someone please explain why this dxgiDevice is added now? What is its purpose? Why is it useful? Why do we WANT it?

 

continuing... the next line of code:

    hr = g_pd3dDevice->QueryInterface( __uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice) );

 

I read what all of the functions do on the msdn, but it just isn't coming together... the msdn states that what we get from this line of code is:

The address of a pointer variable that receives the interface pointer requested in the riid parameter. Upon successful return, *ppvObject contains the requested interface pointer to the object.

 

Question 4. Why are we doing this? What is this actually doing or looking at physically (as in terms of computer hardware...?)

 

continuing... if this function successfully gets this interface pointer...

    IDXGIAdapter* adapter = nullptr;

arrrghh... another one. To the msdn!

The IDXGIAdapter interface represents a display sub-system (including one or more GPU's, DACs and video memory).

okay, that seems a bit more self explanatory. I can now understand this as an actual physical object residing somewhere on or in the computer.

 

    hr = dxgiDevice->GetAdapter(&adapter);

 

This gives us "The address of an IDXGIAdapter interface pointer to the adapter."

 

Question 5. Again what does this actually mean? Is it something like the location on the motherboard that the compiler can use to talk to the graphics adapter? The "hardware address" of the GPU?

 

continuing...

 

    if (SUCCEEDED(hr))
    {
        hr = adapter->GetParent( __uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory) );

        adapter->Release();
    }
    dxgiDevice->Release();

 

Question 6. This GetParent seems to be the ultimate goal of this entire operation. What is its purpose? Why do we want it? What have we ultimately done with all of this code? And why, after its all done, do we just call Release()?

 

Then, I wont do the same breakdown, but the similar set of code happens this time with a

    IDXGIFactory2* dxgiFactory2 = nullptr;

 

and starting to fill out the DXGI_SWAP_CHAIN_DESC1, or a DXGI_SWAP_CHAIN_DESC if they don't retrieve a dxgiFactory2??

 

Question 7. With my previous questions in mind, can you please wrap up in a nutshell what the full code is doing? Please whenever possible don't use terms like device or interface, because they are plastered all over the msdn, and while I am happy to read it and memorize it, I really have no idea what any of it means to the actual computer...

 

Thank you tremendously for your time.


Questions on first Win32 windows application

04 October 2014 - 06:34 AM

I learning how to program win32 applications, and starting with the "Hello World" version found on the MSDN:

 

http://msdn.microsoft.com/en-us/library/bb384843.aspx

 

I have some questions based on their code:

 

1. They have their windows class name as

static TCHAR szWindowClass[] = _T("win32app");

Why would you make it a TCHAR instead of something like:

const char szWindowClass[]  = "win32app";

I have also seen:

wchar_t szWindowClass[] = L"win32app";

This prefix L and _T is confusing to me. Why would you use one of these methods over the other? In modern c++ programming which is the 'best' one to use?

 

 

2. They have this line of code in the full code:

hInst = hInstance; // Store instance handle in our global variable

I noticed you can comment it out and it does not affect the program. In fact, they do not use hInst after this is written, so what is its purpose?

 

 

3. They have this line:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

but I have also seen the same sort of line written as WinProc instead of WndProc. I cant find much information on WinProc. What is the difference?

 

 

4. In their callback they have this code:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    TCHAR greeting[] = _T("Hello, World!");

    switch (message)
    {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        break;
    }

    return 0;
}

I am confused as to a few things.

 

- The program itself just writes "Hello World", but how does it know which "case" to take.

 

- In this particular program there is no input you can do except close or minimize the window, so as the program is running, what is exactly  the default value of "message"?

 

- Does clicking on the red X mean that case "WM_DESTORY" has been selected?

 

 

5. I was playing around with some of the code to change the background color and altered this line:

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

. I changed COLOR_WINDOW + 1 to COLOR_WINDOW + 240. In this case the window does not show and the call "Call to RegisterClassEx failed!" pops up. I ran the code a few times and then changed it back to + 1. When you save it and run it you get an error from VS2013 saying:

"cannot open HelloWorldApp.exe for writing", and when I check task manager I can see a couple of "HelloWorldApp.exe" sitting there. You need to end task them all to make the program compile again. So I guess the code does not properly handle a failed run apart from the message box.

  • In this case how would you properly shut the program down and release the memory?

 

Thank you for your time.


What field is 'making computers play games designed for humans'

06 September 2014 - 11:47 AM

I am a big fan of chess, and more specifically computer chess. I love firing up deep shredder and 2 of my favorite engines and watching them go at it at... but anyway

 

I would like to learn more about using computers to "use software designed for humans". What field is this? I think maybe A.I, but then again isn't A.I for entities In a game, I think this is maybe a more encompassing field.. neural networks? Are there any suggested resources for learning about this, focused on making computers play video games designed for humans? And not just for computer chess, which can have an A.I opponent anyway, but for single-player games whereby the computer takes over the character that the human is meant to play like this:

 

https://www.youtube.com/watch?v=DlkMs4ZHHr8

 

I am quite new to c++ but aiming to make a very simple vertical scrolling shooter inspired by raptor: call of the shadows https://www.youtube.com/watch?v=pYa2g9_5Ss4&t=1m05s

 

I would then like to program a computer to play as the aeroplane, but playing obviously much better than a human due the the computers superhuman calculation abilities and precision. I am wondering how this can be done two ways:

 

1. With the source code (since I will make the game I will have it)
2. Without the source code. Is it even possible to make a computer play it if you dont have the source code?

 

Thanks


PARTNERS