You are currently browsing the 梦许之地 – WONDERLAND blog archives for December, 2007.

Archive for December, 2007

Step First D3D

Saturday, December 29th, 2007

目标, 在.NET 2.0 的托管窗口中框出一块区域进行D3D 绘画. 所谓绘画, 为了减少代码, 暂时定义为纯色屏…

DirectX SDK: 2007 June

Documents:

  • DirectX Documentation for C++
  • DirectX Documentation for Managed Languages (.NET 1.1)
  • Introduction to 3D Game Programming with DirectX 9.0

Samples:

  • DirectX Sample Browser — Tutorial 1: Create a Device

问题的关键就在于, 如何在.Net 的托管环境下使用DirectX, 在托管窗口(Windows::Form) 中进行3D 绘画. 我们有两个选择, 一是使用托管的DirectX (Managed DirectX), 另一种方法是使用Native DirectX (有时候是必须的无奈啊…).

无论是使用托管的, 还是原生的DX, 最核心的, 也是最初的步骤, 都是需要初始化一个D3D 的Device, 使得我们能够通过该Device 来进行3D 绘画.

I. 托管DX 的Device 初始化

以一个基于C++/CLI 的Windows Form Application 为例, 为了获得DX支持, 我们必须添加如下三个.Net References

  • Microsoft.DirectX
  • Microsoft.DirectX.Direct3D
  • Microsoft.DirectX.Direct3DX (Version: 1.0.2911.0)

这三个Reference, 在安装了DirectX 的SDK 后, 会出现在Project->Add Reference->.Net 下. 需要主意的是, 托管的DX 是基于.Net 1.1 的Runtime 的, 在.Net 2.0 和VS 2005 的环境下使用时会抛出一个LoderLock 的Exception. LoadLocker 是VS 2005 引入的MDA (Managed Debugging Assistant) 中的一个, 被设计用来寻找Debug 时一些较难发现的Runtime 问题. 所有的.Net 1.1 的DX 程序集在VS 2005 下都会触发这个Exception (仅在Debugger 下). 暂时的解决方法有三个:

  1. 使用VS 2003 和.Net 1.1 (不是办法的办法 =.=)
  2. 使用MDX 2.0 (要注意的是, MDX 2.0 计划已经被终止, 实际上MDX 2.0已经被Transform 到XNA Framwork)
  3. 禁止VS 2005 Debugger 的LoadLocker Exception (Debug->Exceptions, 去掉LoadLocker 前的钩)

在完成了上面3个步骤中的任何一个以后, 我们就可以专心于我们的托管DX 代码了. 在托管环境下, 我们初始化一个Device 的步骤如下:

  1. 创建一个PresentParameters^ 的对象并填充它.
  2. 创建一个Device^ 对象.

最简单的代码片断如下:

try {
PresentParameters^ paras = gcnew PresentParameters();
paras->Windowed = true;
paras->SwapEffect = SwapEffect::Discard;
Device^ device = gcnew Device(0, DeviceType::Hardware, AControl, CreateFlags::HardwareVertexProcessing, paras);
} catch(DirectXException^ e) {
//Do Something
}

事实上, PresentParameters 定义了很多字段, 完整列表可以参考DX SDK 的帮助文件(Mananged Language 版本).

Device 的构造函数有四个, 例子中使用的原型为:

Device (
int adapter,
DeviceType deviceType,
Control^ renderWindow,
CreateFlags behaviorFlags,
array<PresentParameters^>^ presentationParameters
);

其中adapter 为显卡的编号, 0 代表默认的主显卡( 就是目前在用的那块); deviceType 是DeviceType 的一个枚举类型; renderWindow 可以替换为需要绘图的区域/窗体, 比如一个Form, 一个Panel 等, 类型为Control^; behaviorFlags 是CreateFlags 的一个枚举类型, presentationParameters 就是我们之前创建的用来描述Device 的PresentParameters 的一个实例. 在创建Device 之前, 必须确定显卡支持这些特性, 完整的支持列表和参数可以参考DX 帮助和显卡制造商的说明.

