ĐĎॹá>ţ˙  ÓÝţ˙˙˙ÉĘËĚÍÎĎĐŃŇýy˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ěĽÁM řżĄbjbjâ=â= Í= €W€W’˜đ˙˙˙˙˙˙lNNNNžžž¤BHHHX\´\B¸Ę 0LpźźŇ‘Š-t1<َĽˇĽˇĽˇĽˇĽˇĽˇĘš ęťLĽˇžË3CN‘Ë3Ë3ĽˇçžNNźŇqşˇçžçžçžË3|6N8źžŇَçžË3َçžBçž)Łâłľ¤†žَŇ  °_ŠřđĹBHGj1WśَС0¸mś66źכ6źَçžBBNNNNŮ PT-Dev User manual v1.03  TOC \o "1-2" \h \z  HYPERLINK \l "_Toc118801931" Introduction  PAGEREF _Toc118801931 \h 3  HYPERLINK \l "_Toc118801932" Specification & System requirements  PAGEREF _Toc118801932 \h 4  HYPERLINK \l "_Toc118801933" Installation  PAGEREF _Toc118801933 \h 5  HYPERLINK \l "_Toc118801934" Program examples  PAGEREF _Toc118801934 \h 6  HYPERLINK \l "_Toc118801935" Integrating PT-Dev with your projects  PAGEREF _Toc118801935 \h 7  HYPERLINK \l "_Toc118801936" Starting a new project using PTDevApp  PAGEREF _Toc118801936 \h 7  HYPERLINK \l "_Toc118801937" Setting up for use under EVC3/EVC4/VC6  PAGEREF _Toc118801937 \h 8  HYPERLINK \l "_Toc118801938" Setting up for use under VS2005  PAGEREF _Toc118801938 \h 13  HYPERLINK \l "_Toc118801939" Classes  PAGEREF _Toc118801939 \h 20  HYPERLINK \l "_Toc118801940" PTDevApp (An application class)  PAGEREF _Toc118801940 \h 20  HYPERLINK \l "_Toc118801941" PTDev  PAGEREF _Toc118801941 \h 20  HYPERLINK \l "_Toc118801942" PTMath  PAGEREF _Toc118801942 \h 20  HYPERLINK \l "_Toc118801943" PTDevDisplay  PAGEREF _Toc118801943 \h 20  HYPERLINK \l "_Toc118801944" PTDevInput  PAGEREF _Toc118801944 \h 20  HYPERLINK \l "_Toc118801945" PTDevTimer  PAGEREF _Toc118801945 \h 20  HYPERLINK \l "_Toc118801946" PTDevSurface  PAGEREF _Toc118801946 \h 20  HYPERLINK \l "_Toc118801947" PTDevMaskSurface : PTDevSurface  PAGEREF _Toc118801947 \h 20  HYPERLINK \l "_Toc118801948" PTDevFontSurface : PTDevSurface  PAGEREF _Toc118801948 \h 20  HYPERLINK \l "_Toc118801949" PTDevSpriteSurface : PTDevSurface  PAGEREF _Toc118801949 \h 20  HYPERLINK \l "_Toc118801950" PTDevSprite  PAGEREF _Toc118801950 \h 20  HYPERLINK \l "_Toc118801951" PTDevAnimation  PAGEREF _Toc118801951 \h 20  HYPERLINK \l "_Toc118801952" PTDevAnimated  PAGEREF _Toc118801952 \h 20  HYPERLINK \l "_Toc118801953" PTDevSound  PAGEREF _Toc118801953 \h 20  HYPERLINK \l "_Toc118801954" PTDevApp  PAGEREF _Toc118801954 \h 21  HYPERLINK \l "_Toc118801955" PTDevApp Virtual Functions  PAGEREF _Toc118801955 \h 22  HYPERLINK \l "_Toc118801956" PTDev  PAGEREF _Toc118801956 \h 26  HYPERLINK \l "_Toc118801957" PTMath  PAGEREF _Toc118801957 \h 26  HYPERLINK \l "_Toc118801958" PTDevDisplay  PAGEREF _Toc118801958 \h 27  HYPERLINK \l "_Toc118801959" PTDevInput  PAGEREF _Toc118801959 \h 30  HYPERLINK \l "_Toc118801960" PTDevTimer  PAGEREF _Toc118801960 \h 32  HYPERLINK \l "_Toc118801961" PTDevSurface  PAGEREF _Toc118801961 \h 34  HYPERLINK \l "_Toc118801962" PTDevMaskSurface : PTDevSurface  PAGEREF _Toc118801962 \h 49  HYPERLINK \l "_Toc118801963" PTDevFontSurface : PTDevSurface  PAGEREF _Toc118801963 \h 57  HYPERLINK \l "_Toc118801964" PTDevSpriteSurface : PTDevSurface  PAGEREF _Toc118801964 \h 59  HYPERLINK \l "_Toc118801965" PTDevAnimation  PAGEREF _Toc118801965 \h 65  HYPERLINK \l "_Toc118801966" PTDevAnimated  PAGEREF _Toc118801966 \h 65  HYPERLINK \l "_Toc118801967" PTDevSound  PAGEREF _Toc118801967 \h 65  HYPERLINK \l "_Toc118801968" Data structures and definitions  PAGEREF _Toc118801968 \h 80  HYPERLINK \l "_Toc118801969" Error codes/warnings/returns  PAGEREF _Toc118801969 \h 80  HYPERLINK \l "_Toc118801970" Blit/Draw flags  PAGEREF _Toc118801970 \h 82  HYPERLINK \l "_Toc118801971" Methods for mask surface collision drawing/testing.  PAGEREF _Toc118801971 \h 82  HYPERLINK \l "_Toc118801972" Drawtext() special codes (char)  PAGEREF _Toc118801972 \h 83  HYPERLINK \l "_Toc118801973" Blit FX types  PAGEREF _Toc118801973 \h 85  HYPERLINK \l "_Toc118801974" PTMath definitions  PAGEREF _Toc118801974 \h 86  HYPERLINK \l "_Toc118801975" OpenDisplay()/ChangeDisplay() flags  PAGEREF _Toc118801975 \h 86  HYPERLINK \l "_Toc118801976" CreateSurface() options  PAGEREF _Toc118801976 \h 87  HYPERLINK \l "_Toc118801977" Sound definitions  PAGEREF _Toc118801977 \h 87  HYPERLINK \l "_Toc118801978" Structures  PAGEREF _Toc118801978 \h 88  HYPERLINK \l "_Toc118801979" Support  PAGEREF _Toc118801979 \h 92  Introduction Welcome to PT-Dev, the development system for the Pocket PC, Smartphone and Symbian. This manual is for the installation and implementation of the PT-Dev system. A description of all the functions are described, some with example code to help with code construction, a “HELLO WORLD” app is included to get you started at the beginning and a fully working game (PT-Devoids) with many of the features of PT-Dev implemented is also included with source code. What has PT-Dev to offer? It was written by games programmers for games programmers and we have included features that we would like to see in a development package. Parys Technografx will be using this development system in its own product development and of course, as a result, constant improvements and additions will be made to PT-Dev. An example of designing a development package for games programmers is the inclusion of PT SOUND a 32 channel dynamic system as part of the package for a complete game construction SDK. Many of Parys Technografx team members have over 25 years experience of games programming and were developing software for the early Spectrum, Dragon, Amiga, ST and many more computer platforms. We have team members on hand to help with your technical queries and problems. Specification & System requirements PC 600-Mhz or faster processor Microsoft Windows Ž 2000 Service pack 4 or above XP Service Pack 2 or above 256 MB of RAM or more 30MB of available hard drive space CD-ROM drive (for full version) Embedded Visual C++ version 3/4 and/or Visual C++ 6.0 and/or Visual Studio 2005 Windows Mobile Pocket PC 2002 and Smartphone 2002 hardware devices Pocket PC 2002 and Smartphone 2002 emulators Windows Mobile 2003 devices and emulators Windows Mobile 2003SE devices and emulators Windows Mobile 2005 devices and emulators Note that there is currently a bug in the Windows Mobile GETRAWFRAMEBUFFER call on the ARM emulators (2003SE and 2005) – this means that at the moment PTDev will only function correctly on the ARM emulators when applications developed with PTDev are launched on the ARM emulators with the emulator display set to standard portrait mode. This does not affect PTDev applications on Windows Mobile 2003SE or 2005 devices nor does it affect the x86 emulators or any other devices. The GameAPI gx.dll, gx.lib and gx.h. PT-Dev uses “gx.dll” to access the device frame buffer on older WCE mobile devices or on newer devices when extEscape GETRAWFRAMEBUFFER is unavailable. PT-Dev uses "gx.dll" to take over control of input on all WCE mobile devices. Symbian (under development, check parystec.com for availability dates) Installation PT-Dev demo installation Once you have downloaded the latest PT-Dev demo from the Parys Technografx site (all files have been virus scanned by the latest version of Norton Antivirus) unzip the contents to a folder, for example “C:\Program Files\PT-Dev”. Find in the folder……. Docs Includes Libs PTDevSamples ReadMe.txt The examples are in their own folders inside “PTDevSamples” with subfolders for the different operating systems. To try out the examples load the appropriate workspace file into Embedded VC++ 3, Embedded VC++ 4, Visual C++ 6 or Visual Studio 2005 i.e. for PPC2002 or Smartphone2002 load the “.vcw” file into EVC++ 3, for PPC2003/2003SE or Smartphone2003/2003SE load the “.vcw” file into Embedded VC++ 4, for the PC load the “.dsw” file into VC++ 6, or load the appropriate WM2003SE or WM2005 or PC “.sln” into VS2005. Note that for software developed with PTDev you need to put an appropriate copy of “gx.dll” on the target for the mobile devices and emulators when using WM2002 or WM2003 and on emulators for EVC4 WM2003SE. In the case of Smartphone devices “gx.dll” is usually (always?) on the device already. Program examples PTDevSamples contains the folders PTDevoids and PTHello. In these folders are the folders: Common Files common to all builds PC PC build: Use Visual C++ 6 PPC2002 Pocket PC 2002 build: use Embedded 3 PPC2003 Pocket PC 2003/2003SE build: use Embedded 4 PPC2003SE Pocket PC 2003SE build: use Visual Studio 2005 PPC2005 Pocket PC 2005 build: use Visual Studio 2005 Smartphone2002 Smartphone 2002 build: use Embedded 3 Smartphone2003 Smartphone 2003/2003SE build: use Embedded 4 Smartphone2003SE Smartphone 2003SE build: use Visual Studio 2005 Smartphone2005 Smartphone 2005 build: use Visual Studio 2005 PC2005 PC build: use Visual Studio 2005 PTDevoids is a simple pseudo-3D version of asteroids and demonstrates rotation, scaling, collision testing and the FX blits available in the beta version of PTDev as well as demonstrating how to use PTDevSound. PTHello is a very simple program that just prints a message, it’s provided to give you a sample of an almost completely base-level PTDev application. Integrating PT-Dev with your projects The best way to use PTDev in your own applications is to use the supplied PTDevApp application class. If you wish to add PTDev functionality to an existing project then use the PTDevApp class as a guide to how to do this, for example it demonstrates how and when the PTDev classes should be instantiated, what functions require calling on frame update or minimise/restore and various features you may need to add to your main message loop such as using WM_CANCELMODE to catch the case of a device being switched on again after being switched off with your application running. Starting a new project using PTDevApp The process of setting up a new project to use PTDev by using the PTDevApp application class is pretty much the same no matter which target you have in mind (PPC, Smartphone or PC). The first thing to do is to set up some appropriate folders for your project, in a similar way to those set up for the supplied PTDevSamples. Create a folder inside the “PTDev\PTDevSamples” (or “PTDevBeta\PTDevSamples” or “PTDevTrial\PTDevSamples”) folder having the name of your project, for example “TestApp”. Now, inside that folder, create a folder called “common”, this is where the main source files (common to all targets) for “TestApp” should go. Inside the folder called “common” create another folder called “res”, this is where resources common to all the targets should go. Now copy either the default “PTDev.ico” icon from the “PTDevSamples\PTHello\common\res” folder into this “res” folder, or copy an icon designed for your “TestApp” into this “res” folder (if using the PTDev icon you could also change the name to say “TestApp.ico”). Back inside the “TestApp” folder itself you should then create folders to go alongside “common” for each of your desired targets – for example “PC”, “PPC2002”, “PPC2003”, “PPC2003SE, “PPC2005”, ”SP2002”, “SP2003”, “SP2003SE”, “SP2005” and “PC2005”, then copy the appropriate version of “stdafx.h” from the corresponding folder in “PTDevSamples\PTHello” into this/these folders. To set up your actual projects see the next section for EVC3/EVC4/VC6 and the following section for VS2005. Setting up for use under EVC3/EVC4/VC6 Now load EVC++ 3 for PPC2002 or SP2002, or EVC++ 4 for PPC2003/2003SE or SP2003/2003SE, or VC++ 6 for the PC and select “File:New” from the menu and a window similar to the following should appear:  If “Projects” is not selected, then select it. Now, depending on your target, click once (left button) on either “WCE Pocket PC 2002 Application” or “WCE Smartphone 2002 Application” or “WCE Pocket PC 2003 Application” or “WCE Smartphone 2003 Application” or “Win32 Application”, Then click (left) on the “Project name” text entry box and type in a name for your project, ideally this should be the name you wish the final product to be called, such as using “TestApp” for the final executable “TestApp.exe”. Now click (left) on the browse button to the right of the Location entry text box and browse to select the appropriate folder in PTDevSamples i.e. “PTDevSamples\TestApp\PPC2002” or “PTDevSamples\TestApp\SP2002” or “PTDevSamples\TestApp\PPC2003” or “PTDevSamples\TestApp\SP2003” or “PTDevSamples\TestApp\PC” Having selected the folder, now click on the Location entry text box and use the “End” key to go to the end of the location text, you will see that the MS software has tried to be helpful and added an extra folder on the end of the location using the name of your project, you do not want this so use backspace to remove it from the end of the location text. Now click on the OK button and you’ll see a window like this:  Click to select the “An empty project” option, then click on “Finish”, then on “OK” and an empty project in the location you selected will be created. Now you should be looking at a screen like this:  If you haven’t already created a common main source and header file for this project e.g. in “PTDevSamples\TestApp\common” then: Go again to the main menu and select “File:New” and this time click to select the “Files” tab if it is not selected, then click to select “C++ source file”, then click on the “File name” text entry box and type in a name for your main C++ source file, typically use the same name that you gave the project or “Main”. Now click on the browse button to the right of the Location text entry box and browse to select the “PTDevSamples\TestApp\common” folder and then click on “OK” and a blank C++ file named “TestApp.cpp” (or whatever) will be created and opened, with the result that you are viewing a blank page. Now go again to the main menu and select “File:Open” and open the file “PTDevSamples\PTHello\common\PTHello.cpp” then go to the menu again, this time selecting “Edit:Select all”, then select “Edit:copy” then close the “PTHello.cpp” file and use “Edit:Paste” to paste the text from the “PTHello.cpp” file into your blank file. Now use keys control+h to bring up the search and replace window and enter “PTHello” as the search string and “TestApp” (or whatever you wish to call your application class) as the replacement string, then click on “Replace all”. That’s taken care of your C++ source, now you need a header file for your project, so in a similar manner use “File:New” and again select the “Files” tab if it’s not selected and this time select “C/C++ Header File” then click on the “File name” text entry box and type in a name for your main header file, typically again use the same name you gave to the project or “Main”. Now click on the browse button to the right of the Location text entry box and browse to select the “PTDevSamples\TestApp\common” folder and then click on “OK” and a blank header file named “TestApp.h” (or whatever) will be created and opened, with the result that you are viewing a blank page again. Now go again to the main menu and select “File:Open” and open the file “PTDevSamples\PTHello\common\PTHello.h” then go to the menu again, this time selecting “Edit:Select all”, then select “Edit:copy” then close the “PTHello.h” file and use “Edit:Paste” to paste the text from the “PTHello.h” file into your blank file. Now use keys control+h to bring up the search and replace window and enter “PTHello” as the search string and “TestApp” (or whatever you called your application class) as the replacement string, then click on “Replace all”. If you had already created a common main source and header file for this project: In the left pane right-click on “Source Files” and select “Add files to folder” and browse to your common folder (e.g. “PTDevSamples\TestApp\common”) and select your main source file e.g. “TestApp.cpp” to add it to the source files. Then in the left pane right-click on “Header Files” and select “Add files to folder” and browse to your common folder (e.g. “PTDevSamples\TestApp\common”) and select your main header file e.g. “TestApp.h” to add it to the header files. When you’ve created/added your common main source and header files to the project: Now in the left pane right-click on “Header Files” and select “Add files to folder” and browse to your main target folder (e.g. “PTDevSamples\TestApp\PPC2002”) and select the “stdafx.h” file to add it to the header files. Then again go through the process of adding header files, this time adding “PTDevApp.cpp” and “PTDevApp.h” from the “PTDevSamples\common” folder and ALL the header files from “PTDev\includes” (or “PTDevBeta\includes” or “PTDevTrial\includes”). Now you have both a main source file and required header files but no resources so the next thing to do is add a resource script to your project. From the main menu options choose “File:New” and then again click on the “Files” tab if it’s not already selected, then click on “Resource Script” and then on the File name text entry box and type in a name for your resource script – again typically use the name you gave to the project. Now click OK and the main right pane will change to show you the resource script you have created, just close this window for now. You will also see that there are now three choices for the left pane, the new choice being “ResourceView”. Click on “Resource View” then click on “TestApp Resources” at the top with the right mouse button and from the menu that pops up click on “Import” then browse to select the icon for your project that you put in “PTDevSamples\TestApp\common\res” and you should end up with a screen like this:  Now close the right pane then click on “IDI_ICON1” with the right mouse button and select properties from the menu then modify “IDI_ICON1” to “IDI_APP” then click on the File name entry box and add “..\common\res\” to the beginning of the filename (without the quotes). You should end up with an Icon Properties box looking something like this:  Now press return to accept the changes to the resource icon then press control+s to save the resources. Now change the left pane back to “FileView”, right-click on “Header Files” and select “Add files to folder” and (if not there already) browse to “PTDevSamples\TestApp\PPC2002” (or the appropriate folder for the current target) and you should see that a “resource.h” file has been created, choose this file so that it is added to the “Header Files”. Now you have all the necessary source files to create an application and need to tell the MS software how to build it. To do this first click on “TestApp files” in the left pane, then from the main menu select “Project:Settings” and then above the left-pane in the window that pops up change the “Settings for” option so it says “All Configurations”. Now in the right pane click the “C/C++” tab at the top then change the “Category” option to “Preprocessor” and then click in the “Additional include directories” textbox and paste the following text in the box “.,..\common,..\..\common,..\..\..\includes” (without the quotes). Now click on the “Link” tab at the top and then change the Category option to “Input” and then: if the target is PPC or Smartphone paste the following at the end of the Object/library modules text “ imgdecmp.lib gx.lib ptdev.lib” (excluding the quotes); if the target is the PC then paste the following at the end of the Object/library modules text “ winmm.lib ptdev.lib” (excluding the quotes). Now click on the Additional library path text box and then (without the quotes): if the target is PPC2002 then paste in “..\..\..\libs\ppc2002\arm”; if the target is PPC2003/2003SE then paste in “..\..\..\libs\ppc2003\arm”; if the target is Smartphone2002 then paste in “..\..\..\libs\sp2002\arm”; if the target is Smartphone2003/2003SE then paste in “..\..\..\libs\sp2003\arm; if the target is PC then paste in “..\..\..\libs\pc”. Now if the target is Smartphone or PPC then change the Settings For option above the left pane to the x86 debug (emulator) option and edit the Additional library path text changing the “arm” to “X86em” then change the Settings For option to the x86 release (emulator) option and again edit the Additional library path text changing the “arm” to “X86em”. Now click on “OK” and you should be ready to build your new application but I recommend saving the workspace first. From this point, to get to know how to use PTDev, it’s best to study the PTDevoids sample source. Setting up for use under VS2005 Load Visual Studio 2005 and select “File:New:Project” from the menu and a window similar to the following should appear:  In the left pane click to select either “Smart Device” for a Windows Mobile project or “Win32” for a PC project, then in the right pane click to select either “Win32 Smart Device Project” or “Win32 Project”. Now click to select the “Name” text entry box and type in the name for your project, then click on the “Browse” button to the right and browse to select the correct target folder for the project you are creating – either PPC2003SE, PPC2005, SP2003SE, SP2005 or PC2005 that you previously created in your project folder inside PTDevSamples e.g. “PTDevSamples\TestApp\PPC2005”. Now untick “Create directory for solution” then click on OK. Note that Visual Studio 2005 creates a folder using your project name inside the target folder even if you untick “Create directory for solution”, for example it may create “PTDevSamples\TestApp\PPC2005\TestApp”, this help assumes that this folder is where the project files will go. In the next window that appears click on the “Next” button and you’ll see a window like this (unless your target is a PC in which case skip to the next window):  Use the transport buttons in the center to select the correct SDK for your project target, i.e. a 2003 option for WM2003SE or a WM5.0 option for 2005 devices, then click on the “Next” button and you should see a window like this:  Here click to choose “Windows application” and “Empty project” as shown above, then click on “Finish” and the main window should appear as below:  If you haven’t already created a common main source and header file for this project e.g. in “PTDevSamples\TestApp\common” then: In the “Source Explorer” (left) pane click with the right mouse button on “Source Files” and from the menu select “Add:New Item”, then in the new window click to select “code” in the “Categories” (left) pane and then click to select “C++ file (.cpp)” in the “Templates” (right) pane. Now browse to the common folder you created in your project folder, e.g. “PTDevSamples\TestApp\common”, type in a name for your source file, typically use the name of the project e.g. “TestApp” or use “Main”, then click on the “Add” button and an empty file of the specified name will be created and opened. Now go again to the main menu and select “File:Open:File” and open the file “PTDevSamples\PTHello\common\PTHello.cpp” then go to the menu again, this time selecting “Edit:Select all”, then select “Edit:copy” then close the “PTHello.cpp” file and use “Edit:Paste” to paste the text from the “PTHello.cpp” file into your blank file. Now use keys control+h to bring up the search and replace window and enter “PTHello” as the find string and “TestApp” (or whatever you wish to call your application class) as the replacement string, then click on “Replace all”, click on the “OK” button in the pop-up and close the search and replace window. That’s taken care of your C++ source, now you need a header file for your project, so in the “Source Explorer” (left) pane click with the right mouse button on “Header Files” and from the menu select “Add:New Item”, then in the new window click to select “code” in the “Categories” (left) pane and then click to select “Header file (.h)” in the “Templates” (right) pane. Now browse to the common folder you created in your project folder, e.g. “PTDevSamples\TestApp\common”, type in a name for your header file, typically use the name of the project e.g. “TestApp” or use “Main”, then click on the “Add” button and an empty file of the specified name will be created and opened. Now go again to the main menu and select “File:Open:File” and open the file “PTDevSamples\PTHello\common\PTHello.h” then go to the menu again, this time selecting “Edit:Select all”, then select “Edit:copy” then close the “PTHello.h” file and use “Edit:Paste” to paste the text from the “PTHello.h” file into your blank file. Now use keys control+h to bring up the search and replace window and enter “PTHello” as the find string and “TestApp” (or whatever you called your application class) as the replacement string, then click on “Replace all”, click on the “OK” button in the pop-up and close the search and replace window. Now you’ve created a main source and header file you need to add all the necessary files to your project. If you had already created a common main source and header file for this project: In the “Solution Explorer” pane (left) use the right mouse button to click on “Source Files” and from the menu select “Add:Existing Item” then browse to select the main source file in your common folder e.g. “TestApp.cpp” in “PTDevSamples\TestApp\common”. Now in the “Solution Explorer” pane (left) use the right mouse button to click on “Header Files” and from the menu select “Add:Existing Item” then browse to select the main header file in your common folder e.g. “TestApp.h” in “PTDevSamples\TestApp\common” . When you’ve created/added your common main source and header files to the project: In the “Solution Explorer” pane (left) use the right mouse button to click on “Header Files” and from the menu select “Add:Existing Item” then browse to select “stdafx.h” from the target folder for this project e.g. “PTDevSamples\TestApp\PPC2005”. Then repeat the process of adding header files to add “PTDevApp.cpp” and “PTDevApp.h” from the “PTDevSamples\common” folder (both as header files) and then to add all the files from the “PTDev\includes” folder (or “PTDevBeta\includes” or “PTDevTrial\includes”). Now you have both a main source file and required header files but no resources so the next thing to do is add any resources to your project. In the “Solution Explorer” pane (left) use the right mouse button to click on “Resource” and from the menu select “Add:New Item”. Now in the “Categories” (left) pane click to select “Resource” and then in the “Templates” (right) pane click to select “Resource File (.rc)” then browse to your target application folder e.g. “PTDevSamples\TestApp\PPC2005\TestApp” and supply an appropriate name for your resource file e.g. “TestApp” or “Main” then click the “Add” button and you’ll see that the “Solution Explorer” pane switches to “Resource view”. Now in the “Resource view” pane click with the right mouse button on “TestApp.rc” or whatever you named your resource file, from the menu select “Add Resource…” then select “Icon” as the resource type and click the “Import” button. Now change the “Files of type” option box (at the bottom) to “Icon (.ico)”, browse to select your application icon in the common\res folder e.g. TestApp.ico in “PTDevSamples\TestApp\common\res” and you should end up looking at a screen like this:  In the “Resource view”, click the “+” to open up the “Icon” option and then click on “IDI_ICON1” with the right-mouse button and select “Properties” from the menu and a “Properties” pane should appear to the bottom-right of the VS window. Now click in the “Properties” pane to change the ID from “IDI_ICON1” to “IDI_APP”. In the “Filename” section of the properties window you’ll see that VS has used the full pathname of for the icon, e.g. “E:\PTDev\PTDevSamples\TestApp\common\res\TestApp.ico”. We do not want this so replace the leading part of the pathname, e.g. “E:\PTDev\PTDevSamples\TestApp\”, with “..\..\” (without the quotes), so that the pathname is e.g. “..\..\common\res\PTDev.ico” and when VS asks you if you wish to load the file answer “Yes”. Now press control+s to save the resources. Now you have all the necessary source files to create an application and need to tell VS how to build it. First change the left pane from “Resource view” back to “Solution explorer” then click to select the project name e.g. “TestApp”. Now from the main menu select “Project:Properties” and a window like the one below should appear:  Click on the “+” to open “Configuration Properties” then click on the “+” to open “C/C++” and then click to select “General” in the “C/C++” section if it’s not already selected. Now change the “Configuration” options box (top-left) so it says “All Configurations” then paste the following text into the “Additional include directories” textbox: “.,..\,..\..\common,..\..\..\common,..\..\..\..\includes” (without the quotes). Now click on the “+” to open “Linker” and click to select “General” in the “Linker” section if it’s not already selected then paste the following text into the “Additional library directories” textbox (without the quotes): if the target is Smartphone 2003: “..\..\..\..\libs\sp2003se”; if the target is PocketPC 2003: “..\..\..\..\libs\ppc2003se”; if the target is Smartphone 2005: “..\..\..\..\libs\sp2005”; if the target is PocketPC 2005: “..\..\..\..\libs\ppc2005”; if the target is a PC: “..\..\..\..\libs\pc2005”. Now in the left pane click on the “Input” option under “Linker” and if the target is a mobile device paste “gx.lib ptdev.lib” (without the quotes) into the “Additional dependencies” textbox or if the target is a PC then paste “ptdev.lib winmm.lib” (without the quotes) into the “Additional dependencies” textbox. Finally if the target is mobile then in the “Ignore specific library” textbox put “oldnames.lib” (without the quotes). Now click on “OK” and you should be ready to build your new application, but I recommend saving the project first. If targeting WM2003SE you may need to see the next page. From this point, to get to know how to use PTDev, it’s best to study the PTDevoids sample source. WM2003SE issues IF you get build errors relating to “vftable” and/or “__security_cookie” when trying to build for WM2003SE then you probably need to see this:  HYPERLINK "http://support.microsoft.com/default.aspx?scid=kb;en-us;830482" http://support.microsoft.com/default.aspx?scid=kb;en-us;830482 Follow the instruction to download and install the update patch files if you haven’t previously done so. Then you need to change your WM2003SE project as follows: In the main properties window for the WM2003SE version of your project, select “Input” in the Linker section and add “ ccrtrtti.lib” (without the quotes) to the “Additional dependencies” textbox. Finally select “Code Generation” in the C/C++ section and change the “Buffer Security Check” to “No (/GS-)” (note that sometimes we found VS2005 beta changed this setting back to “yes” and the “__security_cookie” error returned, if this happens just turn the “Buffer Security Check” off again – the problem seems to have been fixed in the release version of VS2005). Now your WM2003SE project should build OK. Classes PTDevApp (An application class) PTDev PTMath PTDevDisplay PTDevInput PTDevTimer PTDevSurface PTDevMaskSurface : PTDevSurface PTDevFontSurface : PTDevSurface PTDevSpriteSurface : PTDevSurface PTDevSprite PTDevAnimation PTDevAnimated PTDevSound Please note that for all functions provided in PTDev: 1. For functions that return HRESULT values (unless otherwise stated): If the function is successful the return value is S_OK (==0). If the function fails but there is no error then the return value is S_FALSE (==1). If the function fails due to an error then an appropriate (negative) error code is returned. 2. RECT structures are considered as top/left inclusive and bottom/right exclusive. PTDevApp PTDevApp is a class provided to interface PTDev with your applications, you could use PTDev without PTDevApp but PTDevApp makes development much simpler, particularly when creating a new project. Also, the PTDevApp files demonstrate how to use the rest of PTDev if you do not wish to actually use PTDevApp itself and the PTDevApp source is provided so you can tailor it as you like if you wish to do so. PTDevApp is designed in such a way that you should create a derived class for your application such as “class MyApp : public PTDevApp” and has a number of virtual functions that you should provide in your derived class. In your main application (.cpp) file you should have a WinMain() that instantiates your derived PTDevApp class, for example: int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR pCmdLine, int nCmdShow) { PTAPPCONFIG config; ::ZeroMemory(&config,sizeof(PTAPPCONFIG)); config.hInstance=hInstance; config.pAppTitle=TEXT("My Application"); config.fps=20; config.displayFlags=PTFixedAspect; config.width=240; config.height=320; config.zoomWidth=480; config.zoomHeight=640; config.icon=IDI_APP; config.alwaysActive=FALSE; config.regainFocus=TRUE; config.doubleClick=FALSE; config.multipleInst=FALSE; #ifdef PTAddSound config.dwMaxSounds=8; config.nChannels=2; config.nSamplesPerSec=22050; config.dwBufferTicks=150; config.wBitsPerSample=16; config.dwVolumeL=0x100; config.dwVolumeR=0x100; #endif // Create the derived application class MyApp* pMyApp=new MyApp(config); // Start the main loop HRESULT hr=-1; if (pMyApp) { hr=pMyApp->Run(); delete pMyApp; } // Exit application return hr; } Run() first instantiates the PTDev classes, these are: PTDev* app_pPTDev; PTDevDisplay* app_pDisplay; PTDevInput* app_pInput; PTDevTimer* app_pTimer; #ifdef PTAddSound PTDevSound* app_pSound; #endif Note that when using PTDevSound the main PTDevApp class takes care of initialising, starting, updating, stopping and closing the sound output; in your application you need only trigger new sounds and change volume or pitch etc. PTDevApp Virtual Functions InitInstance() Your InitInstance() function should initialise all the necessary items for your application, such as initialising variables and instantiating surfaces. For example: HRESULT MyApp::InitInstance() { title=new PTDevSurface(app_pPTDev); ship=new PTDevSurface(app_pPTDev); gamestate=0; shipx=shipy=akey=0; return S_OK; } InitInstance() is only called once from the PTDevApp::Run() function after the instantiation of the PTDev classes. CreateSurfaces() Your CreateSurfaces() function should create the surfaces used by your application such as source surfaces for sprites, fonts and others such as mask surfaces for collision testing (if used), any surfaces should be instantiated in InitInstance(). HRESULT MyApp::CreateSurfaces(PTDevDisplay* pDisplay) { title->CreateSurface(0,app_hInst,TITLE,TEXT("Bitmap")); ship->CreateSurface(0,app_hInst,SHIP,TEXT("Bitmap")); ship->SetColourKey(RGB(0,255,0)); return S_OK; } CreateSurfaces() is only called once by PTDevApp after the initialisation of the necessary PTDev classes, the opening of the display and the call to InitInstance(). Strictly speaking you should of course include error checks for CreateSurface() and any other functions used (returning the error code instead of S_OK on any error). AlignSurfaces() Your AlignSurfaces() function is called by PTDevApp when you instruct PTDevApp to change the display using the SetDisplayMode() function. In it you should call the AlignSurface() function for each of your surfaces so that they are orientated in line with the display and BackBuffer for optimum performance. For example: HRESULT MyApp::AlignSurfaces() { title->AlignSurface(); ship->AlignSurface(); return S_OK; } Again you should really check for errors and return any error code on an error. It should be noted that the PTDevSurface::AlignSurface() functions do so without any extra memory use and eliminate the need to re-call CreateSurface() to reorient surfaces. KeyDown() KeyDown() is called when a key is first pressed. For example: HRESULT MyApp::KeyDown(DWORD dwKey, PTKeyList &keylist) { akey=dwKey; return S_OK; } KeyUp() KeyUp() is called when a key is released. For example: HRESULT MyApp::KeyUp(DWORD dwKey, PTKeyList &keylist) { akey=0; return S_OK; } StylusDown() Called each time the stylus first touches the screen. For example: HRESULT MyApp::StylusDown(POINT p) { coord=p; stylus=TRUE; return S_OK; } StylusUp() Called when the stylus is removed from the screen. For example: HRESULT MyApp::StylusUp(POINT p) { stylus=FALSE; return S_OK; } StylusDblClk() Called when a double-tap is detected. For example: HRESULT MyApp::StylusDblClk(POINT p) { coorddbl=p; stylusdbl=TRUE; // set flag to FALSE when processed return S_OK; } StylusMove() Called when the stylus is moved across the screen. For example: HRESULT MyApp::StylusMove(POINT p) { coord=p; return S_OK; } OnMinimize() If you need to do any housekeeping as your app is minimised then do it here. HRESULT MyApp::OnMinimize() { return S_OK; } OnRestore() If you need to do any housekeeping as your app is restored then do it here. HRESULT MyApp::OnRestore() { return S_OK; } ProcessNextFrame() ProcessNextFrame() is where you update the BackBuffer with the next frame of your application. In it you should perform all necessary updates/animation etc. ProcessNextFrame() is called by PTDevApp based on the framerate you set in “PTAPPCONFIG config” in your WinMain() and precedes the BackBuffer actually being put on display. For example: HRESULT MyApp::ProcessNextFrame(PTDevSurface* pBackBuffer, DWORD dwFlags) { PTBLTFX bltfx; long w=(long)pBackBuffer->GetWidth(); long h=(long)pBackBuffer->GetHeight(); pBackBuffer->FillRect(NULL,0,0,NULL); bltfx.centre.x=(w>>1)+shipx; bltfx.centre.y==(h>>1)+shipy; pBackBuffer->BlitFast (NULL,ship,NULL,UsePTColourKey|UsePTCentre,&bltfx); if (stylus) { shipx=coord.x-(w>>1); shipy=coord.y-(h>>1); } if (akey) { Shutdown(); akey=0; } return S_OK; } ExitInstance() Here you should perform housekeeping ready for program exit, deleting surfaces or deallocating memory instantiated or allocated in InitInstance(). HRESULT MyApp::ExitInstance() { delete ship; delete title; return S_OK; } PTDev The PTDev class contains shared variables used by the other classes in the PTDev library. It includes no functions and is not a true base class; it simply requires instantiating prior to the rest of the PTDev library. If using PTDevApp then PTDev is taken care of in the Run() function, otherwise you should simply instantiate PTDev using for example: app_pPTDev=new PTDev(); PTMath PTMath, as you might expect, is a class containing some maths functions. An instance is created on instantiation of the PTDev class and is used internally in the rest of the PTDev library, also being publicly available via the PTDev class, for example: app_pPTDev->pPTMath->SinCos(s,c,angle); Most of the functions in PTMath relate to the Sines and Cosines of angles. The value used for the angles is such that: 360 degrees (or 2pi radians) is PTTwoPi or (1<GetKeyList(); keylist=app_pInput->keys; #else keylist.vkUp=VK_UP; keylist.vkDown=VK_DOWN; keylist.vkLeft=VK_LEFT; keylist.vkRight=VK_RIGHT; keylist.vkStart=VK_RETURN; keylist.vkA=WK_A; keylist.vkB=WK_B; keylist.vkC=WK_C; keylist.vkD=WK_D; #endif KeyDown(wParam,keylist); } return 0; case WM_KEYUP: PTKeyList keylist; #ifdef _WIN32_WCE app_pInput->GetKeyList(); keylist=app_pInput->keys; #else keylist.vkUp=VK_UP; keylist.vkDown=VK_DOWN; keylist.vkLeft=VK_LEFT; keylist.vkRight=VK_RIGHT; keylist.vkStart=VK_RETURN; keylist.vkA=WK_A; keylist.vkB=WK_B; keylist.vkC=WK_C; keylist.vkD=WK_D; #endif KeyUp(wParam,keylist); return 0; (WK_A to WK_D are simply defines in “PTDevApp.h” and may be changed as you like) When using PTDevApp the Run() function calls CloseInput() on minimise and OpenInput() on restore, if not using PTDevApp then you need to handle minimise/restore by calling CloseInput() and OpenInput() appropriately. If OpenInput() fails it will return PTINPUT_ERROR. CloseInput() void PTDevInput::CloseInput() CloseInput() unlocks the buttons on mobile devices, releasing them back to the system. When using PTDevApp the Run() function calls CloseInput() on minimise and OpenInput() on restore, if not using PTDevApp then you need to handle minimise/restore by calling CloseInput() and OpenInput() appropriately. GetKeyList() HRESULT PTDevInput::GetKeyList() GetKeyList() sets PTDevInput::keys to the correct codes for the device buttons, on full PC’s GetKeyList() sets the list to the following defaults: keys.vkUp=VK_UP; keys.vkDown=VK_DOWN; keys.vkLeft=VK_LEFT; keys.vkRight=VK_RIGHT; keys.vkA=0xbd; keys.vkB=0xbb; keys.vkC=0xdb; keys.vkD=0xdd; keys.vkStart=VK_RETURN; GetKeyList() is handled in PTDevApp if you are using it, otherwise you should call GetKeyList() directly to retrieve the codes assigned to the buttons on the device. If OpenInput() has not been called or retrieving the keylist fails then GetKeyList() returns PTINPUT_ERROR. PTDevTimer PTDevTimer is a class to handle the frame timings for your application. If using PTDevApp then PTDevTimer is taken care of in Run(), otherwise you should create an instance of PTDevTimer using for example: app_pTimer=new PTDevTimer() If using PTDevApp then all essential PTDevTimer calls are done from within PTDevApp . The functions in PTDevTimer are: StartTimer() DWORD StartTimer(DWORD TargetFrameRate) StartTimer() starts the timer set to use the specified TargetFrameRate in frames per second. If using PTDevApp then the frame timing for your application is taken from config.fps as initially set in your WinMain() and StartTimer() is called from Run() before entering the main program loop. If not using PTDevApp then just call StartTimer() directly before your main program loop with an appropriate frames per second value for your application. If TargetFrameRate is zero or greater than 1000 then StartTimer() returns PTTIMER_RANGE_ERROR, otherwise it returns the target frame time*256 in milliseconds. WaitForNextFrame() void PTDevTimer::WaitForNextFrame() WaitForNextFrame() does exactly as it says i.e. it waits the relevant time based on when the last call to StartTimer() or WaitForNextFrame() was made and on the current frame rate as set in the last call to StartTimer(). If using PTDevApp then WaitForNextFrame() is called after each call to your ProcessNextFrame() and before the BackBuffer is put on display which means updates to the display are as regular as possible. If not using PTDevApp then just call WaitForNextFrame() directly as your application requires. GetAveFrameRate() FLOAT PTDevTimer::GetAveFrameRate() GetAveFrameRate() simply returns the current average frame rate over a second. You may call it as you wish, it is not called in PTDevApp. GetAveFrameTime() FLOAT PTDevTimer::GetAveFrameTime() GetAveFrameTime() simply returns the current average frame time over a second in milliseconds. You may call it as you wish, it is not called in PTDevApp. GetLastFrameTime() DWORD PTDevTimer::GetLastFrameTime() GetLastFrameTime() returns the last frame time*256 in milliseconds. You may call it as you wish, it is not called in PTDevApp. GetWorstRate() FLOAT PTDevTimer::GetWorstRate() GetWorstRate() returns the worst frame rate since the last call to StartTimer() or ResetWorstRate() in frames per second. You may call it as you wish, it is not called in PTDevApp. ResetWorstRate() void PTDevTimer::ResetWorstRate() ResetWorstRate() resets the worst frame rate to the last requested target frame rate. You may call it as you wish, it is not called in PTDevApp. PTDevSurface PTDevSurface is the base class for all surfaces in PTDev, all PTDev surfaces are limited to a maximum width or height of 2048 pixels. Using PTDevSurface has 4 main parts: Instantiating a surface Creating a surface Manipulating/using the surface Deleting the surface Instantiating a surface requires an existing PTDev object, use for example: title=new PTDevSurface(app_pPTDev); Deleting a surface is straightforward, for example: delete title; The functions available in PTDevSurface allow you to create, use and manipulate your surfaces: CreateSurface() Once you’ve instantiated your surface object you must create the actual surface. CreateSurface() is five times overloaded: HRESULT PTDevSurface::CreateSurface(DWORD flags, HMODULE hModule, DWORD ResourceID, const TCHAR* pResourceType) HRESULT PTDevSurface::CreateSurface(DWORD flags, PTDevSurface* pSourceSurf) HRESULT PTDevSurface::CreateSurface(DWORD flags, void* pBuffer) HRESULT PTDevSurface::CreateSurface(DWORD flags, const TCHAR* filename) HRESULT PTDevSurface::CreateSurface(DWORD flags, DWORD width, DWORD height) As you can see above you may CreateSurface() from a resource, from an existing PTDevSurface, from a (PTSurf) buffer, from a (PTSurf) file or simply create an empty surface to a given width and height, respectively. In all cases the flags parameter has two bits you may set, these are: PTSurfClear PTSurfFixed If PTSurfClear is set in flags then the surface is cleared to black irrespective of whether the call indicates source graphics or not so you get a black surface of the relevant size. Note that PTSurfClear is ignored when creating a surface from a PTSurf resource or when creating a surface with PTSurfFixed set in flags. If PTSurfFixed is set in flags then the created surface is flagged as unmodifiable with respect to all surface operations including AlignSurface() which means that such a surface will not be realigned when requested. Surfaces created to a specified width and height are never flagged as unmodifiable. Surfaces created from a PTSurf resource are always flagged as unmodifiable. If using unmodifiable surfaces, for optimum performance it should be ensured that all surfaces’ alignments stay matched to that of the BackBuffer by setting the PTKeepPitch flag for controlling OpenDisplay() and ChangeDisplay(). An unmodifiable surface can only be used as a PTDevSpriteSurface or PTDevFontSurface if it doesn’t requires the use of GrabSprites() or GrabFont() or if the invisible and transparent colours match in the call to GrabSprites() or GrabFont() as otherwise any pixels of the invisible colour are changed in the “grab”. You may call CreateSurface() again for a PTDevSurface object that already has a surface created without calling FreeSurface() first; if the call to CreateSurface() fails, the original surface is always freed. Re-using PTDevSurface objects in this way should be avoided due to the poor memory handling of mobile devices. CreateSurface() (from a resource) HRESULT PTDevSurface::CreateSurface(DWORD flags, HMODULE hModule, DWORD ResourceID, const TCHAR* pResourceType) Call CreateSurface() with hModule, ResourceID and pResourceType set the same way as you would for calling ::FindResource(), for example: title->CreateSurface(0,app_hInst,TITLE,TEXT("JPG")); HModule should be a handle to the module whose executable file contains the resource. If using PTDevApp this is app_hInst for your application executable. For the ResourceID simply use the name of your resource. The pResourceType text may be one of the following: “Bitmap” for standard MS Windows bitmap files “.bmp”, “PNG” for “.png” image files (mobile only), “JPG” for “.jpg” image files (mobile only), “GIF” for “.gif” image files (mobile only), or “PTSURF” for a PTSurf buffer. “Bitmap”, “PNG”, “JPG”, and “GIF” resources should not contain multiple images or non-standard embedded information. “PTSURF” is for PTSurf buffers included as resources having previously been saved using PTDevSurface::SaveSurface(). CreateSurface() from a resource may return the following errors: PTSURF_TYPE_UNKNOWN, PTSURF_RES_FIND_ERROR, PTSURF_RES_LOAD_ERROR, PTSURF_RES_LOCK_ERROR, PTSURF_MEM_ERROR, PTSURF_DCMP_FAIL, PTSURF_HDC_ERROR, PTSURF_LOAD_BMP_ERROR, PTSURF_DIB_ERROR, PTSURF_RES_SIZE_ERROR, PTSURF_TYPE_INVALID or PTSURF_SURFSIZE_ERROR CreateSurface() (from a surface) HRESULT PTDevSurface::CreateSurface(DWORD flags, PTDevSurface* pSourceSurf) Simply provides a way of duplicating a surface, it may return the following errors: PTSURF_NO_SURFACE, PTSURF_NO_SURFACEMEM or PTSURF_MEM_ERROR CreateSurface() (from a PTSurf buffer) HRESULT PTDevSurface::CreateSurface(DWORD flags, void* pBuffer) Allows you to create a surface from a PTSurf buffer currently stored in memory, for example after having loaded a PTSurf file, previously saved using PTDevSurface::SaveSurf(), into memory (having allocated the memory yourself). Note that such surfaces do NOT release this buffer memory on FreeSurface() or surface destruction since the memory was not allocated by PTDevSurface. May return the following errors: PTSURF_TYPE_INVALID, PTSURF_TYPE_UNKNOWN or PTSURF_SURFSIZE_ERROR, CreateSurface() (from a PTSurf file) HRESULT PTDevSurface::CreateSurface(DWORD flags, const TCHAR* filename) Allows you to create a surface directly from a PTSurf file previously saved using PTDevSurface::SaveSurf(), it may return the following errors: PTSURF_FILE_READ_ERROR, PTSURF_FILE_SIZE_ERROR, PTSURF_SURFSIZE_ERROR or PTSURF_MEM_ERROR CreateSurface() (simply to given width and height) HRESULT PTDevSurface::CreateSurface(DWORD flags, DWORD width, DWORD height) Creates a surface of the given width and height, on error it may return: PTSURF_SURFSIZE_ERROR or PTSURF_MEM_ERROR. AlignSurface() AlignSurface() is twice overloaded: HRESULT PTDevSurface::AlignSurface() HRESULT PTDevSurface::AlignSurface(long xPitch, long yPitch) The no parameter version will align the surface to match the current alignment of the BackBuffer and should be called whenever the BackBuffer is realigned if you wish to maintain optimum performance. If using PTDevApp then you should have calls to AlignSurface() for all your surfaces in your PTDevApp::AlignSurfaces() function. If not using PTDevApp then you should make calls to AlignSurface() for your surfaces appropriately in a similar manner. If there is no BackBuffer (i.e. OpenDisplay() has not been called previously) then AlignSurface() fails and returns PTSURF_NODISP_ERROR. The second version, where you may pass an xPitch and yPitch, is for specialist use. The xPitch and yPitch values are in pixels. An example could be that you want to force a surface to have an xPitch of +1 and a positive yPitch in which case you should pass +1 for xPitch and any positive value >1 for the yPitch. Note that one of the two parameters, xPitch or yPitch, MUST be either +1 or –1 and the other parameter MUST be either >+1 or <-1 depending on how you want the surface to be aligned. If the xPitch and/or yPitch value/s do not follow these restrictions then AlignSurface() will fail. Both versions of AlignSurface() will fail if the surface is flagged as unmodifiable. A surface will be flagged as unmodifiable if CreateSurface() was called with the PTSurfFixed bit set in flags or if it was created from a PTSurf resource. If AlignSurface() fails either due to bad values of xPitch or yPitch or because the surface is unmodifiable then it will return S_FALSE. AlignSurface() will return a PTSURF_NO_SURFACEMEM error if there is no surface. FreeSurface() void PTDevSurface::FreeSurface() FreeSurface() frees up all the resources associated with a surface i.e. the actual surface is deleted but not the PTDevSurface object. SetViewPort() HRESULT PTDevSurface::SetViewPort(RECT* pRect) SetViewPort() allows you to specify a rectangular area of your surface the outside of which will not be modified by drawing or blitter operations i.e. it lets you specify a clipping rectangle for the surface. By default, on creation of a surface, the ViewPort is set to the entire surface rectangle. The new ViewPort set in SetViewPort() will be the rectangle specified by pRect, clipped to the entire surface rectangle. If you pass NULL as pRect then the ViewPort is reset to the entire surface rectangle. If using the debug version of PTDev then SetViewPort() returns PTSURF_NO_SURFACEMEM if there is no surface. GetSurfData() PTSURFACE* PTDevSurface::GetSurfData() GetSurfData() returns a pointer to the surface’s PTSURFACE data unless there is no surface in the PTDevSurface object in which case it returns NULL. If you wish to manipulate a surface using your own custom routines on a pixel basis then the surface’s PTSURFACE structure gives you the required information. GetSurfaceFlags() HRESULT GetSurfaceFlags(DWORD& dwFlags) GetSurfaceFlags() sets dwFlags to the surface surface.flags if there is a surface, otherwise it returns PTSURF_NO_SURFACEMEM. Currently the only relevant flag from the surface flags is PTSurfFixed which indicates that the surface is unmodifiable if set. GetBufferBase() unsigned short* PTDevSurface::GetBufferBase() GetBufferBase() returns the base address of the surface buffer or NULL if there is no surface. Note that the base address is NOT necessarily the address of pixel (0,0). The offset to the address of pixel (0,0) from the base address can be calculated using the xPitch, yPitch, width and height of the surface. GetXpitch() long PTDevSurface::GetXpitch() GetXpitch() returns surface.xPitch (in pixels) or zero if there is no surface. GetYpitch() long PTDevSurface::GetYpitch() GetYpitch() returns surface.yPitch (in pixels) or zero if there is no surface. GetWidth() DWORD PTDevSurface::GetWidth() GetWidth() returns surface.width (in pixels) or zero if there is no surface. GetHeight() DWORD PTDevSurface::GetHeight() GetHeight() returns surface.height (in pixels) or zero if there is no surface. GetColourKey() HRESULT PTDevSurface::GetColourKey(COLORREF& cColourKey) GetColourKey() sets cColourKey to surface.colourKey if there is a surface, otherwise it returns PTSURF_NO_SURFACEMEM. SetColourKey() HRESULT SetColourKey(COLORREF cColourKey) SetColourKey() sets the surface surface.colourKey to cColourKey if there is a surface, otherwise it returns PTSURF_NO_SURFACEMEM. ColourrefToNative() void ColourrefToNative(DWORD& dwNative, COLORREF cColour) ColourrefToNative() sets dwNative to the value of cColour converted to the internal format used by the surface (currently always RGB 565). NativeToColourref() void PTDevSurface::NativeToColourref(COLORREF& cColour, DWORD dwNative) NativeToColouref() sets cColour to the value of dwNative converted to a COLORREF from the internal format used by the surface (currently always RGB 565). ColourrefToColourref() void PTDevSurface::ColourrefToColourref(COLORREF& cNative, COLORREF cColour) ColourrefToColourref() sets cNative to cColour with the bits masked appropriately, it is equivalent to calling ColourrefToNative() followed by NativeToColourref(). GetPixel() HRESULT PTDevSurface::GetPixel(COLORREF& cColour, long x, long y) If the pixel at location (x,y) is on the surface then GetPixel() sets cColour to the colour of the pixel. If using the debug version of PTDev and there is no surface then GetPixel() returns PTSURF_NO_SURFACEMEM. If the pixel location (x,y) is off the surface then GetPixel() returns S_FALSE. SetPixel() HRESULT PTDevSurface::SetPixel(long x, long y, COLORREF cColour, DWORD flags, PTDRAWFX *pDrawFX) SetPixel() sets the pixel at (x,y) on the surface (if the pixel is inside the surface ViewPort) to the colour set by cColour, flags and pDrawFX. If using the debug version of PTDev and there is no surface then SetPixel() returns PTSURF_NO_SURFACEMEM. If the pixel is clipped then SetPixel() returns S_FALSE. DrawLine() HRESULT PTDevSurface::DrawLine(long x1, long y1, long x2,long y2, COLORREF cColour, DWORD flags, PTDRAWFX* pDrawFX) DrawLine() draws a line from pixel position (x1,y1) to pixel position (x2,y2) (inclusive) on the surface (clipped to the surface ViewPort) according to cColour, flags and pDrawFX. If using the debug version of PTDev and there is no surface then DrawLine() returns PTSURF_NO_SURFACEMEM. If the line is clipped completely then DrawLine() returns S_FALSE. DrawRect() HRESULT PTDevSurface::DrawRect(RECT* pRect, COLORREF cColour, DWORD flags, PTDRAWFX* pDrawFX) DrawRect() draws the rectangle outline specified by pRect on the surface (clipped to the surface ViewPort) according to cColour, flags and pDrawFX. Note that the bottom/right of the rectangle are treated as exclusive and corner pixels are processed twice. If pRect is NULL then the rectangle is taken to be the current surface ViewPort. If using the debug version of PTDev and there is no surface then DrawRect() returns PTSURF_NO_SURFACEMEM. If the rectangle is clipped completely then DrawRect() returns S_FALSE. FillRect() HRESULT PTDevSurface::FillRect(RECT* pRect, COLORREF cColour, DWORD flags, PTDRAWFX* pDrawFx) FillRect() draws the filled rectangle specified by pRect on the surface (clipped to the surface ViewPort) according to cColour, flags and pDrawFX. Note that the bottom/right of the rectangle are treated as exclusive. If pRect is NULL then the rectangle is taken to be the current surface ViewPort. If using the debug version of PTDev and there is no surface then FillRect() returns PTSURF_NO_SURFACEMEM. If the rectangle is clipped completely then FillRect() returns S_FALSE. BlitFast() BlitFast() is twice overloaded: HRESULT BlitFast(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) HRESULT BlitFast(RECT* pClipRect, long x, long y, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) The first version either Blits the source data to the destination, excluding rotation/scaling, centred on the centre of the destination Viewport or to a destination centre specified by flags and pBltFX. The second version Blits the source data to the destination, including rotation/scaling, either such that x and y specify the top-left corner of the destination area or to a destination centre specified by flags and pBltFX. BltFast() (No destination coordinate) HRESULT BlitFast(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitFast() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, clipped to the rectangle specified by pClipRect and according to flags and pBltFX excluding rotation/scaling. If flags and pBltFX do not specify a destination centre then the centre of the (dest.) surface ViewPort is taken as the destination centre. The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitFast() returns PTSURF_NO_SURFACE. If there is no source surface, BlitFast() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitFast() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitFast() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitFast() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitFast() returns S_FALSE. BlitFast() (Using destination coordinate) HRESULT BlitFast(RECT* pClipRect, long x, long y, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitFast() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, clipped to the rectangle specified by pClipRect and according to flags and pBltFX including rotation and scaling. The (dest.) surface coordinate (x,y) is taken as the destination top-left for the rectangle copied (before the application of any rotation/scaling) unless flags and pBltFX specify a destination centre in which case that takes priority. The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitFast() returns PTSURF_NO_SURFACE. If there is no source surface, BlitFast() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitFast() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitFast() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitFast() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitFast() returns S_FALSE. BlitScale() HRESULT BlitScale(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitScale() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, clipped to the rectangle specified by pClipRect and according to flags and pBltFX excluding rotation but including scaling. If flags and pBltFX do not specify a destination centre then the centre of the (dest.) surface ViewPort is taken as the destination centre. The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitScale() returns PTSURF_NO_SURFACE. If there is no source surface, BlitScale() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitScale() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitScale() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitScale() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitScale() returns S_FALSE. BlitRot() HRESULT BlitRot(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitRot() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, clipped to the rectangle specified by pClipRect and according to flags and pBltFX including rotation and scaling. If flags and pBltFX do not specify a destination centre then the centre of the (dest.) surface ViewPort is taken as the destination centre. The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitRot() returns PTSURF_NO_SURFACE. If there is no source surface, BlitRot() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitRot() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitRot() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitRot() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitRot() returns S_FALSE. BlitRect() HRESULT BlitRect(RECT* pClipRect, RECT* pScaleRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitRect() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, scaled to the rectangle specified by pScaleRect, clipped to the rectangle specified by pClipRect and according to flags and pBltFX including scaling. If pScaleRect is NULL then the source rectangle is scaled to the destination surface ViewPort. Any scaling specified by flags and pBltFX is applied in addition to the scaling to the relevant rectangle. If flags and pBltFX do not specify a destination centre then the centre of the scaling rectangle is taken as the destination centre for the rectangle copied (i.e. the centre of pScaleRect or of the destination ViewPort). The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitRect() returns PTSURF_NO_SURFACE. If there is no source surface, BlitRect() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitRect() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitRect() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitRect() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitRect() returns S_FALSE. BlitRotRect() HRESULT BlitRotRect(RECT* pClipRect, RECT* pScaleRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX) BlitRotRect() copies the source rectangle specified by pSrcRect from the source surface specified by pSrcSurf to the surface, scaled to the rectangle specified by pScaleRect, clipped to the rectangle specified by pClipRect and according to flags and pBltFX including scaling and rotation. If pScaleRect is NULL then the source rectangle is scaled to the destination surface ViewPort. Any scaling and rotation specified by flags and pBltFX is applied in addition to the scaling to the rectangle. If flags and pBltFX do not specify a destination centre then the centre of the scaling rectangle is taken as the destination centre for the rectangle copied (i.e. the centre of pScaleRect or of the destination surface ViewPort). The rectangle copied is clipped to the result of clipping the rectangle specified by pClipRect to the destination ViewPort. If pClipRect is NULL then the rectangle copied is simply clipped to the destination ViewPort. If pSrcRect is NULL then the source rectangle is taken as the entire source surface specified by pSrcSurf. If using the debug version of PTDev then: If pSrcSurf is NULL, BlitRotRect() returns PTSURF_NO_SURFACE. If there is no source surface, BlitRotRect() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, BlitRotRect() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitRotRect() returns PTSURF_SOURCERECT_INVALID. If the (dest.) surface is flagged as unmodifiable then BlitRotRect() returns PTSURF_NOTMOD_ERROR. If the rectangle is completely clipped then BlitRotRect() returns S_FALSE. Intersecta() HRESULT Intersecta(POINT* p, PTDevSurface* pDestSurf, RECT* pClipRect1, RECT* pScaleRect1, RECT* pSrcRect1, DWORD flags1, PTBLTFX *pBltFX1, RECT *pClipRect2, RECT* pScaleRect2, PTDevSurface* pSrcSurf, RECT* pSrcRect2, DWORD flags2, PTBLTFX *pBltFX2) Intersecta() performs a virtual collision check on two blitter objects, the objects’ destination can be anywhere, the destination surface pDestSurf is only required in order to get the destination coordinates if pScaleRect1 or pScaleRect2 is NULL and flags1 and pBltFX1 or flags2 and BltFX2 do not specify a destination centre. If a scaling rectangle is specified by pScaleRect1 or pScaleRect2 then the relevant object is scaled to that rectangle, if pScaleRect1 or pScaleRect2 is NULL then no scaling (to a rectangle) is applied which means that if corresponding BlitRect() or BlitRotRect() calls were made such that the blitter object was scaled to the destination surface ViewPort then an appropriate rectangle must be supplied as pScaleRect1 or pScaleRect2 i.e. a rectangle matching the ViewPort. For example if two objects were (to be) blitted as follows: pBackBuffer->BlitRect(pClipRect, NULL, pSrcSurf1, pSrcRect1, 0,NULL); pBackBuffer->BlitRotRect(NULL, NULL, pSrcSurf2, pSrcRect2, 0, NULL); Then to test for intersection (collision) you could use: RECT arect; POINT p; pBackBuffer->GetViewPort(arect); if (pSrcSurf1->Intersecta(&p, NULL, pClipRect, &arect, pSrcRect1, 0, NULL, NULL, &arect, pSrcSurf2, pSrcRect2, 0, NULL)==S_OK) { process collision at point p } If flags1 and pBltFX1 or flags2 and pBltFX2 do not specify a destination centre then the destination centre is taken as the centre of the rectangle specified by pScaleRect1 or pScaleRect2 unless pScaleRect1 or pScaleRect2 is NULL in which case the centre of the ViewPort of the destination surface specified by pDestSurf is used as the destination centre. Only intersections within BOTH clip rectangles specified by pClipRect1 and pClipRect2 are considered (one or both may be NULL in which case they do not contribute to any clipping). Note that NO ViewPort is used in the clipping, if you wish to clip to a particular destination ViewPort then you must specify appropriate clipping rectangle/s as pClipRect1 and/or pClipRect2. Use pSrcSurf to specify the source surface for the second blitter object, note that it can be NULL only if the second blitter object is not using the ColourKey and has a source rectangle specified by pSrcRect2. You may specify a source rectangle for the first blitter object using pSrcRect1 and for the second using pSrcRect2, if a source rectangle pointer is NULL then the entire source surface is used as the source rectangle, in which case the relevant source surface must be valid. This intersection test works with blitter objects that have rotation and/or scaling and/or are using a ColourKey (as specified by flags1, pBltFX1, flags2 and pBltFX2). If an intersection is found then Intersecta() sets *p to a valid intersection coordinate and returns S_OK. If no intersection is found then Intersecta() returns S_FALSE. If using the debug version of PTDev then: If there is no surface memory for the first blitter object, Intersecta() returns PTSURF_NO_SURFACEMEM if the first blitter object is set to use the ColourKey by flags1 or if pSrcRect1 is NULL. If pSrcSurf is NULL, Intersecta() returns PTSURF_NO_SURFACE if the second blitter object is set to use the ColourKey by flags2 or if pSrcRect2 is NULL. If pSrcSurf is not NULL but has no surface, Intersecta() returns PTSURF_NO_SURFACEMEM if the second blitter object is set to use the ColourKey by flags2 or if pSrcRect2 is NULL. If the rectangle specified by pSrcRect1 or pSrcRect2 extends off the area of the relevant source surface when the relevant blitter object is set to use the ColourKey in flags1 or flags2 then Intersecta() returns PTSURF_SOURCERECT_INVALID. If a destination surface is required and pDestSurf is NULL then Intersecta() returns PTSURF_NO_SURFACE. If a destination surface is required and the PTDevSurface specified by pDestSurf does not have any surface data then Intersecta() returns PTSURF_NO_SURFACEMEM. Intersectb() HRESULT Intersectb(POINT *p, PTDevSurface *pDestSurf, RECT *pClipRect1, RECT *pScaleRect1, RECT *pSrcRect1, DWORD flags1, PTBLTFX *pBltFX1, RECT* pClipRect2, long x2, long y2, PTDevSurface *pSrcSurf, RECT *pSrcRect2, DWORD flags2, PTBLTFX *pBltFX2) Intersectb() is provided for cases when one of the blitter objects you wish to collision test was/is going to be blitted using BlitFast() to a given (top-left) destination coordinate. Simply pass the appropriate data for this blitter object as the second set of data in the call to Intersectb(), passing the top-left coordinate as x2 and y2. Apart from using the specified top-left corner point (x2,y2) to set the destination location (if the specified flags2 and pBltFX2 do not specify a destination centre) and applying no scaling rectangle to the second object, Intersectb() operates in exactly the same way as Intersecta(). This intersection test works with blitter objects that have rotation and/or scaling and/or are using a ColourKey (as specified by flags1, pBltFX1, flags2 and pBltFX2). Intersectc() Intersectc(POINT* p, RECT* pClipRect1, long x1, long y1, RECT* pSrcRect1, DWORD flags1, PTBLTFX* pBltFX1, RECT* pClipRect2, long x2, long y2, PTDevSurface* pSrcSurf, RECT* pSrcRect2, DWORD flags2, PTBLTFX* pBltFX2) Intersectc() is provided for cases when both the blitter objects you wish to collision test was/is going to be blitted using BlitFast() to a given (top-left) destination coordinate. Pass the top-left coordinates to Intersectc() as x1, y1 and x2,y2. Apart from using the specified top-left corner point/s (x1,y1) and/or (x2,y2) to set the destination location (if the specified flags1 and pBltFX1 and/or flags2 and pBltFX2 do not specify a destination centre) and applying no scaling rectangles to the objects, Intersectc() operates in exactly the same way as Intersecta(). This intersection test works with blitter objects that have rotation and/or scaling and/or are using a ColourKey (as specified by flags1, pBltFX1, flags2 and pBltFX2). SaveSurface() HRESULT SaveSurface(TCHAR* filename) SaveSurface() will save a valid surface out in PTSurf format as a file called filename which may then be included as a PTSURF resource to be turned back into a surface using CreateSurface() (or loaded directly). SaveSurface() may return the following errors: PTSURF_NO_SURFACEMEM, PTSURF_SURFSIZE_ERROR, PTSURF_FILEOPEN_ERROR or PTSURF_FILEWRITE_ERROR SaveBMP() HRESULT SaveBMP(TCHAR*filename) SaveBMP() will save a valid surface out in standard Windows bitmap format as a file called filename which may then be included as a Bitmap resource to be recreated as a surface using CreateSurface()or loaded into graphics applications. SaveBMP() may return the following errors: PTSURF_NO_SURFACEMEM, PTSURF_SURFSIZE_ERROR, PTSURF_MEM_ERROR, PTSURF_FILEOPEN_ERROR or PTSURF_FILEWRITE_ERROR DrawText() long DrawText(long x, long y, RECT* pDestRect, RECT* pClipRect, DWORD font, char* text, DWORD flags, PTTXTFX* pTxtFX, PTSELRECT* pSelRect) DrawText() draws the text starting at the specified (x,y) location in the font specified by the font reference number font using the formatting rectangle specified by pDestRect (or using the surface ViewPort if pDestRect is NULL), clipped to the rectangle specified by pClipRect (and the surface ViewPort) and using the specified flags, pTxtFX and pSelRect. If you specify scaling using flags and pTxtFX then the characters and text layout are adjusted accordingly. If you specify rotation using flags and pTxtFX then the individual characters are rotated, the layout is not rotated (yet) ! The text itself may contain control codes to set/change the colours, size and layout of the text including allowing font changes. If DrawText() succeeds then the return value is the address of the first character in the text string following the last character output by DrawText(). If using the debug version of PTDev then: If the specified font has no surface then DrawText() returns PTSURF_NO_SURFACE. If the specified font surface has no buffer then DrawText() returns PTSURF_NO_SURFACEMEM. If there is no (dest.) surface, DrawText() returns PTSURF_NO_SURFACEMEM. If any (used) character rectangle extends off the area of the source surface then DrawText() returns PTSURF_SOURCERECT_INVALID. If the formatting rectangle specified by pDestRect (not NULL) is invalid then DrawText() returns S_FALSE. If any invalid control characters are found in the text string then DrawText() will return PTTEXT_FORMAT_ERROR. DrawText() may also return the errors associated with the Blit, Draw and Fill functions. If the specified font reference number is greater then the current number of fonts in the PTDev font table minus one then DrawText() will return S_FALSE. PTDevMaskSurface : PTDevSurface PTDevMaskSurface is a class (derived from the PTDevSurface base class) for handling mask surfaces for collision detection. Using PTDevMaskSurface has 4 main parts: Instantiating a mask surface Creating a mask surface Manipulating/using the mask surface Deleting the mask surface Instantiating a mask surface requires an existing PTDev object, use for example: mask=new PTDevMaskSurface(app_pPTDev); Deleting a mask surface is also straightforward, for example: delete mask; Since it is a derived class, PTDevMaskSurface objects inherit all the functions available to PTDevSurface objects though some functions, such as DrawText(), aren’t particularly relevant to using collision testing using masks. To create a mask surface use CreateSurface() as for any PTDevSurface. The extra functions available in PTDevMaskSurface itself are for the handling of collision testing using masks: SetMaskPixel() HRESULT SetMaskPixel(long x, long y, DWORD mask) SetMaskPixel() sets the pixel at location (x,y) on the mask surface to the value of mask. If the point (x,y) is not on the mask surface then SetMaskPixel() returns S_FALSE. If there is no surface buffer then SetMaskPixel() returns PTSURF_NO_SURFACEMEM. OrMaskPixel() HRESULT OrMaskPixel(long x, long y, DWORD mask) OrMaskPixel() BITWISE ORs the pixel at location (x,y) on the mask surface with the value of mask.If the point (x,y) is not on the mask surface then OrMaskPixel() returns S_FALSE. If there is no surface buffer then OrMaskPixel() returns PTSURF_NO_SURFACEMEM. GetMaskPixel() HRESULT GetMaskPixel(long x, long y, DWORD& dwMaskfound) GetMaskPixel() sets dwMaskfound to the value of the mask at pixel (x,y) on the surface. If the point (x,y) is not on the mask surface then GetMaskPixel() returns S_FALSE and sets dwMaskfound to zero. If there is no surface buffer then OrMaskPixel() returns PTSURF_NO_SURFACEMEM. MaskRect() HRESULT MaskRect(RECT*pRect, DWORD flags, PTDRAWFX* pDrawFx, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) MaskRect() draws or BITWISE ORs the rectangle specified by pRect (clipped to the current mask surface ViewPort) on the mask surface as the value mask and/or tests the rectangle specified by pRect (clipped to the current mask surface ViewPort) for intersections/collisions with any mask values already on the surface according to the specified flags, pDrawFX and maskmethod. If testing for intersection/collision as specified by maskmethod then MaskRect() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the specified pRect or simply assume any value on the surface within the specified pRect matching colmask is a collision, in either case MaskRect() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether MaskRect() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If there is no valid mask surface MaskRect() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pRect is clipped completely then MaskRect() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then MaskRect() sets dwMaskfound to zero and Coord to (-1,-1). BlitMask() (No destination coordinate) HRESULT BlitMask(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMask() without a destination coordinate blits exactly the same way as the equivalent BlitFast() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltFast(). If testing for intersection/collision as specified by maskmethod then BlitMask() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMask() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMask() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMask() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMask() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMask() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMask() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMask() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMask() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BlitMask() sets dwMaskfound to zero and Coord to (-1,-1). BlitMaskScale() HRESULT BlitMaskScale(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMaskScale() blits exactly the same way as BlitScale() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltScale(). If testing for intersection/collision as specified by maskmethod then BlitMaskScale() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMaskScale() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMaskScale() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMaskScale() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMaskScale() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMaskScale() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMaskScale() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMaskScale() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMaskScale() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BliMaskScale() sets dwMaskfound to zero and Coord to (-1,-1). BlitMaskRot() HRESULT BlitMaskRot(RECT* pClipRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMaskRot() blits exactly the same way as BlitRot() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltRot(). If testing for intersection/collision as specified by maskmethod then BlitMaskRot() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMaskRot() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMaskRot() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMaskRot() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMaskRot() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMaskRot() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMaskRot() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMaskRot() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMaskRot() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BlitMaskRot() sets dwMaskfound to zero and Coord to (-1,-1). BlitMaskRect() HRESULT BlitMaskRect(RECT* pClipRect, RECT* pScaleRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMaskRect() blits exactly the same way as BlitRect() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltRect(). If testing for intersection/collision as specified by maskmethod then BlitMaskRect() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMaskRect() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMaskRect() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMaskRect() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMaskRect() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMaskRect() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMaskRect() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMaskRect() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMaskRect() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BlitMaskRect() sets dwMaskfound to zero and Coord to (-1,-1). BlitMaskRotRect() HRESULT BlitMaskRotRect(RECT* pClipRect, RECT* pScaleRect, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMaskRotRect() blits exactly the same way as BlitRotRect() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltRotRect(). If testing for intersection/collision as specified by maskmethod then BlitMaskRotRect() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMaskRotRect() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMaskRotRect() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMaskRotRect() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMaskRotRect() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMaskRotRect() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMaskRotRect() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMaskRotRect() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMaskRotRect() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BlitMaskRotRect() sets dwMaskfound to zero and Coord to (-1,-1). BlitMask() (Using destination coordinate) HRESULT BlitMask(RECT* pClipRect, long x, long y, PTDevSurface* pSrcSurf, RECT* pSrcRect, DWORD flags, PTBLTFX* pBltFX, DWORD maskmethod, DWORD mask, DWORD colmask, DWORD& dwMaskfound, POINT& Coord) BlitMask() using top-left coordinate (x,y) blits exactly the same way as the equivalent BlitFast() except that pixels copied are replaced with the appropriate mask as specified by maskmethod (any colour methods or opacity specified by flags and pBltFX are ignored) and collision testing may also be performed as specified by maskmethod and colmask. If flags specifies use of the source surface ColourKey then this is applied the same way as when using BltFast(). If testing for intersection/collision as specified by maskmethod then BlitMask() can either use colmask as a BITWISE AND mask with any values already drawn on the mask surface to test if there is intersection within the blitted area or simply assume any value on the surface within the blitted area matching colmask is a collision, in either case BlitMask() will set dwMaskfound to the value at the collision location and Coord to the location of the collision. If using colmask as a BITWISE AND mask then you can use maskmethod to specify whether BlitMask() should return on the first collision it finds (setting dwMaskfound to the value of the mask at that collision location) or tests for collisions throughout the entire test rectangle BITWISE ORing the values found at all collision locations together, setting dwMaskfound to this value and Coord to the last collision location found (in this way finding all collisions in one pass). If using the debug version of PTDev then: If pSrcSurf is NULL, BlitMask() returns PTSURF_NO_SURFACE. If there is no source surface, BlitMask() returns PTSURF_NO_SURFACEMEM. If there is no mask surface, BlitMask() returns PTSURF_NO_SURFACEMEM. If the rectangle specified by pSrcRect extends off the area of the source surface then BlitMask() returns PTSURF_SOURCERECT_INVALID. If the mask surface is not modifiable then BlitMask() returns PTSURF_NOTMOD_ERROR (using an unmodifiable mask surface is not allowed). If the object to be blitted is clipped completely then BlitMask() returns S_FALSE. If maskmethod specifies collision testing and no collision is found then BlitMask() sets dwMaskfound to zero and Coord to (-1,-1). PTDevFontSurface : PTDevSurface PTDevFontSurface is a class (derived from the PTDevSurface base class) for handling font surfaces for use in text display. Using PTDevFontSurface has 4 main parts: Instantiating a font surface Creating a font surface Manipulating/using the font surface Deleting the font surface Instantiating a font surface requires an existing PTDev object, use for example: afont=new PTDevFontSurface(app_pPTDev); Deleting a font surface is also straightforward, for example: delete afont; Since it is a derived class, PTDevFontSurface objects inherit all the functions available to PTDevSurface objects. To create a font surface use CreateSurface() as for any PTDevSurface. The extra functions available in PTDevFontSurface itself are specifically for handling surfaces of font characters: GrabFont() HRESULT GrabFont(COLORREF key, COLORREF trans, DWORD flags) GrabFont() creates a font from the character graphics on the PTDevFontSurface. The graphics should be in a row (or rows if using extra styles) aligned as they would be when printed and each character separated by at least one clear (key) column of pixels. PTDev currently allows the following character set: !”#$%&’()*+,./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ There should be more than one row of characters if you wish to have custom styles (separated by at least one clear (key) row of pixels) i.e. italic, bold or bold+italic versions of the font. The first row should be “normal”, the next italic (if any), then bold (if any) and finally bold+italic (if any). Use the flags to specify if there are any bold, italic or bold+italic characters. The character graphics need not include the full character set, in that you may have a character set that stops anywhere before the “~”, but any set MUST have graphics for all the characters from the “!” up to your last character. The width of the font’s space character is set to the width of the “.” graphic plus one if the “.” exists, otherwise it is set to the width of the “!” graphic plus one – in either case if the resulting space width is less than 3 pixels then it is set to 3 (the space width being set separately for the different font styles, if any). GrabFont() sets the surface ColourKey to key and allows you to use trans to specify a special transparent colour that you may use to ensure any character with clear vertical separation such as a double quote (“) is grabbed as a whole character rather than separate characters. On your source surface simply use the trans colour to fill any vertical separation in such characters and when grabbed the character will be grabbed whole and the trans colour changed into the key colour ready for use. Note that this means your trans colour is always transparent as far as the final use of the font is concerned i.e. you cannot also use trans as one of the colours in a multi-coloured font. If no trans colour is required, simply set trans to the same value as key. If your surface is unmodifiable you MUST do this or GrabFont() will fail i.e. if your font is on an unmodifiable surface then your characters must be such that no trans colour is required. If GrabFont() fails to set the surface ColourKey to key then it returns PTSPRITES_SETKEY_ERROR. If the key and trans passed in your call to GrabFont() are different and the PTDevFontSurface is unmodifiable then GrabFont() returns PTSURF_NOTMOD_ERROR. If GrabFont() fails reading the surface data then it returns PTSPRITES_READPIX_ERROR. If no graphics are found on the surface or the number of characters in different font styles differs then GrabFont() returns PTSPRITES_NUMSPRITES_ERROR. If GrabFont() is unable to allocate memory for the font then it returns PTSPRITES_MEM_ERROR. SetFontBase() SetFontBase() is twice overloaded: HRESULT SetFontbase(char c) void SetFontbase(DWORD n) SetFontBase(char c) sets the font baseline offset to the base of specified char (from the top of the tallest char), this version sets the offsets individually for fonts with multiple styles. If there is no grabbed font or the character specified is outside the font’s character range then SetFontBase(char c) will return PTSPRITES_NUMSPRITES_ERROR. SetFontBase(DWORD n) sets all the font baseline offsets to the number of pixels specified by n (from the top of the tallest character in the font), the offsets being set the same for each style in fonts with multiple styles. AddFont() long AddFont() AddFont() adds the font for this PTDevFontSurface() to the PTDev table of fonts, enabling you to use the font in the PTDevSurface::DrawText() function. If the font is added to the font table successfully then AddFont() returns the font reference number for use in DrawText(). At the moment you may add up to a maximum of 40 fonts to the font table and the font reference number returned will be between 0 and 39 unless adding the font fails for any reason (e.g. 40 fonts already added) in which case AddFont() returns 40 or more i.e. if AddFont() returns 40 or more then the AddFont() operation has failed. FreeFont() void FreeFont() FreeFont() frees up all memory and resources associated with the font including removing the font from the PTDev font table if necessary as well as freeing up the surface memory if it was originally allocated by the CreateSurface() function. PTDevSpriteSurface : PTDevSurface PTDevSpriteSurface is a class (derived from the PTDevSurface base class) for handling surfaces of sprites (graphics to be moved/animated etc.). Using PTDevSpriteSurface has 4 main parts: Instantiating a sprite surface Creating a sprite surface Manipulating/using the sprite surface Deleting the sprite surface Instantiating a sprite surface requires an existing PTDev object, use for example: sprites=new PTDevSpriteSurface(app_pPTDev); Deleting a sprite surface is also straightforward, for example: delete sprites; Since it is a derived class, PTDevSpriteSurface objects inherit all the functions available to PTDevSurface objects. To create a sprite surface use CreateSurface() as for any PTDevSurface. The extra functions available in PTDevSpriteSurface itself are specifically for handling surfaces of sprite graphics: GrabGfx() HRESULT GrabGfx(COLORREF key, COLORREF trans) GrabGfx() creates a Graphics Table of all the separate graphics it finds on the sprite surface. A graphic is considered to be separate if there is a rectangular outline of pixels in the key colour surrounding it. If you have some graphics with clear vertical or horizontal gaps within what is an individual graphic then you must join the separate sections using the trans colour in order for GrabGfx() to consider the object a single graphic. As such an object is grabbed, any pixels in the trans colour are changed to the key colour so they will not be part of the graphic when blitted with the ColourKey enabled. If none of your objects require use of the trans colour in this manner then simply pass the same value for trans as for key. If you do need to use a separate trans colour then that colour must not be used in the actual graphics themselves in the same way that you cannot use the key colour as part of a graphic – in fact you cannot use colours that are the same as the key or trans in a graphic when all values are converted to the surface format (currently RGB 565). If trans is different from key, then because GrabGfx() modifies any trans colour found to be key colour, you cannot GrabGfx() on an unmodifiable surface. Any previous Graphics Table for the sprite surface is removed by the call to GrabGfx() even if GrabGfx() fails and any memory for the previous table that was allocated by a PTDevSpriteSurface object is freed if it is not in use by any other PTDevSpriteSurface object/s. The Graphics Table created is flagged as modifiable. The grab algorithm works top-left to bottom-right in rows, a row is considered to include any graphic (not already found) that overlaps vertically speaking with any other graphic (not yet found) in the row but does not overlap horizontally with any graphic (not yet found) above it, this is illustrated in the following graphic giving the relevant order in which the graphics are grabbed:  This algorithm allows you to make best use of the surface whilst still having control over the order in which the graphics are grabbed. If the sprite surface is invalid then GrabGfx() returns PTSPRITES_SURF_ERROR. If setting the ColourKey to key fails then GrabGfx() returns PTSPRITES_SETKEY_ERROR. If GrabGfx() is unable to allocate sufficient memory then it returns PTSPRITES_MEM_ERROR. If GrabGfx() fails when reading the surface data then it returns PTSPRITES_READPIX_ERROR. If GrabGfx() fails when writing to the surface data then it returns PTSPRITES_SETPIX_ERROR. If trans is different from key and the surface is unmodifiable then GrabGfx() will return PTSURF_NOTMOD_ERROR. If any other error occurs GrabGfx() will return PTSPRITES_INTERNAL_ERROR. CheckGfx() HRESULT CheckGfx() CheckGfx() checks that the Graphics Table is valid for a sprite surface. If the surface is invalid then GrabGfx() returns PTSPRITES_SURF_ERROR. If any of the source area rectangles in the table extend off the sprite surface or if any are overlapping then GrabGfx() returns PTSPRITES_DATA_ERROR. SetResGfx() HRESULT SetResGfx(HINSTANCE hinst, TCHAR*id) SetResGfx() lets you set use a Graphics Table stored as a resource (having previously been saved using PTDevSpriteSurface::SaveGfx() and then included as a “PTSpriteRects” resource type). hinst should be a handle to the module whose executable file contains the resource. If using PTDevApp this is app_hInst for your application executable. Simply use hinst to specify the module handle and id to specify the name of your PTSpriteRects resource. The Graphics Table is flagged as unmodifiable since resource memory may not be modified on mobile devices. Any previous Graphics Table for the sprite surface is removed by the call to SetResGfx() even if SetResGfx() fails and any memory for the previous table that was allocated by a PTDevSpriteSurface object is freed if it is not in use by any other PTDevSpriteSurface object/s. Any previous Graphics Table for the sprite surface is removed by the call to SetResGfx() even if SetResGfx() fails and any memory for the previous table that was allocated by a PTDevSpriteSurface object is freed if it is not in use by any other PTDevSpriteSurface object/s. If SetResGfx() fails to find, load or lock your resource then it will return PTSPRITES_RES_FIND_ERROR, PTSPRITES_RES_LOAD_ERROR or PTSPRITES_RES_LOCK_ERROR respectively. If SetResGfx() fails to set the ColourKey for the sprite surface to that stored with the Graphics Table then SetResGfx() returns PTSPRITES_SETKEY_ERROR. If the surface is invalid then SetResGfx() returns PTSPRITES_SURF_ERROR. If any of the source area rectangles in the table extend off the surface or if any are overlapping then SetResGfx() returns PTSPRITES_DATA_ERROR. SetGfx() SetGfx() is twice overloaded: HRESULT SetGfx(PTGraphic* source, DWORD num, BOOL mod, COLORREF key) HRESULT SetGfx(PTDevSurface* pSurf, COLORREF key) The first version allows you to specify your own array of PTGraphic data for use with the PTDevSpriteSurface and whether it is modifiable or not, using mod. Simply supply a pointer to your table of PTGraphic data as source, the number of structures as num, specify whether the data is modifiable or not using mod and the ColourKey to be used using key. The second version of SetGfx() allows you to set the PTDevSpriteSurface object to use the same Graphics Table as another PTDevSpriteSurface object, simply supply a pointer to the other PTDevSpriteSurface as pSurf and a value for the ColourKey as key (i.e. this surface need not use the same ColourKey as the other). For either version of SetGfx(): Any previous Graphics Table for the sprite surface is removed by the call to SetGfx() even if SetGfx() fails and any memory for the previous table that was allocated by a PTDevSpriteSurface object is freed if it is not in use by any other PTDevSpriteSurface object/s. If SetGfx() is unable to set the surface ColourKey then it will return PTSPRITES_SETKEY_ERROR. If the surface is invalid then SetGfx() returns PTSPRITES_SURF_ERROR. If any of the source area rectangles in the table extend off the surface or if any are overlapping then SetGfx() returns PTSPRITES_DATA_ERROR. For the second version of SetGfx(): The Graphics Table for the surface is flagged to the same modifiable state as the Graphics Table for pSurf. If there is an error with the Graphics Table data from the source sprite surface specified by pSurf then SetGfx() will return PTSURF_NOSURF_ERROR. LoadGfx() HRESULT LoadGfx(const TCHAR* file) LoadGfx() allows you to load in a Graphics Table for the surface from the file with filename file previously saved using PTDevSpriteSurface::SaveGfx(). Any previous Graphics Table for the sprite surface is removed by the call to LoadGfx() even if LoadGfx() fails and any memory for the previous table that was allocated by a PTDevSpriteSurface object is freed if it is not in use by any other PTDevSpriteSurface object/s. The loaded Graphics Table is flagged as modifiable. If LoadGfx() has problems opening the file, with the file size or reading the file then it will return either PTSPRITES_FILE_OPEN_ERROR, PTSPRITES_FILE_SIZE_ERROR or PTSPRITES_FILE_READ_ERROR respectively. If LoadGfx() is unable to allocate the memory required for the Graphics Table then it will return PTSPRITES_MEM_ERROR. If the surface is invalid then LoadGfx() returns PTSPRITES_SURF_ERROR. If any of the source area rectangles in the table extend off the sprite surface or if any are overlapping then LoadGfx() returns PTSPRITES_DATA_ERROR. SaveGfx() HRESULT SaveGfx(const TCHAR* file) SaveGfx() allows you to save the Graphics Table for the surface as a file with filename file. You may then either include this file as a PTSpriteRects resource for use with a sprite surface using SetResGfx() or use the LoadGfx() function to reload it for use with a sprite surface. If there is no Graphics Table for the surface or the number of graphics is zero then SaveGfx() will return PTSPRITES_DATA_ERROR. If SaveGfx() is unable to get the ColourKey for the surface then it will return PTSPRITES_READKEY_ERROR. If SaveGfx() is unable to open the file or fails when writing to the file then it will return PTSPRITES_FILE_OPEN_ERROR or PTSPRITES_FILE_WRITE_ERROR respectively. GetNumGfx() DWORD GetNumGfx() GetNumGfx() simply returns the number of PTGraphic objects in the Graphics Table for the surface, if there is no Graphics Table it will return zero. ChangeOffsets() HRESULT ChangeOffsets(DWORD num, long xadd, long yadd) ChangeOffsets() allows you to modify the offsets to the animation centre of a sprite with respect to the rotation centre by specifying a change to the x offset as xadd and a change to the y offset as yadd, num giving the number of the sprite in the Graphics Table. If the Graphics Table is flagged as not modifiable then ChangeOffsets() will return PTSPRITES_MEM_PROTECT_ERROR. If num specifies a value beyond the number of entries in the Graphics Table (or there is no Graphics Table) then ChangeOffsets() will return PTSPRITES_NUMSPRITES_ERROR. ChangeSize() HRESULT ChangeSize(DWORD num, long xadd, long yadd) ChangeSize() allows you to modify the size of the animation rectangle of the sprite by specifying a change to the width as xadd and a change to the height as yadd, num giving the number of the sprite in the Graphics Table. If the Graphics Table is flagged as not modifiable then ChangeSize() will return PTSPRITES_MEM_PROTECT_ERROR. If num specifies a value beyond the number of entries in the Graphics Table (or there is no Graphics Table) then ChangeSize() will return PTSPRITES_NUMSPRITES_ERROR. SetOffsets() HRESULT SetOffsets(DWORD num, long xoff, long yoff) SetOffsets() lets you specify the offsets to the animation centre of a sprite, given as Graphics Table entry num, with respect to the rotation centre as xoff and yoff. If the Graphics Table is flagged as not modifiable then SetOffsets() will return PTSPRITES_MEM_PROTECT_ERROR. If num specifies a value beyond the number of entries in the Graphics Table (or there is no Graphics Table) then SetOffsets() will return PTSPRITES_NUMSPRITES_ERROR. SetSize() HRESULT SetSize(DWORD num, long width, long height) SetSize() lets you specify the width and height of the animation rectangle of the sprite given as entry num in the Graphics Table. If the Graphics Table is flagged as not modifiable then SetSize() will return PTSPRITES_MEM_PROTECT_ERROR. If num specifies a value beyond the number of entries in the Graphics Table (or there is no Graphics Table) then SetSize() will return PTSPRITES_NUMSPRITES_ERROR. PTDevAnimation The PTDevAnimation class is not yet fully finished or tested., for now please see the header (.h) files. PTDevAnimated The PTDevAnimated class is not yet fully finished or tested, for now please see the header (.h) files. PTDevSound PTDevSound is a class to provide sound handling for your applications. If using PTDevApp then instantiating PTDevSound is done in the Run() function, if not it should be instantiated after the PTDev class, using for example: app_pSound=new PTDevSound(); The functions in PTDevSound are as follows: InitSoundPT() HRESULT InitSoundPT(DWORD dwMaxSounds, WORD nChannels, DWORD nSamplesPerSec, DWORD dwBufferTicks, WORD wBitsPerSample, DWORD dwVolumeL, DWORD dwVolumeR) InitSoundPT() initialises the PTDevSound object to: allow up to a maximum of dwMaxSounds, use either mono (1) or stereo (2) playback as specified by nChannels, playback at nSamplesPerSec, use a playback buffer dwBufferTicks milliseconds in length, use either 8 or 16 bit sample replay as specified by wBitsPerSample and play at dwVolumeL on the left channel (or both if mono) and dwVolumeR on the right channel (if stereo). There is currently a maximum of 8 for dwMaxSounds in the demo version of PTDev, the maximum in the licensed version is 32, in either case it's best to limit the value to the minimum your application requires so that sound playback consumes the least processor time and available memory. nSamplesPerSec has an absolute minimum of 4000 and a maximum of 44100 and in practice most (all?) devices accept 11025, 22050 or 44100. The buffer length dwBufferTicks needs to be set to a large enough value such that the buffer replay does not loop within successive calls to PlaySoundPT(), the value is limited to a minimum of 20 and a maximum of 1000. In practice it's best to set dwBufferTicks to twice the maximum number of milliseconds a single frame update of your application is going to take. Larger values of dwBufferTicks do NOT cause lag in the playback of a new sound when it is triggered but do cause lags in the time taken for playback to respond to dynamic changes in the volume or pitch of a given sound (also note that larger values will use more memory). Your source samples may be mono or stereo, 8-bit or 16-bit irrespective of how you set the playback. Normal "maximum" volume for dwVolumeL and dwVolumeR is 0x100 (256) but you can use larger values up to 0xffff (65535) as well as smaller. The mixer mixes in 32-bit mode so "square-waving" due to too much volume is limited to a minimum. If you are using PTDevApp then calling InitSoundPT() is taken care of in Run() using the values from your config as set in your WinMain() otherwise you need to call InitSoundPT() before any calls are made to the other PTDevSound functions. If sound playback is already initialised/operative then InitSoundPT() returns S_FALSE. If dwMaxSounds==0 or nChannels==0 or nChannels>2 or nSamplesPerSec>44100 or nSamplesPerSec<4000 or (wBitsPerSample!=8 and wBitsPerSample!=16) then InitSoundPT() returns MC_BADFORMAT. If dwBufferTicks<20 then InitSoundPT() returns MC_BUFFERSHORT and if dwBufferTicks>1000 then InitSoundPT() returns MC_BUFFER_LONG. If dwVolumeL>0x1000 or stereo playback is requested and dwVolumeR>0x1000 then InitSoundPT() returns MC_TOOLOUD. If no wave out device is found in the hardware then InitSoundPT() returns MC_NOSOUND. If InitSoundPT() is unable to allocate the memory required it will return MC_NOMEM. StartSoundPT() HRESULT StartSoundPT(HWND hwnd) StartSoundPT() actually starts the sound buffer playing, you must call it after InitSoundPT() before attempting to play any samples. Each time your application is minimised, if you do not wish playback to continue, a call should be made to StopSoundPT() which means that when your application is restored another call needs to be made to StartSoundPT(). If using PTDevApp this is taken care of, otherwise you should make explicit calls to StopSoundPT() and StartSoundPT() as necessary. If StartSoundPT() is successful, or sound playback was already started, or if sound playback has not been initialised using InitSoundPT() then StartSoundPT() returns the current state flags for the PTDevSound object (i.e. a positive value). If StartSoundPT() is unable to open the wave out device or unable to interrogate the wave out device then it will close sound output and return MC_NOSOUND (a negative value). PlaySoundPT() HRESULT PlaySoundPT() PlaySoundPT() updates the sound output buffer with any sounds currently being played. PlaySoundPT() should be called often enough such that successive calls to PlaySoundPT() are made without the playback buffer looping, this means that successive calls should be made more often then the time set for the playback bufferlength (dwBufferTicks in InitSoundPT()). In practice it’s best to ensure that the time between successive calls to PlaySoundPT() is half that of the time for the buffer to loop (i.e. dwBufferTicks/2 milliseconds). If you are using PTDevApp then PlaySoundPT() is called within Run() once per frame update of your application. If not using PTDevApp you should do something similar e.g. calling PlaySoundPT() once per frame update of your application. Note that extra calls can be made to PlaySoundPT() to avoid the buffer looping, the only negative effect of this is the extra processor time taken for the extra buffer updates. If PlaySoundPT() is successful, or sound playback is not initialised or is disabled then PlaySoundPT() returns the current state flags for the PTDevSound object (i.e. a positive value). The only possible error (negative) return value from PlaySoundPT() is MC_RESTART_ERROR which may occur if the device has been switched off and on again while the application was running and sound playback was active, even then it shouldn’t happen. StopSoundPT() void StopSoundPT() StopSoundPT() stops sound playback completely, so that an explicit call to StartSoundPT() is required before sound will be played again. If your application is using sound then StopSoundPT() should be called each time your application is minimised if you wish sound output to stop, requiring that StartSoundPT() be called when your application is restored from being minimised. If using PTDevApp then StopSoundPT() is called from within PTDevApp when your application is minimised (if your application is set to be inactive when minimised), if not using PTDevApp then you need to make an explicit call to StopSoundPT() when your application is minimised if you wish sound to stop. PauseSoundPT() HRESULT PauseSoundPT() PauseSoundPT() pauses replay of all current sounds, however any new sounds triggered will be played unless they are started with the PTStartPaused flag set. If sound playback is not already initialised using InitSoundPT() then PauseSoundPT() returns MC_NOTINITIALISED. If sound playback has not been started using StartSoundPT(), or has been stopped using StopSoundPT() then PauseSoundPT() will return MC_STOPPED. RestoreSoundPT() HRESULT PTDevSound::RestoreSoundPT() RestoreSoundPT() will unpause all sound channels, irrespective of why each was paused. If sound playback is not already initialised using InitSoundPT() then RestoreSoundPT() returns MC_NOTINITIALISED. If sound playback has not been started using StartSoundPT(), or has been stopped using StopSoundPT() then RestoreSoundPT () will return MC_STOPPED. PlayWavPT() MCCHANNEL PlayWavPT(void* pWav, DWORD dwLength, DWORD dwVolumeL, DWORD dwVolumeR, DWORD flags, MCCHANNEL nChannel, DWORD dwNumLoops, DWORD nSamplesPerSec, long iRateChange) PlayWavPT() instructs PTDevSound to start playing the plain PCM wav format buffer (including wav header) located at address pWav. dwLength should specify the total length of the wav buffer (including the header). dwVolumeL and dwVolumeR set the relative volume at which this sound should be played (dwVolumeR is ignored if both the wave and playback are mono). flags may contain the following binary flags: PTPlayAlways PTPlayOverLoop PTPlayFixed PTStartPaused PTFreqOverride PTPlayLoop PTPlayReserved If PTPlayAlways is set then if none of the current sound channels are free this sound will replace the oldest non-reserved, non-looping channel. If no such channel exists then PlayWavPT() will return MC_NOCHANNEL. If PTPlayOverLoop is set then if none of the current