DirectX API 编程起步 #02 窗口的诞生
在这篇文章里我们先用 windows API 制作一个窗口出来,以后再用 DirectX API 渲染的东西就会显示在这里,控制台那黑白的画面肯定是没法用的。
每次的代码都会更新到Github
首先贴出来目前为止的文件结构图,由上到下表示#include“XXXXX”关系
系统头文件的调用不包含在内
由于.h和.cpp都是对应出现的,我就不写的那么详细了
Main.cpp 是调用 SoftwareClass 类的主函数。
那么我们从上往下开始吧。
Main.cpp
由于只用调用接下来的类成员函数就行,所以这个代码非常简单。
////////////////
// Main.cpp //
////////////////
#include"SoftwareClass.h" /*********************************
这里是整个程序的入口函数
WinMain
仅适用于Win32编程
**********************************/ int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR pScmdline,int nCmdshow)
{
//新建类指针
SoftwareClass *Software;
//new一个类出来
Software = new SoftwareClass;
//初始化、运行、结束该程序
if (Software->Initialize())
{
Software->Run();
}
Software->Shutdown();
//删除并清理类指针
delete Software;
Software = NULL;
return ;
}
SoftwareClass
接下来就是重点的主要类SoftwareClass,它管理着这个程序的生杀大权,并调用InputClass(记录输入的类)和GraphicsClass(渲染图形的类)来完成更高级的操作。
首先是他的header
SoftwareClass.h
////////////////////////
// SoftwareClass.h //
/////////////////////// /*******************************
该类包含整个程序运行所需的功能
********************************/ #ifndef _SOFTWARECLASS_H_
#define _SOFTWARECLASS_H_ //////////////
// include //
//////////////
#include<Windows.h> //////////////////
// File include //
//////////////////
#include"InputClass.h"
#include"GraphicsClass.h" /////////////////////////
// Class Declaration //
/////////////////////////
class SoftwareClass
{
public:
//默认构造,复制,析构函数
SoftwareClass();
SoftwareClass(const SoftwareClass&);
~SoftwareClass(); bool Initialize();//初始化
void Shutdown();//关闭
void Run();//运行 //主要消息处理函数
//系统级消息丢给另外的一个WndProc
//比如窗口的关闭等消息
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM); //以下为私有成员函数
private:
bool Frame();
//创建窗口最重要的函数
void InitializeWindows(int&, int&);
void ShutdownWindows();
//以下为私有数据成员
private:
//创建窗口程序需要的参数,无需过度关心
LPCWSTR m_SoftwareName;
HINSTANCE m_hinstance;
HWND m_hwnd; //m_* 代表成员数据
InputClass *m_Input;
GraphicsClass *m_Graphics;
}; ////////////////////////
// Static Function //
/////////////////////// //次要消息处理函数
//用于处理系统级消息
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /////////////
// Global //
///////////// //用于消息处理函数的调用
//因为我们有两个
//所以需要这个静态变量指向该类
static SoftwareClass *SoftwareHandle = NULL; #endif
SoftwareClass.cpp
接着是他的.cpp
///////////////////////////
// SoftwareClass.cpp //
//////////////////////////
#include "SoftwareClass.h" //////////////////////////////////////////////////////////
SoftwareClass::SoftwareClass()
{
m_hinstance = NULL;
m_hwnd = NULL;
m_SoftwareName = NULL; m_Input = NULL;
}
SoftwareClass::SoftwareClass(const SoftwareClass &other)
{
}
SoftwareClass::~SoftwareClass()
{
}
////////////////////////////////////////////////////////// bool SoftwareClass::Initialize()
{
int screenWidth, screenHeight;
bool result; screenHeight = ;
screenWidth = ;
InitializeWindows(screenWidth, screenHeight); //new一个输入处理类
m_Input = new InputClass;
if (!m_Input)
{
return false;
}
m_Input->Initialize(); //new一个图形处理类
m_Graphics = new GraphicsClass;
if (!m_Graphics)
{
return false;
} //由于图形类涉及到窗口的创建
//容易失败
//因此测试一下new是否成功
result = m_Graphics->Initialize(screenWidth, screenHeight, m_hwnd);
if (!result)
{
return false;
} return true;
} //先清除输入类和图形类
//再关闭窗口程序
void SoftwareClass::Shutdown()
{
if (m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = NULL;
} if (m_Input)
{
delete m_Input;
m_Input = NULL;
} ShutdownWindows();
} //消息的翻译分配在此
void SoftwareClass::Run()
{
MSG msg;
bool done, result;
done = false; ZeroMemory(&msg, sizeof(MSG)); //程序的最主要循环
//不停地渲染、输出画面
while (!done)
{
//消息队列的查找
if (PeekMessage(&msg, NULL, , , PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} //这说明PostQuitMessage被调用了
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
result = Frame();
if (!result)
{
done = true;
}
}
}
} LRESULT SoftwareClass::MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
m_Input->KeyDown((unsigned int)wParam); //当ESC被按下时,退出程序
if (wParam == VK_ESCAPE)
{
PostQuitMessage();
}
return ;
case WM_KEYUP:
m_Input->KeyUp((unsigned int)wParam);
return ;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
} bool SoftwareClass::Frame()
{
bool result; result = m_Graphics->Frame();
if (!result)
{
return false;
}
return true;
} //窗口程序的创建,注册,显示
void SoftwareClass::InitializeWindows(int &screenWidth, int &screenHeight)
{
WNDCLASSEX wc = {};
DEVMODE dmScreenSettings;
int posX, posY; //赋值那个静态变量
//指向该类
SoftwareHandle = this;
//别管
m_hinstance = GetModuleHandle(NULL);
//由于Unicode的原因
//所有字符串要用 TEXT() 括起来
m_SoftwareName = TEXT("MyShabbyEngine"); //填写对象wc的有关信息
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
//该窗口的消息处理函数
wc.lpfnWndProc = WndProc;
//以下全部不用管
wc.cbClsExtra = ;
wc.cbWndExtra = ;
wc.hInstance = m_hinstance;
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hCursor = NULL;
wc.lpszMenuName = NULL;
//设置程序窗口背景
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
//类名,意义不明
wc.lpszClassName = m_SoftwareName;
//这步绝不能漏了
wc.cbSize = sizeof(WNDCLASSEX); //向系统注册该窗口
RegisterClassEx(&wc); //从系统得到显示的分辨率
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN); //如果GraphicsClass文件里设置为全屏
if (FULL_SCREEN)
{
memset(&dmScreenSettings, , sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = ;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN); posX = posY = ;
}
else
{
screenWidth = ;
screenHeight = ; posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / ;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / ;
} //在显示屏创建窗口
//无边框
m_hwnd = CreateWindowEx(WS_EX_APPWINDOW,
m_SoftwareName, m_SoftwareName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight,
NULL, NULL, m_hinstance, NULL); //将窗口显示出来
ShowWindow(m_hwnd, SW_SHOW);
SetFocus(m_hwnd); ShowCursor(false);
} void SoftwareClass::ShutdownWindows()
{
//显示鼠标指针
ShowCursor(true); if (FULL_SCREEN)
{
ChangeDisplaySettings(NULL, );
} DestroyWindow(m_hwnd);
m_hwnd = NULL; UnregisterClass(m_SoftwareName, m_hinstance);
m_hinstance = NULL; SoftwareHandle = NULL;
} LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_DESTROY:
case WM_CLOSE:
PostQuitMessage();
return ;
default:
return SoftwareHandle->MessageHandler(hWnd, Msg, wParam, lParam);
}
}
InputClass
该类监控并记录哪些键被按下
InputClass.h
////////////////////
// InputClass.h //
/////////////////// /******************************
该类包含记录输入按键的功能
******************************/ #ifndef _INPUTCLASS_H_
#define _INPUTCLASS_H_ /////////////////////////
// Class Declaration //
/////////////////////////
class InputClass
{
public:
//默认构造、复制、析构函数
InputClass();
~InputClass();
InputClass(const InputClass&);
//初始化
void Initialize();
//当按键被按下或抬起时调用
void KeyDown(unsigned int);
void KeyUp(unsigned int);
//检测某键是否被按下
bool IsKeyDown(unsigned int);
private:
//储存哪些键被按下
//true表示正被按下
bool m_keys[];
}; #endif
Input.cpp
////////////////////
// InputClass.cpp //
///////////////////
#include "InputClass.h" InputClass::InputClass()
{
}
InputClass::~InputClass()
{
}
InputClass::InputClass(const InputClass &other)
{
} //初始化按键表
void InputClass::Initialize()
{
int i;
for (i = ; i < ; i++)
{
m_keys[i] = false;
}
} void InputClass::KeyDown(unsigned int input)
{
//将该键设为true
m_keys[input] = true;
} void InputClass::KeyUp(unsigned int input)
{
//将该键设为false
m_keys[input] = false;
} bool InputClass::IsKeyDown(unsigned int key)
{
return m_keys[key];
}
GraphicsClass
最后是GraphicsClass,由于目前只做了窗口的显示,其实还并未涉及到任何 DirectX 的代码,所以这个类基本上是空的。
GraphicsClass.h
/////////////////////////
// GraphicsClass.h //
/////////////////////// /***********************
该类处理图像
********************/ #ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_ //////////////
// include //
//////////////
#include<Windows.h> /////////////
// Global //
///////////// //是否全屏显示
const bool FULL_SCREEN = false;
//是否垂直同步
const bool VSYNC_ENABLED = true;
//场景相关数据
const float SCREEN_DEPTH = 1000.0;
const float SCREEN_NEAR = 0.1f; /////////////////////////
// Class Declaration //
////////////////////////
class GraphicsClass
{
public:
GraphicsClass();
GraphicsClass(const GraphicsClass&);
~GraphicsClass(); bool Initialize(int, int, HWND);
void Shutdown();
bool Frame();
private:
bool Render();
}; #endif
GraphicsClass.cpp
///////////////////////////
// GraphicsClass.cpp //
//////////////////////////
#include "GraphicsClass.h" GraphicsClass::GraphicsClass()
{
} GraphicsClass::GraphicsClass(const GraphicsClass &other)
{
} GraphicsClass::~GraphicsClass()
{
} bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hWnd)
{
return true;
} void GraphicsClass::Shutdown()
{
} bool GraphicsClass::Frame()
{
return true;
} bool GraphicsClass::Render()
{
return true;
}
最后程序正确运行后,会在屏幕中间产生一个黑色的矩形,没有边框,也没有鼠标指针。按ESC可退出。
我知道。。。光贴代码屁用没有。。。。。日后补上注释
DirectX API 编程起步 #02 窗口的诞生的更多相关文章
- DirectX API 编程起步 #01 项目设置
=========================================================== 目录: DirectX API 编程起步 #02 窗口的诞生 DirectX A ...
- Flink Program Guide (2) -- 综述 (DataStream API编程指导 -- For Java)
v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VM ...
- Mysql C语言API编程入门讲解
原文:Mysql C语言API编程入门讲解 软件开发中我们经常要访问数据库,存取数据,之前已经有网友提出让鸡啄米讲讲数据库编程的知识,本文就详细讲解如何使用Mysql的C语言API进行数据库编程. ...
- ASP.NET Web API编程——路由
路由过程大致分为三个阶段: 1)请求URI匹配已存在路由模板 2)选择控制器 3)选择操作 1匹配已存在的路由模板 路由模板 在WebApiConfig.Register方法中定义路由,例如模板默认生 ...
- 黑客编程教程(二)Win API编程简介
第二节 Win API编程简介 下面介绍一下WIN API. 我们需要自己编写一个工具时,必然会用到很多操作windows和控制windows的函数,这些函数就是windows API. API是Ap ...
- 浅谈Windows API编程
WinSDK是编程中的传统难点,个人写的WinAPI程序也不少了,其实之所以难就难在每个调用的API都包含着Windows这个操作系统的潜规则或者是windows内部的运行机制…… WinSDK是编程 ...
- Maya API编程快速入门
一.Maya API编程简介 Autodesk® Maya® is an open product. This means that anyone outside of Autodesk can ch ...
- 第23 章 : Kubernetes API 编程范式
Kubernetes API 编程范式 需求来源 首先我们先来看一下 API 编程范式的需求来源. 在 Kubernetes 里面, API 编程范式也就是 Custom Resources Defi ...
- Team Foundation API - 编程访问 WorkItem
Team Foundation Server (TFS)工具的亮点之一是管理日常工作项, 工作项如Bug, Task,Task Case等. 使用TFS API编程访问TFS服务器中的工作项, 步骤如 ...
随机推荐
- c#开发工具软件集合
visual studio 2015(自带Nuget) Resharper de4dot dnspy ILMergeGui Git 大漠插件3.1233 天使插件v4.019 Navicat_Prem ...
- sql server:compare data from two tables
--Comparing data between two tables in SQL Server --Create two Tables-- CREATE TABLE TableA(ID Int, ...
- [PHP] 自定义错误处理
关闭掉默认的错误提示,注册自己的错误提示 Application.php <?php class Application{ public static function main(){ head ...
- javascript 之正则匹配HTML
正则表达式 <(\S*?) [^>]*>.*?</\1>|<.*? /> 匹配 <html>hello</html>|<a> ...
- Hibernate的缓存技术详解
转载注明出处:http://www.cnblogs.com/xiaoming0601/p/5882980.html 一.什么是缓存: 并不是指计算机的内存或者CPU的一二级缓存:缓存是指为了降低应用程 ...
- Android开发中的问题及相应解决(持续更新)
最近博客写的少了,以后还得经常更新才行. ------------------------------------------------------------ 1.特定业务需求下try cath ...
- [Design Pattern] Substitute Interface
[Design Pattern] Substitute Interface 目的 将对象的成员建立为替身接口的成员,用来解耦对象之间的循环相依. 情景 假设开发人员接手一个系统,在系统里有订单对象.送 ...
- Eclipse反编译工具Jad及插件JadClipse配置
Jad是一个Java的一个反编译工具,是用命令行执行,和通常JDK自带的java,javac命令是一样的.不过因为是控制台运行,所以用起来不太方便.不过幸好有一个eclipse的插件JadClipse ...
- 回车键和button按钮都绑定同一个事件,如何避免按回车的时候button重复点击
保存一个全局变量,用来记录Button的焦点状态 <button onclick="login();" onfocus="window.buttonIsFocuse ...
- Sharepoint学习笔记—习题系列--70-573习题解析 -(Q104-Q106)
Question 104You plan to create a workflow that has the following three activities: CreateTask OnTask ...