在Device 创建完成后, 就可以使用该Device 进行图形绘制. 最简单的, 绘制一个纯色屏幕, 或者说清屏, 代码如下:

device->Clear(ClearFlags::Target, Color::SkyBlue, 1.0f, 0);
device->BeginScene();
//You can do something here to draw 3D stuff
device->EndScene();
device->Present();

Clear 方法将Device 所指定的区域填充为纯色, 例子中为天蓝色. Clear 的原型有四个, 例子中的为:

void Clear ( ClearFlags flags, Color color, float zdepth, int stencil );

其中flags 是一个ClearFlag 枚举, 用来指定要清除的表面; color 是一个Color 枚举.

我们可以将该清屏代码放入Control 的Paint 事件函数中, 这样每次Control 被Repaint, 就会被Clear 为指定的纯色, 或者某个3D 图形( 如果有的话).

至此, Managed DX 和C++/CLI 工作地很好.

II. Native Device 的初始化

Native 的DX 要在托管环境下使用就稍微有点麻烦了. 不过由于是Native 的, 所以在性能上会比托管DX 有所优势( 设计良好的前提下), 而且有时候由于一些第三方库的原因, 不得不使用Native 的DX. 下面简要说明以下在托管环境中使用Native DX 时容易遇到的问题.

首先, 我们要设定头文件的include 路径(%DX SDK%\include), 然后, 添加Library 的路径(%DX SDK%\lib), 接着, 将d3d9.lib, d3dx9.lib, winmm.lib 添加到Input Library 中.

然后在需要的地方包含头文件<d3dx9.h>

初始化一个Native 的DX Device 比托管代码要多一些步骤, 也要格外小心一些, 典型代码如下:

IDirect3D9 *_d3d9 = Direct3DCreate9(D3D_SDK_VERSION); //为了包含正确的头文件, 必须使用D3D_SDK_VERSION

D3DCAPS9 caps; //检查显卡的Capability

HRESULT hr = _d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

int vp = 0;

if( SUCCEEDED( hr ) ) {
if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
} else {
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
}
} else {
//FAIL;
}

D3DPRESENT_PARAMETERS paras;

//填充完整的Present Parameters 信息, 完整的字段含义参考DX 帮助
paras.BackBufferWidth = 200;
paras.BackBufferHeight = 192;
paras.BackBufferFormat = D3DFMT_A8R8G8B8;
paras.BackBufferCount = 1;
paras.MultiSampleType = D3DMULTISAMPLE_NONE;
paras.MultiSampleQuality = 0;
paras.Windowed = true;
paras.SwapEffect = D3DSWAPEFFECT_DISCARD;
paras.hDeviceWindow = (HWND)(pnlOther->Handle.ToPointer());
paras.EnableAutoDepthStencil = true;
paras.AutoDepthStencilFormat = D3DFMT_D24S8;
paras.Flags = 0;
paras.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
paras.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

IDirect3DDevice9* device = 0; //D3D9 Device

hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, (HWND)(panel->Handle.ToPointer()),
vp, ¶s, &device);

if( SUCCEEDED( hr ) ) {
//创建Device 成功
} else {
//FAIL
}

大致的步骤和托管DX 是一样的, 事实上, 在任何时候初始化一个Device 最好都要检查显卡的支持, 在上面的托管代码中, 这部分被省略了, 估计.Net 帮我们完成了很多事情, 默认值工作的很好. 但在Native 代码中, 省略初始化任何一个Paras 的字段都有可能导致Device 的创建失败(Investiagting 中).

另外, CreateDevice 方法的第三个参数接受的是一个HWND 类型的窗口句柄, 但是我们是使用的是一个托管窗口的托管Panel, 因此, 我们要获取这个Panel 的句柄, 方法是调用Panel::Handle 属性, 它返回一个IntPtr, 实际上包含了该控件的句柄, 所以, 我们通过ToPointer() 获得void*, 再强制转换为HWND 传给CreateDevice.

获得了Device , 我们同样可以在Paint 时间中重绘屏幕, 如下:

m_device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0×00000000, 1.0f, 0);
m_device->Present(0, 0, 0, 0);

