/*
Copyright (C) 2010, Heikki Salo
All rights reserved.
Distributed under the BSD license:
http://www.opensource.org/licenses/bsd-license.php
*/
#include "stdafx.h"
#include <Commdlg.h>
#include "DPUtils.hpp"
#include "DPDevice.hpp"
#include "DPTexture.hpp"
#include "DPWindow.hpp"
#include "DPVector.hpp"
int messageBox(DPWindow* window, const char* text, const char* title, UINT type)
{
HWND parent = window ? window->getHandle() : 0;
return MessageBoxA(parent, text, title, type);
}
python::object fileDialog(const char* titleName)
{
char nameBuffer[1024];
OPENFILENAMEA fileName;
ZeroMemory(&fileName, sizeof(fileName));
fileName.lStructSize = sizeof(fileName);
fileName.hwndOwner = 0;
fileName.lpstrFile = nameBuffer;
fileName.lpstrFile[0] = '\0';
fileName.nMaxFile = sizeof(nameBuffer);
fileName.lpstrFilter = 0; //"All\0*.*\0Text\0*.TXT\0";
fileName.nFilterIndex = 0; //1;
fileName.lpstrFileTitle = NULL;
fileName.nMaxFileTitle = 0;
fileName.lpstrInitialDir = NULL;
fileName.lpstrTitle = titleName;
fileName.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR; // | OFN_ALLOWMULTISELECT;
if (GetOpenFileNameA(&fileName) == 0)
return python::object(); //Nothing was selected or an error occurred.
const char* resultName = fileName.lpstrFile;
return python::str(resultName);
}
/*
void drawThemed(DPTexture& texture, HDC hdc, python::dict& mapping)
{
HTHEME theme = OpenThemeData(0, L"");
if (theme == 0) {
DPThrow("Can't open a theme.")
}
CloseThemeData(theme);
}*/
python::dict writeChars(DPTexture& texture, HDC hdc, pyunicode& chars)
{
D3D11_TEXTURE2D_DESC desc;
texture.getTexture()->GetDesc(&desc);
//For line drawing.
if (SetPixel(hdc, 0, 0, RGB(255, 255, 255)) != 0x00ffffff) {
//Not a disaster, but things might look funny.
DPWarn("Wrong color from SetPixel()");
}
const int padding = 1;
UINT x = padding;
UINT y = padding + 2; //Space for the white dot.
python::dict mapping;
for (UINT i=0; i < chars.size(); ++i) {
SIZE charSize;
if (GetTextExtentPoint32(hdc, &chars[i], 1, &charSize) == 0) {
DPThrow("Can't get character size");
}
//charSize.cx += 1;
if (x + charSize.cx >= desc.Width) {
//x overflows, move to the next line.
x = padding;
y += charSize.cy + padding;
}
if (y + charSize.cy >= desc.Height) {
//y overflows.
DPThrow("Texture is too small for all characters");
}
RECT area = {x, y, x + charSize.cx, y + charSize.cy};
if (DrawText(hdc, &chars[i], 1, &area, DT_LEFT | DT_TOP | DT_NOPREFIX | DT_SINGLELINE) == 0)
DPThrow("Can't draw a character");
UINT texWidth = desc.Width;
UINT texHeight = desc.Height;
float texx = float(x) / (texWidth);
float texy = float(y) / (texHeight);
float texx2 = float(x + charSize.cx) / (texWidth);
float texy2 = float(y + charSize.cy) / (texHeight);
python::object keyval(python::handle<>(PyUnicode_FromUnicode(&chars[i], 1)));
mapping[keyval] = python::make_tuple(
x, y, charSize.cx, charSize.cy,
texx, texy, texx2, texy2);
x += charSize.cx + padding;
}
return mapping;
}
python::object _initFont(DPTexture& texture, python::str& fontArg, int fontSize, int weight,
UINT quality, UINT charSet, python::object& textArg)
{
pyunicode fontName = fontArg;
pyunicode text = textArg;
scoped_object<IDXGISurface1*> surface;
TestHR(texture.getTexture()->QueryInterface<IDXGISurface1>(&surface));
DWORD italic = FALSE;
DWORD underline = FALSE;
DWORD strikeOut = FALSE;
scoped_object<HFONT> hfont = CreateFont(-fontSize, 0, 0, 0, weight, italic, underline,
strikeOut, charSet, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,
quality, VARIABLE_PITCH, fontName.c_str());
if (hfont == 0)
DPThrow("Can't create a font");
HDC hdc;
TestHR(surface->GetDC(FALSE, &hdc));
HGDIOBJ oldFont = SelectObject(hdc, hfont); //Set new.
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(255, 255, 255));
//SetTextCharacterExtra(hdc, 1);
python::object mapping;
try {
mapping = writeChars(texture, hdc, text);
}
catch (...) {
SelectObject(hdc, oldFont); //Restore.
surface->ReleaseDC(0);
throw;
}
SelectObject(hdc, oldFont); //Restore.
TestHR(surface->ReleaseDC(0));
return mapping;
}
//See DPDevice::getAdapterAtIndex() for comparison.
python::list enumAdapters()
{
scoped_object<IDXGIFactory*> factory;
TestHR(CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&factory)));
python::list results;
IDXGIAdapter* adapter = 0;
UINT i = 0;
while (factory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC desc;
HRESULT hr = adapter->GetDesc(&desc);
adapter->Release();
TestHR(hr);
python::object name(python::handle<>(PyUnicode_FromUnicode(
desc.Description, wcslen(desc.Description) )));
results.append(python::make_tuple(name, desc.VendorId, desc.DeviceId,
desc.SubSysId, desc.Revision, desc.DedicatedVideoMemory, desc.DedicatedSystemMemory,
desc.SharedSystemMemory));
++i;
}
return results;
}
bool isKeyDown(int vk)
{
return GetAsyncKeyState(vk) & 0x8000;
}
void setCursorPos(int x, int y)
{
if (SetCursorPos(x, y) == 0)
DPThrow("Can't set cursor position");
}
python::object getCursorPos()
{
POINT point;
if (GetCursorPos(&point) == 0)
DPThrow("Can't get cursor position");
return python::make_tuple(point.x, point.y);
}
python::object getClipboardData(UINT format)
{
if (OpenClipboard(0) == 0)
DPThrow("Can't open the clipboard");
PyObject* value = 0;
if (IsClipboardFormatAvailable(format)) {
HANDLE data = GetClipboardData(format);
if (data) {
void* pointer = GlobalLock(data);
if (format == CF_UNICODETEXT) {
WCHAR* text = (WCHAR*)pointer;
value = PyUnicode_FromWideChar(text, wcslen(text));
}
GlobalUnlock(data);
}
}
CloseClipboard();
if (PyErr_Occurred())
python::throw_error_already_set();
if (value == 0)
return python::object();
return python::object(python::handle<>(value));
}
void setClipboardData(python::object& data, UINT format)
{
pyunicode textdata = data;
if (OpenClipboard(0) == 0)
DPThrow("Can't open the clipboard");
EmptyClipboard();
HGLOBAL handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(WCHAR) * (textdata.size() + 1));
if (handle) {
WCHAR* globaltext = (WCHAR*)GlobalLock(handle);
memcpy(globaltext, textdata.c_str(), sizeof(WCHAR) * textdata.size());
globaltext[textdata.size()] = 0; //NULL terminator.
GlobalUnlock(handle);
SetClipboardData(format, handle);
}
CloseClipboard();
}
/*
DPAtExit() is called after Py_Finalize() (if Py_AtExit() worked).
*/
extern void DPCloseMedia();
extern "C"
void DPAtExit()
{
DPCloseMedia();
}
extern void ExportDPDevice();
extern void ExportDPBuffer();
extern void ExportDPTexture();
extern void ExportDPView();
extern void ExportDPWindow();
extern void ExportDPEffect();
extern void ExportDPMatrix();
extern void ExportDPVector();
extern void ExportDPInputLayout();
extern void ExportDPDeviceState();
extern void ExportDPMedia();
//DirectPython exception class.
PyObject* dpExeception = 0;
BOOST_PYTHON_MODULE(d3d11)
{
#if defined(_DEBUG)
/* When debugging enable memory leak checking. It
is normal that some amount of memory is not
freed.
*/
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
//The handle leaks. It's ok when debugging.
HANDLE logFile = CreateFile(L"memoryleaks.log", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if (logFile == INVALID_HANDLE_VALUE) {
DPWarn("Can't create a memory log file");
}
else {
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_WARN, logFile);
}
#endif
using namespace boost::python;
//The exception class is never released.
dpExeception = PyErr_NewException("d3d11.Error", PyExc_RuntimeError, 0);
if (dpExeception == 0)
python::throw_error_already_set();
scope().attr("Error") = python::object(python::borrowed<>(dpExeception));
def("enumAdapters", enumAdapters);
def("messageBox", messageBox);
def("fileDialog", fileDialog);
def("isKeyDown", &isKeyDown);
def("_initFont", _initFont);
def("enableDebug", DPEnableDebug);
def("setCursorPos", setCursorPos);
def("getCursorPos", getCursorPos);
def("getClipboardData", getClipboardData, (arg("format") = CF_UNICODETEXT));
def("setClipboardData", setClipboardData, (arg("data"), arg("format") = CF_UNICODETEXT));
ExportDPWindow();
ExportDPDevice();
ExportDPEffect();
ExportDPBuffer();
ExportDPTexture();
ExportDPInputLayout();
ExportDPView();
ExportDPMatrix();
ExportDPVector();
ExportDPDeviceState();
ExportDPMedia();
//Header versions.
scope().attr("D3D11_SDK_VERSION") = D3D11_SDK_VERSION;
scope().attr("D3DX11_SDK_VERSION") = D3DX11_SDK_VERSION;
scope().attr("D3DX11_DLL") = D3DX11_DLL_A;
scope().attr("DP_VERSION") = make_tuple(DPVERISONMAJOR, DPVERSIONMINOR, DPVERSIONMICRO);
scope().attr("PY_VERSION") = make_tuple(PY_MAJOR_VERSION, PY_MINOR_VERSION, PY_MICRO_VERSION);
if (FAILED(D3DX11CheckVersion(D3D11_SDK_VERSION, D3DX11_SDK_VERSION)))
DPWarn("D3D11/D3D11X version mismatch");
Py_AtExit(&DPAtExit);
}