0×00000000 是颜色的16 进制代码, 代表黑色.

这里还有一个问题, 由于IDirect3DDevice9* 是Native 类型, 因此在ref class 定义中, 如果定义IDirect3DDevice9* 为member, 那我们无法直接通过&device 将成员地址传给CreateDevice() 来创建设备, 因为这时候的IDirect3DDevice9* 被wrap 成CLR 的ptr 类型, 因此, 我们必须先创建一个临时变量IDirect3DDevice9* device ,然后再将创建成功的device 赋值给IDirect3DDevice9* 类型的member, 比如m_device. ( if( SUCCEEDED( hr ) ) m_device = device;)

至此, 我们就完成了Native D3D Device 在托管代码中的初始化, 接下来可以用该Device 可以来进行3D 图形的绘制…

//End of Step First D3D

Demo Code 下载: D3D Managed Sample

在编译前需要安装DirectX SDK, 并且重新定义Native Code 部分的头文件路径, LIB 路径地址. 需要禁止LoadLocker (见上文).

运行截图: 还没有开始画3D 图形 =.= 继续研究中…

D3D Managed Demo.JPG

啊~男人~

Thursday, December 27th, 2007

看标题貌似是要表达一下对”男人们”的感慨, 继而联想到可能是要写点对<集结号>这个热门的感想, 不是评论… 通常战争片是我们这些没有经历的毛孩子所无法评论的~

先说总体感觉吧, 在震撼和血腥的背后, 有真实的感动, 但是也有缺憾, 看到最后总觉得少了点什么, 总觉得应该有更多要说的故事, 但是, 事实上故事确实就这么结束了; 片尾曲, 桥头上那段, 很好听, 在昏暗的画面中, 火光映着谷子地的脸, 带点感伤, 似乎那一回头就已经预示了覆灭, 但是, 集结号没有响之前, “死也要给我打下去…”; 结尾有点TITANIC 沉入海底的感觉, 47名烈士, 默默地躺在了地底.

故事一开始不断地刺激着人的神经, 在还没有反应过来的时候, 一波又一波的战斗接踵而至, 没有火箭炮, 没有飞机, 没有很尖端的武器, 但就是这些老式的步枪, 大炮, 手榴弹, 加上破破烂烂的坦克, 一样将战争的残忍场面刻画得鲜红而震撼.

谁不怕死? 谁打心眼里不怕死? 但是只要是个兵, 是条汉子, 在命令下, 就得不怕死地斗下去; 攻坚, 往死里冲, 防守, 往死里扛; 勇气是战友的鲜血炼出来的, 是兄弟的呐喊给喊出来的! 打到最后已经分不清画面上到底是哪里在爆炸, 伤亡的是敌是友了, 漫天火光, 满目苍胰, 血水和雪水融化在一起, 从战亡的士兵身边流过…

可能是视角转换的太快, 从战争一下子到了”和平年代”, 忽然感觉有点不适应, 想要知道的结局也一直没有详细刻画, 只有谷子地最后发自内心骂出的那句话和”擦肩而过”的炮弹让人印象深刻. 为兄弟们争取正名的过程漫长, 而又辛苦, 无知的误解和蔑视压在了这位老兵的身上, 而当最后的集结号吹响时, 能如何, 即使在汶水之战的最后时刻, 集结号能吹响, 那又如何…

战争是残酷的, 每一个在战争中牺牲的士兵的生命, 都不是简单的”烈士”两个字所能承受得起的, 虽然, 现在的我们也只能做到这些.

电影拍得很有感觉, 是应该, 也值得哭的, 虽然有点未尽, 但是国产战争片能拍到这份上很欣慰了, 有场面, 有情, 够了. 本来以为只是中国版的”斯巴达300勇士”, 看来我低估了冯导~ 这部影片不是”肌肉男”所能简单表达和理解的.

电影说完了, 来抨击一下几个事情… 留到最后是不想破坏看电影的感想… 但着实是很生气.

1. 正大星美影城, efeso 发的优惠券被告知不能用于周一–周四, 因为那四天必有优惠, 非正价场… 我说我就出正价钱, 补差价行不? 不行… 于是, 本来可以换到4张电影票的优惠券突然间就成了废纸… 本来还想35的票价挺厚道的… 好吧, 那9:20 的场子半价优惠, 应该是30 吧, 那卖票的一口咬定还是35… 好吧, 我继续忍, 不Care 这些小钱, 心情重要, 既然不能换, 也不能折, 那我刷卡总可以吧, 结果居然和我说刷卡也不行@_@, 只能付现金, 我靠, 那整天宣传的刷卡打折的优惠都是给鬼看的啊… 最后无奈付了现金, 5*35… 无奈的不是钱, 是影城对待顾客的态度! 那个卖票的小白脸, 记住你了…

2. 电影9:20开场, 就事先在正大里逛逛, 看看有没有好看的外套可买, 同一件外套已经穿了2周多了吧=.= 哎… 结果选来选去, 决定买个160 的毛衣, 因为买200 减50 嘛, 那当然就多买个几双袜子凑满200 咯, 于是又被告知, 该品牌袜子不参与活动/fd… 那好, 我选你的袜子, 不就是班尼路嘛… 选好以后, 售货小姐墨迹了一会儿, 大概是觉得这样太亏了, 因为我买了15*3 的袜子, 结果155 除了衣服还多3双袜子… 又喊个小白脸过来在电脑上比划比划, 扔下一句, 袜子都不能参加活动! 测那… 扔下衣服就走, 如果是平时我可能就买了, 但是经历过电影票事件之后, 对于这种事情极度地不爽… 既然喊出来了, 那你们就事先给我设计好, 不要等顾客自己算好了再来搪塞!

3. 看电影过程中, 有两个不文明的人一直在唧唧歪歪, 就好象有一只苍蝇, 对不起, 是一群苍蝇, 在你耳边, 嗡儿~嗡儿~嗡儿… 飞进你的耳朵里… 救命啊… 于是, 我很想把他们揪过来, 把他们肠子扯出来, 勒住他们的脖子, 再手起刀落, 哗~~ 让他们的鲜血来祭奠荧幕上牺牲的战士们… 不过我很文明, 做了个手势让他们安静点… 无奈… 有些人就是贱! 依旧! 还装模作样的评论, 说什么真的战争不是这样的, 还自以为了不起地搞剧透, 在不合时宜的时候带头哄笑, 操, 他算哪个”小王八蛋”, 从几本垃圾书, 几个垃圾论坛中中看来的句子就拿来给自己”撑面子”? 一回头, 又TMD 是个小白脸… 找抽型!

同样是男人, 差距咋就这么大呢…

幸好, 嘿嘿, 这次有4个MM 陪着看电影, 就消消气, 不去计较那么多了, 欣赏电影比较重要, 嗯嗯~~ 不过有些人的素质啊, 是应该注意一下了. 某些官儿呢, 也该考虑一下现在生活的来之不易了, 是不是该学学人家, 真的为人民大众, 为在边防第一线的同志们办点实事呢~~ 表只看米啦…

回想到南*大学的别*事件, 众多河蟹事件, 不尽长叹哪~~ 希望还是要给的, 只是但愿不要收获失望…

又是一年圣诞

Tuesday, December 25th, 2007

不知不觉又过了一年, 去年的这个时候, 仿佛是差不多的心境, 在遥远的异国他乡, 在一个昏暗的地方, 度过了一个颓废却又貌似很High 的圣诞节…

今年的圣诞又急匆匆地来到了… 坐在硕大的显示器前, 脑子里尽是些奇怪的想法… SIGH… 还是出去玩吧, 在家里太窝了…

其实本来是希望能在大街上看到汹涌的人群和很多很多的圣诞老人, plus 很多庆祝活动, 比如烟火啊之类的东西; 但是事实上, 除了汹涌的人群, 在街上就再也看不到啥了 ^^ 有些地方甚至很是冷清~ 比如外滩x号.

和同事们到达外滩的时候, 正好下起了小雨, 风也有些寒冷; 可能是因为好久没有来外滩的缘故, 触过道路边上的建筑竟然很有感觉, 随手拍了一张照片, 竟也让我眼前一亮, 在手机上… 我要单反 T_T

外滩

那个… 过人是比较煞风景… 没有构图的意识, 哈哈, 哈哈, 哈哈…

从外滩一路走到南京路, 人也渐渐多起来, 好多人头上都带着”兔耳朵”, 当然是女的啦, 还有人戴小魔鬼的耳朵 =.= 开始我还以为那些戴兔耳朵的女的打算Cosplay 或者回去让BF/LG 惊喜一下, 后来才发现, 原来只是”流行”而已… 至少, 兔耳朵比头上顶个会招手的圣诞老人要好看得多, 嘿嘿:D

到了人民广场段就不知道该去哪里了, 没有看到任何有趣的节目, 也有些小累了… 不过运气似乎在照顾我们, 原本关闭的教堂居然又重新打开了! 虽然进去以后还是看不清楚祷告的状况, 不过歌舞的声音, 朗诵还是比较有意境的, 让人比较静心. 可惜, 挤来挤去, 早就没有了祷告的气氛和意愿, 所以, 看过热闹以后就闪了; 下次来这个地方的时候, 会是多久以后呢~~

事实上, 我们三个, 真的很不甘心就这么回去了… 发狠的通常结果就是冲动, 冲动素魔鬼… 既然都是魔鬼了, 那去PUB 参加个圣诞晚会不算过分吧 =.=

衡山路上Pub 很多, 不过一出地铁口就发现了百度, 鉴于从朋友那里听来南京的百度不错, 就一股脑钻了进去, 想要在震耳欲聋的音乐声中让自己的这个圣诞节更热闹些. 慢着… 去年我也不是这样想的么…

圣诞这种日子基本上不预订是没有卡位的, 但是我们争取了1个小时, 终于抢占到了一个小角落, 在一个硕大的音源旁边… demo, 坐下来的时候, 风景还是不错的嘿嘿~~ 点了一瓶黑牌威士忌, 开始静等圣诞晚会的到来, 似乎也不是很High…

好戏都在后面总是对的, 10点半以后人越来越多, 吧台上开始有调酒师表演, 舞台上也开始有人跳舞, 借着酒精的那一点力量, 我们居然也在12前的半个小时, 蹦进了舞池; 后来才知道, 那个酒的酒精度是40… 不过跳舞也有跳舞的好处, 可以感受圣诞来临前几秒的气氛和吃上MM 们发的费列罗~~ 咳, 可惜还是不太属于这里, 短暂的激情过后, 坐在吧台, 居然有一丝倦意, 声音却还是很吵…

凌晨4点的时候, 回到了家, 钻进被窝以后就忘记了这个世界, 睡到昏天地暗, 一觉醒来已经是今天下午4点~~ 头疼, 心也疼, 哎, 以后还是不去了吧, 适得其反… 今晚再好好休息一下, 明天又要开始上班了:)

THE SEAL

Sunday, December 23rd, 2007

如果有人问我, 南京和上海, 我更熟悉哪个, 我会毫不犹豫地告诉他, 上海… 即使我只在上海待了半年, 即使我还没有完全熟悉浦东的路, 即使这个城市大到让我无法全部了解…

南京已经变得太过陌生, 陌生的风景, 陌生的人们, 陌生的记忆; 夜间辗转在南京寒冷的街头, 深深地感受着这个冬天的寒冷.

但是, 这些曾经的景色并不能阻挡我回忆过去, 回忆在那片小小的地方所种下的所有回忆. 再次看到珠江路, 再次看到横行天桥, 再次看到31路公交车… 在波澜不惊地同时, 竟也有一丝哀怨. 这个我待了1年的城市, 竟然也变成了这样…

差点在一激动之下跑去浦口, 毕竟2年啊, 也是我回忆最多最快乐的两年. 但是, 我相信回去以后, 我看到的, 同样会是一片陌生的景色. 东大不在了, 人也不在了, 不去也罢.

徘徊着, 徘徊着, 曾经想要拥有一个单反的想法竟然再次强烈地冲击着我的大脑; 拿起手机, 看着屏幕上满是马赛克的图像, 又慢慢放了下去; 不清楚的记忆, 要它做什么.

坐在开往上海的火车上, 看着周围的风景一排排飞快地往后倒退, 死命地对自己重复着一句话, 死命地重复…

肚子莫名其妙地一阵阵挛, 脑海中飞快地闪过一个词, 禽流感, 随即即为自己的想法所笑, 却笑不出来. 情流感吧…

毫无还手之力, 也许这样… 很好呢…

只是在一抹淡笑中, 我离开了, 就像我沉着脸来到时一样.

包里还是那三张卡, 三张没能销毁的卡… 世界果然是轮回的… 火车外的阳光有些刺眼, PSP 适时地没有电了, 身边座位空得发虚…

一觉醒来, 上海, 我又回来了.

打击, 抨击…

Wednesday, December 19th, 2007

今天忽然想起来, 自己第一次”申请”信用卡被拒是南京的某个银行, 貌似是交通银行… 当时屁颠颠地跑去说我想申请信用卡, 结果直接被告知没有固定收入不能办卡 =.= 不像现在, 大学生办卡易如反掌… 之所以扯到这个倒不是因为和银行有什么过不去的, 而是因为到今天为止, 我还没有收到已经批准了的卡片 T_T 建行的等了3个多星期了, 浦发的两个多星期, 简直比被拒还难受. 不就是一封挂号信么, 有那么难吗, 还是上海本埠, 从浦东到浦东… FAINT… 不是说银行的效率低下, 我现在很怀疑邮局的效率!

上网翻了一下如何通过挂号信编号查询邮件的状态, 结果令我震惊! 满互联网网民都在骂中国邮政! 我简直不敢相信自己的眼睛! 何以一个国家机构被如此斥责! 归根到底, 原因就是: 挂号信件太慢, 无法查询, 丢失不负责… 把挂号信做到这个地步也不容易啊, 什么是挂号信, 不就是为了图个安全吗, 如果说慢一点也就忍受了, 但是无法查询, 丢失不负责, 这种投诉也太伤我们心了.

想起EMS 的广告, 速度决定一切, 但是心寒的是, 在所有快递中, EMS 是最慢的… 同城快递, 民营的只要1天, EMS 呢? 国际快递, 人家UPS 为了找最佳线路, 甚至连减少左转弯都考虑进去了… 如果说EMS 收了钱幸好还可以查查状态, 那挂号就不要指望了, 我就不明白挂号信的编号是要来干嘛的, 就为了扫描一下? 现在网络那么发达, 联网一下, 在线查询一下邮件应该是很合情理的功能, 就算不能对外, 那内部至少支持一下这样的方式查询吧, 不知道都为什么都说要等很久才能查到结果, 甚至一个月之久, 甚至然后丢下一句信件丢失就没有了声音… 虽然我没有亲自经历丢失信件, 不过现在已经很心寒了. 邮局看看大家的心声吧…

按照道理, 中国邮政国内一枝独秀, 网络遍布全国各地, 应该有很大的优势, 可是为什么却造成现在这种不讨好的状况. 据说邮政还是年年亏损, 但是邮费可是一路拔高啊… 是不是该改革一下了, 邮政局… 也是国家的一条血脉啊! 搞成这样, 大家怨声载道, 何必呢…

不知道尚在路上的两封挂号信现在身在何处, 生死何卜… 但愿不要寄丢. 要是真丢了我可要怒了, 挂失, 重新出卡, 再等待… 我可受不了… 不想再被折磨了. 慢一点, 我忍你, 但是千万别把它寄丢了… 像是嗓子眼里卡了只虫子… SIGH…

顺便表扬一下浦发, 800 人工居然一打就通, 态度也还行, 不像网上说的那么差… 总算改善了一下我对浦发的印象, 也不枉我平白无故就迷上浦发了… 人品爆发了么难道? 希望以后打800 也一打就通, 表老是给我忙音, 阿门…