Quantcast
Channel: 英特尔开发人员专区文章
Viewing all 154 articles
Browse latest View live

基于新型一体机平台开发浸入式应用

$
0
0

介绍

过去几年来,一体式(AIO)电脑已经发展为家庭和办公设备的主流,可交付强大的处理器性能、大屏幕图形功能以及简约而又时尚的外形设计。随着微软推出 Windows* 8,一体式电脑采用了传统键盘与鼠标输入方式以及极具创新特性的触控功能,为最终用户交付新的软硬件交互方式。现在,在上述功能进一步发展的基础上,一款新设备又将产生 — 便携一体式(pAIO)电脑。

便携一体式电脑具备高端技术规格,采用可平放运行的大触控屏,以及可支持有限移动性的内置电池。这些功能有望催生崭新使用场景,同时,整合以下创新特性的应用与游戏有望得以开发:

  • 多用户和多触控用户界面
  • 基于语音或摄像头采集的手势语的多模式交互
  • 多工具场景,例如,使用智能手机作为游戏控制器
  • 借助英特尔® 无线显示(WiDi)在高清电视上提供附加游戏或应用视图

能够在水平方向分离运行这一特性为软件开发人员带来了机遇和挑战,他们需要调整思维以利用便携一体式电脑带来的全新特性。本文将介绍可帮助软件开发人员设计此类触控交互应用的四个指南,以及基于英特尔® 处理器的便携一体式(pAIO)电脑的出色用户体验。

指南 1:了解便携一体式电脑的平台功能

便携一体式(pAIO)电脑为应用开发人员带来前所未有的机遇,它具备大触控屏、轻量移动性和平放功能,以及支持多触控、多用户应用的高处理性能 

便携一体式电脑与传统一体式电脑存在一些公共设计元素;然而,基于英特尔处理器的 pAIO 还具备一些关键特性,可为软件开发人员带来新机遇,为最终用户带来新体验。便携一体式电脑支持固定计算和适应性计算体验,提供屏幕倾斜功能,支持垂直、倾斜和平放场景;屏幕尺寸范围是 18.4-27 英寸(图 1)。多触控功能通过触控板提供,支持最低 10 个触控点,轻量移动性通过板载电池提供。通过图片中的轻量移动性和平放功能,pAIO 为开发创新型软件带来了机遇。这些创新型软件可充分利用浸入式大屏幕画布交付的多触控、多用户功能。

图 1.屏幕方向

高度智能的英特尔® 酷睿™ 处理器家族为全特性、多用户、多触控 pAIO 应用交付超高性能和惊艳视觉计算,这些应用涉及的领域包括游戏、教育、娱乐、医疗保健、商业、内容创建和生活方式。应用设计人员可利用英特尔酷睿处理器开发出色应用,交付精彩图片和无缝触控体验(表 1)。

特性第二代英特尔® 酷睿™ 处理器第三代英特尔® 酷睿™ 处理器优势

处理器

  • 英特尔® 睿频加速技术1
  • 英特尔® 超线程(HT)技术2
  • 英特尔睿频加速技术
  • 英特尔超线程技术
  • 英特尔睿频加速技术
  • 英特尔超线程技术
  • 由于内核更多、能效更高,速度得到显著提升
  • 针对复杂工作负载提高处理效率和总体性能

USB

USB 2.0 (480 Mbps)

USB 3.0 (5 Gbps)

性能比 USB 2.0 高 10 倍

媒体与显示

  • 英特尔® 快速视频同步3
  • 英特尔® 高清视频技术4
  • Intru™ 3D6
  • 英特尔® 高清显卡 2000/30004
  • 英特尔® 无线显示技术 2.05
  • 英特尔快速同步视频
  • 英特尔高清视频技术
  • Intru 3D
  • 英特尔高清显卡 2500/4000
  • 英特尔无线显示技术 3.x
  • 加速媒体转码
  • 以最理想的方式欣赏图像和高清视频,获得更清晰的图像、更流畅的体验和更丰富的色彩
  • 在您的电脑上支持 3D 视觉体验
  • 出色核芯显卡
  • 将内容轻松、直接流至大屏幕高清电视
  • 英特尔快速同步视频
  • 英特尔高清视频技术
  • Intru 3D
  • 英特尔高清显卡 2500/4000
  • 英特尔无线显示技术 3.x
  • 加速媒体转码
  • 以最理想的方式欣赏图像和高清视频,获得更清晰的图像、更流畅的体验和更丰富的色彩
  • 在您的电脑上支持 3D 视觉体验
  • 出色核芯显卡
  • 将内容轻松、直接流至大屏幕高清电视

表 1.处理器比较

指南 2:明智选择您的软件开发环境

Windows 8 支持两种不同的开发环境,它们决定着您的开发工具选项、特性可用性、与之前版本 Windows 的兼容性、以及您的发布/销售模式。

Windows 8 支持您使用众多编程语言和工具进行应用开发。您甚至可以使用一种语言编写组件,并用于使用另一种语言编写的应用中。然而,您必须提前决定即将开发的应用类型,是 Windows 商店应用还是 Windows 桌面应用(参见图 2)。

桌面应用可运行于 Windows 8 的 Windows 桌面模式。该模式看似传统 Window 环境,但体验有所不同。桌面模式支持基于触控与传感器的应用。另外,一些硬件驱动程序和设备特性 — 如英特尔® 无线显示技术(英特尔® WiDi)和 OpenGL* 目前仅支持在桌面模式下运行的应用。

Windows 商店应用利用最新 WinRT API,在 Visual Studio* 2012 中使用 C++、C# 或 web 技术而开发,例如 HTML5、JavaScript* 和 CSS3。

图 2.面向 Windows* 8 应用的高级开发环境

开发人员应该知道一些设备特性和技术可能还未面向 Windows 商店应用环境推出或开发。因此,您选择 Windows 商店应用模式还是选择 Windows 桌面应用模式将决定着以下选项:可用的开发环境,可用的硬件特性,与之前版本 Windows 的兼容性,以及应用的销售与发布模式(见表 2)。

向公众发布和销售 Windows 商店应用一般是通过 Windows 商店。Windows 商店向全球庞大客户群发布或出售应用。关于销售和发布应用,桌面开发人员拥有更多选项。除了传统发布和履约选项,一些开发人员可将其桌面应用放在 Windows 商店的列表中(创建一个购买网站的链接)。

功能/工具集Windows* 8 桌面模式应用Windows 商店应用

英特尔® WiDi

有(可能需要浏览器插件)

可编程 GFX - OpenGL*

可编程 GFX - OpenGL

可编程 GFX – OCL*, CM*

英特尔® 图形性能分析器(英特尔® GPA)

完整工具功能,不包括:IE10、WinRT 应用分析以及 Frame Analyzer 中的 DX10(带 15.28 驱动程序 + 新的 OpenCL SDK)

不包含(WinRT 不支持设备)

英特尔® 性能瓶颈分析器(英特尔® PBA,又称 xIF)

支持桌面应用分析。查看器在桌面中有效。

部分功能集可用于 WinRT。

开发环境(VS*,Eclipse*)

部分

英特尔 AppUp® 中心

Windows 商店

无(一些桌面应用可能在 Windows 商店列出并创建购买网站的链接)

兼容之前版本的 Windows

表 2.面向 Windows* 商店和 Windows 桌面应用的特性兼容性

指南 3:触控对于开发面向 pAIO 的应用十分关键

Windows 8 支持您针对 Windows 商店应用和 Windows 桌面应用灵活选择

触控为用户提供直观、有趣、自然的应用交互方式。运行于英特尔酷睿处理器架构 pAIO 的多触控多用户应用的用户界面(UI)依赖于在总体设计过程中有机融合并创新运用触控功能。幸运的是,微软已经确保提供密集型触控 API 以支持 Windows 商店应用和桌面应用的开发。  

Windows 商店应用

Windows 为 Windows 商店应用的开发提供两个 API 集合:Windows Runtime (WinRT) 和 Windows Library for JavaScript (WinJS)。

Windows Runtime。这些 JavaScript、C#、Visual Basic* 和 C++ API 可访问所有核心平台特性。

  • 使用指针事件获取基本接触信息,例如,位置与设备类型,压力和接触几何等扩展信息,并支持更多复杂交互。
  • 使用手势事件管理静态单指操作,例如:点击和按住(双点和右点由基本手势演变)。
  • 使用操作事件管理动态多触控操作,夹捏和拉伸以及利用惯性与速率数据的操作,例如,摇拍/滚动、缩放和旋转。

Windows Library for JavaScript。 WinJS 提供 JavaScript API 的库,其中可提供控制、CSS 风格和帮助您编写代码的功能。WinJS 命名空间包含的功能类似于 WinRT 环境中 Windows.UI.XAML 命名空间的功能。

Windows 8 桌面应用

桌面应用运行于 Windows 8 的 Windows 桌面模式。Microsoft Windows 8 桌面应用中支持触控输入和手势的三个方法是:

  • WM_POINTER 最容易编码,支持最丰富的手势集,但仅运行于 Windows 8。 WM_POINTER 消息接收触控输入,使用操作语境功能识别来自这些消息的手势。
  • WM_GESTURE 编码简单,向后兼容 Windows 7,但是受到的限制也最严格。
  • WM_TOUCH 完全向后兼容 Windows 7。每一个触控事件都通知您的应用,您的代码必须采集这些事件并识别其代表的手势。

通常人们错误地认为,不能为桌面模式开发新 Windows 8 基于触控与传感器的应用。这种观点是错误的。另外,一些硬件驱动程序和设备特性 — 如英特尔® 无线显示技术(英特尔® WiDi)和 OpenGL* 目前仅支持在桌面模式下运行的应用。

多模式交互

下一代应用和游戏引入了基于语音与摄像头采集的手势的多模式交互,也有望支持 Windows 8 桌面模式应用。开发人员应当考虑采用英特尔® 感知计算 SDK 以便在 pAIO 上支持多模式交互。另外,开发人员可使用英特尔® 通用连接框架(英特尔® CCF) 以支持多工具场景,例如,智能手机等备用设备可用来控制 pAIO 上运行的游戏。

软件框架与验证

选择开发 Windows 8 桌面游戏的软件设计人员还拥有现有大量软件框架和验证工具的附加优势。这些工具可帮助您在开发 pAIO 应用时加速开发进程、优化性能以及最大程度提高触控响应性能(表 3)。

工具优势

Microsoft XNA

提供工具与库,提高平台移植性,同时支持开发人员将更多时间用于关注内容与体验。

Adobe Flash*,AIR,游戏 SDK

交付可支持丰富用户界面、媒体效果和 web 连接的框架。

OpOpenGL 和 DirectX*

支持访问图形硬件特性以优化图形密集型应用。

Windows* Presentation Foundation (WPF)

提供强大的 GUI 开发框架,基于 DirectX 的更高级别抽象层,其中的元素可基于事件创建链接并利用。

HTML5

为具备多媒体和图形功能、基于 web 的应用提供标记语言。十分适合网络游戏开发。

GPUView

支持对 GPU 过载等相关问题进行故障排查。

英特尔® 电源工具

评测各个场景下的 CPU 功耗。

Visual Studio* 2012 Profiler

监控并呈现关键呼叫堆栈以隔离性能问题。

FRAPS

评测每秒帧数(FPS)以确保流畅图形渲染。

表 3.Windows* 8 桌面模式软件框架和验证工具

指南 4:了解用户体验

面向多用户多触控水平大屏幕进行设计需要换位思考 — 您面对的不是手机屏幕!

开发人员社区为手机与平板电脑等设备的触控屏设计精彩游戏和应用已经有一段时间了,但是对于 pAIO,小屏幕的限制不复存在,因此,设计人员可整合更多、更出色的交互与控制。

成功的设计需要了解用户通常如何进行应用交互。对于某些应用,一个游戏可同时有四个人玩,因此,从多用户的角度出发十分关键。另外,控制在屏幕上的布局需要切合设备的预期使用模式(表 4)。

使用模型用户数量特殊考虑应用示例

多个玩家,单独控制

  • 2 个玩家,相对分立
  • 4 个玩家,分立四角

必须考虑玩家的位置。最佳位置是屏幕边缘

足球游戏的玩家控制位于屏幕的对面边缘

多个玩家,共享控制

多个玩家,不拘一角

共享控制位于最便利的位置

传统家庭棋盘游戏,共享控制(数字骰子,罚张等)位于游戏棋盘的中央(屏幕)

多用户协作游戏

支持多个用户在屏幕上协作

共享控制,图形自然,易于理解

园林规划

表 4.多用户场景示例

用户角度

pAIO 屏幕可拆卸下来平放在桌面上,因此可支持新的多用户应用。对于应用开发人员而言,为多用户设计应用需要了解用户希望如何与应用交互以及用户之间如何交互。了解用户的角度十分关键:

  • 早期设计应明确用户的数量和类型。是每个用户都需要一个控制集(很多游戏是这样),还是所有用户共用一个控制集(多用户协作型应用)
  • 最便捷的触控目标是屏幕边缘
  • 在特定时间,多个玩家可能有多个关注点

用户控制十分关键

如何设计用户界面影响到触控输入的易用性。为了确保您的应用针对触控而优化,请考虑以下指南:

  • 由于 pAIO 屏幕尺寸大,考虑使用大图标和图片 — 需要最低程度的升级
  • 每个用户应确信能够通过物理位置、颜色或形状找到可用的控制基于图片的说明通常更易于各方理解
  • 触控需要较大的用户界面元素以确保精度,防止手指混淆重要信息。不过,与平板电脑相比,大屏幕的触控为设计人员提供了更多可用空间
  • 确保用户界面始终可见,并留意用户的手掌可能接触其它控制或屏幕信息

确保应用生动有趣

可平放在桌面上的大屏幕 pAIO 为设计人员提供了设计精彩、直观、可视化的触控交互机遇。您的应用应具备真实感,吸引用户玩索。以下提示帮助您获得“真实感”:

  • 始终为触控交互提供即时、直接的视觉反馈。例如,您可以使用高亮度或工具提示指示当前触控目标,防止无操作其它目标
  • 调节物理引擎管理游戏速度。使用加速和惯性等物理效果为摇拍等交互提供自然体验
  • 考虑引入下一代功能和多模式交互,例如,基于语音和/或手势的控制

总结

便携一体式电脑具备大屏幕尺寸、轻量移动性和平放功能,为应用开发人员带来新机遇。在英特尔酷睿处理器的支持下,这些创新型应用有望为用户交付出色图片和无缝触控体验。然而,设计这些应用需要换位思考并明确可用的开发选项;而我们英特尔功能提供丰富的资源库,包括软件设计考虑因素、触控集成和平台功能。更多信息,请跟踪以下链接。

设计与开发:

  1. 设计面向超极本™ 设备和触控桌面应用:
    http://software.intel.com/en-us/articles/designing-for-ultrabook-devices-and-touch-enabled-desktop-applications
  2. 为开发人员开发桌面自然用户界面 API:
    http://software.intel.com/en-us/articles/developing-with-desktop-natural-user-interface-api-s-for-developers
  3. 面向 Windows 桌面应用的设计人员工具:
    http://software.intel.com/en-us/articles/designer-tools-for-windows-desktop-applications
  4. 为超极本™-触控界面重塑应用:
    http://software.intel.com/en-us/blogs/2012/08/09/re-imagining-apps-for-ultrabook-part-1-touch-interfaces/
  5. 触控设计原则:手势和触控目标:
    http://software.intel.com/en-us/blogs/2012/08/29/touch-design-principles-part-2-postures-and-touch-targets
  6. 在使用 C# 的 Windows* 8 风格用户界面中支持触控:
    http://software.intel.com/en-us/articles/enabling-touch-in-windows-8-metro-style-apps-with-c
  7. 人机触控:在后 PC 时代开发超极本™ 应用:
    http://software.intel.com/en-us/articles/the-human-touch-building-ultrabook-applications-in-a-post-pc-age
  8. 在 Windows* 8 应用中处理触控输入:
    http://software.intel.com/en-us/articles/handling-touch-input-in-windows-8-applications
  9. 触控友好型控制按钮:
    http://software.intel.com/en-us/articles/touch-friendly-control-buttons-bubbles-2
  10. 触控操作示例:
    http://software.intel.com/en-us/articles/touch-reactive-sample-bubbles

代码示例:

  1. 比较触控编码技术 – Windows* 8 桌面触控示例:
    http://software.intel.com/en-us/articles/comparing-touch-coding-techniques-windows-8-desktop-touch-sample
  2. 触控示例:
    http://software.intel.com/en-us/articles/touch-samples
  3. Windows* 8 上超极本™ 桌面应用程序开发:具有触控和感应功能的照片应用程序:
    http://software.intel.com/en-us/articles/photo-application-for-ultrabook-and-windows-8-desktop-applications-development-with-touch-and-sensors
  4. Windows 桌面触控摄像头示例:
    http://software.intel.com/en-us/articles/windows-desktop-touch-camera-sample-whitepaper

英特尔公司© 2013 年版权所有。所有权保留。

Intel、英特尔、英特尔标识、AppUp、Core、酷睿、InTru、Ultrabook、超极本是英特尔在美国和/或其他国家的商标。

*其他的名称和品牌可能是其他所有者的资产。

OpenCL 和 OpenCL 标识是苹果公司的商标,需获得 Khronos 的许可方能使用。

1(英特尔® 睿频加速技术)要求系统支持英特尔® 睿频加速技术。仅指定英特尔® 处理器支持英特尔® 睿频加速技术和英特尔® 睿频加速技术 2.0。详情请咨询您的系统生产商。其性能可能因硬件、软件和系统配置的不同而各有所异。更多信息,敬请登陆 www.intel.com/go/turbo。

2(超线程)需要支持英特尔® 超线程(HT)技术的系统;请咨询您的电脑制造商。实际性能会因所使用的具体硬件和软件的不同而有所差异。并非所有英特尔® 处理器都支持该技术。如欲了解更多信息(包括哪些处理器支持英特尔® 超线程技术),请访问 http://www.intel.com/go/ht。

3(英特尔® 快速同步视频-3 年基准)视频转码声称采用 Cyberlink* MediaEspresso 6 来渲染一个时长为 4 分钟、449 MB、1920x1080i、18884 Kbps 的 MPG2 视频文件,在 Apple iPod* 上以 640x360 的分辨率、H.264 和 MP4 文件格式播放。相比英特尔® 酷睿™ 处理器(台式机)和英特尔® 酷睿™ 2 双核处理器 E8400 (台式机)和 P8600 (笔记本),第三代英特尔® 酷睿™ i5-3450 处理器(台式机)和第三代英特尔® 酷睿™ i5-3320M 处理器(笔记本电脑)的速度提升了 4 倍。

4(核芯显卡)核芯显卡并不是在所有电脑上都支持,可能需要安装优化软件。请咨询您的系统制造商。更多信息,敬请登录 http://www.intel.com/go/biv。

5(英特尔® 无线显示技术)需要配备支持英特尔® 无线显示技术的电脑、平板电脑、智能手机、兼容适配器及电视。敬请注意,1080p 高清功能及蓝光播放功能* 仅限带有内建图形加速功能的指定英特尔® 处理器。请向您的电脑制造商查询。更多信息敬请登陆 www.intel.com/go/widi。

6观看立体 3D 内容需要 3D 眼镜和支持 3D 功能的显示器。物理风险系数显示在 3D 材料中。


Windows* 8 上的超极本™ 桌面应用开发:支持触控和传感器的图片应用

$
0
0

下载源代码:

PhotoApplication.zip

介绍

众所周知,超极本™ 设备通常具有时尚的美学设计、漂亮的外观和流畅的触控。然而,与大多数标准的笔记本电脑相比,超极本的真正优势就在于它们的硬件性能。除了具备笔记本电脑支持的标准功能外,超极本还具备了一些独有的特性,如触摸屏、GPS、加速计,并支持方向传感器、环境光线传感器、NFC 和其他传感器。当前,消费者在个人计算设备上拥有了更多的选择,比如台式机、笔记本电脑、平板电脑等。大多数的消费者在处理复杂的软件应用和进行数据存储时仍然将台式机或笔记本电脑作为首选。随着智能第三方应用和多任务处理的不断出现,平板电脑以其极高的便携性为我们提供了一个可以替代笔记本电脑的绝佳选择。然而,尽管平板电脑可以处理一些与工作或业务相关的任务,它们仍然无法完全代替笔记本电脑。

而可变形的超极本由于既可以用作平板电脑又可以用作笔记本电脑,因此仅通过自身一台设备即可满足消费者的多重需求。它们不仅具备了笔记本电脑的功能,还具备了平板电脑的易用性和便利性。OEM 厂商在设计可变形超极本时往往能够独出心裁。例如,一些可变形设计可以支持一种可拆卸的键盘,因此在卸下键盘之后显示屏便可以用作独立的平板电脑。而其他的可变形设计则支持显示屏进行滑动或翻转操作,进而可以在平板电脑和笔记本电脑模式间进行切换。

集成 Windows 8 的可变形超极本集两种设备的角色于一身,同时提供了强大的功能。借助集成 Windows 8 的英特尔硬件,用户既可以运行桌面应用,也可以运行 Windows 应用商店(以前称作 Metro-style)中的应用。微软的新 Win RT API 为开发人员提供了在 Windows 8 上创建 Windows 商店应用的工具。另外,一些 Win RT API 还可用于在 Windows 8 上开发桌面应用,这意味着开发人员可轻松将他们的传统 Windows 应用移植至 Windows 8 桌面应用。

以下一系列文章详解了一个简单的超极本图片应用。该应用将展示开发人员如何使用超极本的独有特性(包括触摸屏、GPS、环境光线、方向和电源传感器)来创建出智能、动态的应用。这些代码段和源代码将帮助开发人员将他们的传统 Windows 应用移植到 Windows 8 上。本文同时还说明了如何通过 Windows 8 上的受控代码访问 Win 32 API 上的非受控代码。

面向超极本的图片应用

这是一个简单的 Windows 8 应用,用户可以使用它进行拍照、查看图片、为图片加注地理标记等。该应用支持通过触控和鼠标/键盘输入,为用户提供了极佳的平板电脑和笔记本电脑双模式体验。

以下文章将通过图片应用中的代码段帮助您快速了解超极本设备应用开发的不同方面。第一部分说明了在开发能够支持流畅触控应用时在用户界面设计方面需要注意的事项。此外,你还能学到如何使用一些触摸手势,如“轻拂”、“滑动”、“捏拉”和“缩放”。

为运行 Windows* 8 的超极本™ 增加对桌面应用的触控支持

可实现极佳用户体验的用户界面指南

这一部分文章中将通过代码段帮助你了解功耗感知和环境感知的实施细节,以及如何在你的应用上使用传感器。点击你感兴趣的文章了解更多有关信息:

开发适合搭载 Windows* 8 的超极本TM 的低功耗桌面应用

在搭载 Windows* 8 的超极本的桌面应用中启用加速计传感器

在搭载 Windows* 8 的超极本TM 的桌面应用中启用方向传感器

在搭载 Windows* 8 的超极本TM 的桌面应用中启用环境光线传感器 (ALS)

本应用仅用于说明之目的,尽管如此,我们仍然提供了一个信息板为您展示各种传感器的数据,包括环境光线、方向、功耗等级、亮度等。

相关文章

通知

本文件中包含关于英特尔产品的信息。本文件不构成对任何知识产权的授权,包括明示的、暗示的,也无论是基于禁止反言的原则或其他。英特尔不承担任何其他责任。英特尔在此作出免责声明:本文件不构成英特尔关于其产品的使用和/或销售的任何明示或暗示的保证,包括不就其产品的(i)对某一特定用途的适用性、(ii)适销性以及(iii)对任何专利、版权或其他知识产权的侵害的承担任何责任或作出任何担保。

除非经过英特尔的书面同意认可,英特尔的产品无意被设计用于或被用于以下应用:即在这样的应用中可因英特尔产品的故障而导致人身伤亡。

英特尔有权随时更改产品的规格和描述而毋需发出通知。设计者不应信赖任何英特产品所不具有的特性,设计者亦不应信赖任何标有保留权利摂或未定义摂说明或特性描述。对此,英特尔保留将来对其进行定义的权利,同时,英特尔不应为因其日后更改该等说明或特性描述而产生的冲突和不相容承担任何责任。此处的信息可随时更改,恕不另行通知。请勿根据本文件提供的信息完成一项产品设计。

本文件所描述的产品可能包含使其与宣称的规格不符的设计缺陷或失误。这些缺陷或失误已收录于勘误表中,可索取获得。

在发出订单之前,请联系当地的英特尔营业部或分销商以获取最新的产品规格。

索取本文件中或英特尔的其他材料中提到、包含订单号的文件的复印件,可拨打 1-800-548-4725 1-800-548-4725, 或登陆:http://www.intel.com/design/literature.htm

在性能检测过程中涉及的软件及其性能只有在英特尔微处理器的架构下方能得到优化。诸如SYSmark和MobileMark等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。上述任何要素的变动都有可能导致测试结果的变化。请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。

对本文件中包含的软件源代码的提供均依据相关软件许可而做出,任何对该等源代码的使用和复制均应按照相关软件许可的条款执行。

英特尔、超极本和 Intel 标识是英特尔在美国和/或其他国家的商标。

英特尔公司 2012 年版权所有。所有权利受到保护。

*其他的名称和品牌可能是其他所有者的资产。

附件

下载 photoapplication.zip (19.26 MB)

设计面向超极本™ 设备并支持触控的桌面应用

$
0
0

下载 PDF

随着 Windows 8* 以及支持触控的计算机的推出(例如英特尔超极本™ 设备,其中触摸是额外的输入方式),用户拥有了与应用和软件交互的新方式。在过去,触摸仅限制在特殊设备中使用,这些设备需要专门的软件,而今天我们看到大量制造商正在制造支持这些新输入方式的设备。

超极本在这些设备中显得卓尔不同,不仅包含触摸功能,也配备有笔记本电脑式键盘和鼠标触控板,以便于以传统方式操作。因此用户可选择过去所用的键盘,也可使用触摸作为输入源。

The 智能手机和平板电脑的广泛普及意味着设计人员需要调整自己的思维,清楚了解触摸的功能和限制。本文将讨论这对用户界面的设计有何影响,并提供一些指导以设计出可促进交互并提供卓越用户体验的出色软件。

触摸

触摸输入并非全新的输入方式。这种方式实际上已存在了很长时间(我参与开发的首个基于触摸的应用程序可追溯到 90 年代早期),但是直到最近才走向平价,在主流设备中获得广泛应用。在过去,构建基于触摸的应用程序的情况非常少见,而今天的智能手机几乎都以触摸为基础,并且最终用户也十分喜爱这种方式。随着全新 Windows 8 (设计定位为触摸优先系统)的发布,预期将有更多设备采用触摸模式,无论是平板电脑、台式机还是笔记本电脑。

用户应当能以自然的方式与超极本的触摸屏交互。如果屏幕上有按钮,它们应该凸显出来,在触碰它后,发生的效果就和将鼠标移动到按钮上并进行点击一样。相似地,诸如二指拨动缩放以及触摸并拖动以将内容在屏幕上四处平移的手势应当能如用户所预期一般发挥作用。

触摸方式是全特性设备在功能上的绝佳补充。

是否可触控

用户不仅仅会处于支持触控的情况,在某些情况下,例如设备的键盘被隐藏或移除,就可能处于只能进行触控的环境。如果应用程序依赖于鼠标行为(例如悬停以展示命令或操作),用户将无法使用软件。为了让这种软件可用,我们必须确保控件足够大以支持触控,并且在预期的使用模式下布置方式将会有效。

触摸设计包括确定投入多少时间和资源更合适,这需要根据对于业务的重要性以及投资回报 (ROI) 进行权衡。例如,投入到面向客户的应用程序上可能要比投入到仅有少数用户使用的内部应用程序上得到更高的投资回报(业务关键应用程序可能并非如此)。

定义了数个支持触控的应用程序类别。这些类别包括:

  • 可触控:控件的尺寸被设计得足够大以在只能触控的环境下正确发挥作用,据研究表明,尺寸至少要达到 23 x 23 (6 mm) 像素并且控件之间要有足够的空间,才能防止意外误操作。应用程序能够感知和使用诸如轻拂和平移的手势,从而移动可滚动的区域并且无需使用悬停。
  • 触控支持:大多数常用控件至少达到 40x40 像素 (10 mm),并且支持触控目标的标准相关手势,例如平移、二指拨动缩放和旋转。基本多点触摸操作已实施,并且能够如预期发挥作用。
  • 触控优化:重新访问内容以最大程度降低混乱并尽可能提升用户体验。使用战略性布置在屏幕上易于访问的区域中的控件执行任务。诸如惯量和动量的更高级别的交互功能可让界面变得更生动。

将现有应用程序迁移到新环境的挑战在于至少确保这些应用程序可触控,从而能够在只能触控的环境下起作用。为了帮助您进行投入决策,本文将讨论重新设计触摸操作系统时用到的一些设计原则,并探索如何将它们应用至桌面。

触控设计原则

在 2011 年的 Build conference 大会上亮相的 Windows 8 的设计人员们讨论了他们用于开发以触控优先的框架的一套原则。这些原则包括:

触控应当自然而直观。通过用户触碰屏幕来获取触摸输入,从而选择和操作对象和控件。这意味着最终用户不需要专门的培训就可与应用程序交互。例如在使用超极本时,其中一个很好的功能是可以创建并使用触摸密码来登录。与其他一些身份验证模式相比,这样不仅更个性化,速度也更快,并且更安全。

直接而真实。 触摸一个控件可操作该控件,而不是操作界面中不同区域中的对象,并且对用户提供发生了某些事件的反馈。这种反馈包括声音或振动。包括惯量和动量等特性可提供更为实际的体验,并且与真实世界更为一致。

例如在屏幕上用手指轻拂某个控件可移动图片,但是在摩擦力和惯量的作用下最终停下来。如果尝试做一些不支持的操作,例如将控件移动至屏幕上无效的位置,它会轻微移动,但是会迅速返回原位置。

可移植并且一致。应用程序应当遵照行业标准并且以一致的方式实施手势。手势和操作在不同应用程序上意味着同样的事情。例如,二指拨动手势可通过将控件调整得更小来缩小或影响控件,而分开手指的手势则起到相反的作用。触摸和拖放可执行平移操作。在创建新的自定义手势时需要仔细思考,尤其是在和系统手势的操作方式一样时。

没有阻碍。 设计为可感知触摸的控件要容易访问并且在界面设计中位于合理的位置。对这些对象的操作不会妨碍或阻碍任务的完成。

来自构建 Windows 8 博客 - Windows 8 触控语言

触摸限制

触摸在选择上的精确度较差,并且不可执行应用程序的悬停等事件。因此设计人员需要确保控件足够大,要有足够的边距,以便能触摸到它们。不应该加入依靠悬停(类似鼠标悬停)来完成操作或任务的控件。应当了解的一些限制包括:

  • 鼠标和指针具有很高的精度,可让用户选择特定像素,而触摸的精度要差得多,需要触摸目标足够大并且目标间隔足够距离才能选择目标。例如在使用触摸在屏幕上书写时,您无法看到接触点在何处。用于文本输入的其他方式可能更有效。

  • 屏幕上尺寸更大的控件以及可选键盘显示意味着可供显示内容的屏幕区域变小。
  • 既然悬停不可用,则将需要重新构思依赖于悬停的控件。
  • 用于文本、输入和选择时将更为困难。
  • 屏幕键盘会占用空间,从而留给您的内容的空间变少。

  • 触摸必须是可以撤销的,有时用户会不小心碰到屏幕并触摸到一些东西,应用不应该进行不可恢复的破坏性行为。

采用触摸通常是为了以易用和自然的方式与应用程序交互,它可能是众多输入方式中的一种,也可能是唯一可用的输入方式。这意味着您的应用程序不能依赖于键盘和鼠标的可用性。由于触摸和手势活动由操作系统转变为鼠标事件,因而良好支持鼠标的应用程序可方便地转变为支持触控的应用程序。

触摸目标大小调整考虑事项

将触摸作为输入方式时,首先要考虑的事项之一是用于选取操作的物体,也就是手指,要比鼠标指针或触摸笔尖大得多。手指的大小可从儿童的 8 mm 到职业运动员的 18 mm 或更大。平均大小在 11 mm 到 15 mm 之间。

指导

触摸目标要有足够的大小才能实现可触控,至少要达到 23 x 23 像素(大约 6 mm)。有些控件则过小而无法触摸到,例如大小为 9 x 15 像素的旋转控件,因此设计人员应当考虑备选方式,为用户提供更多选择。

控件之间的间隔是另一方面,越大越好。如果链接或选项彼此过于靠近,用户则更有可能发生误触。因此,如果空间允许,建议增大控件之间的间距。

Acceptable

Better

工具栏图标为默认大小(16 x 16 像素)时难以被触摸到,因此您应当考虑使用更大的图标,并且在其间加入足够大的边距,让进行所需的选择更为容易。五个像素大小的边距比较合适,但是如果屏幕布局允许,则越大越好。此外要考虑包含在工具栏中的控件的类型,例如下拉列表或文本框,并让它们足够大,以正常发挥作用。

菜单区域中,命令之间的间隔可能对于只能触控的设备显得过于紧凑。默认设置下,命令之间的间隔为 7 个像素,但是如果多增加 4 个像素,就可以拥有更加易用的菜单系统。幸运的是,您可利用操作系统的原生功能帮助您实现体验的一致性和实施应用程序所需的大量工作。

如果这些准则显得过于约束,可考虑使用功能区。该控件于 2007 年推出,采用触摸友好型设计,允许您选择按钮大小和组织方式,以满足非常复杂的场景的要求。例如,Windows Explorer 使用标准的功能区让查找用于文件复制或重命名的命令更为容易,还以直观、易用的方式提供了对于非常用命令的访问。请注意,最常用的命令将以更大的图标表示。

功能区也是可折叠的。因此在不需要它时,用户可在视图中隐藏它。按钮、复选框、组合框以及其他命令可设计到功能区中,让用户可更方便地根据需要查找和完成任务。

位置 – 控件的布置

一般而言,开发人员可以根据硬件限制来限制应用程序必须感知的布局数目。具有 1024 x 768 屏幕大小的标准横向意味着应用程序设计人员可以直接在画布上安排控件,并且应用对大多数用户可用。由于平板电脑和超极本可以方便地旋转,控件的固定布局意味着屏幕的特定区域将比其他区域更容易被触摸到。在平板电脑上效果良好的控件布局可能在笔记本电脑上适得其反。

这种情况下,自适应的布局将凸显作用。使用诸如 XAML 的标记语言构建的应用程序可使用布局容器来放置控件,并让它们更接近用户。通过检测输入设备(例如物理键盘的可用性)来确定哪种布局适用,这样将帮助您的应用程序适应正在使用的设备。确保常用控件之间有明显的差异是不错的做法,无论是位置还是所用的图像都最好有明显差异。例如,您不希望用户在需要点击保存时意外碰到删除或取消。

多个布局的设计

设计人员需要确保软件将会适应用户选择将在其中运行它的环境。这意味着我们需要测试一个分辨率矩阵,确保软件良好工作,其中包括根据每种可能采用的输入方式测试每种分辨率。

这样会增加要测试的场景数目。但是通过了解不同的操作模式,您将了解自己的软件是否可满足用户期望的使用方式。

系统控件和手势

关于 Windows 8 要注意的一点是,屏幕的边距由操作系统用作访问特定功能和行为的常用位置。例如,从屏幕右侧轻扫将显示超级按钮。从左侧轻扫将允许用户循环访问活动的应用程序栈。在放置控件时,您应当避免与该区域过于接近,从而与这些系统手势混淆。

  • 超级按钮 –从屏幕的左缘轻扫便可显示 Windows 8 支持的标准功能,其中包括搜索、共享、开始、设备和设置
  • 应用程序栈 –从屏幕的右缘轻扫,就可在活动的应用程序之间切换。向内和向外轻扫可显示活动的应用程序的缩略图。
  • 应用程序栏 –从顶部或底部轻扫可显示应用程序栏,其中有上下文与活动的应用程序一致的命令,但在桌面模式中,由于桌面处于活动状态而没有活动的应用程序栏。

灵敏响应

在实施某个行为时,您应当确保应用程序立即响应。如果在与应用程序交互时延迟过长,将导致用户怀疑应用程序是否理解手势或操作。请记住,触控应当直接而简便。因此当实施某个行为时,如果可行,可尝试将复杂处理卸载到后台进行。

对于复杂的动画,建议在这些动画需要大量时间和/或处理时,以单独的线程运行它们您也可在动画的末尾完成细节渲染。

考虑内容空间

很显然,如果我们需要更大的控件尺寸以及控件之间的更大边距,就无法在单个屏幕上放置足够多的内容。就强制我们了解特定交互点的核心数据是什么而言,这并不一定是坏事。通过去除不重要的细节或将它们移动至其他屏幕并提供在它们之间顺畅导航的方法而确保屏幕的整洁有序,这样可提高应用程序的易用性。

简单是好事。挑战在于确定要点以专注于应用的本旨。确定在不同点用户需要在屏幕上呈现什么将有助于划分内容优先级。有时候当前选择的控件的上下文有助于确定在不同时刻应当显示和隐藏什么。

总结

尽管大多数 Windows 7 应用程序确实可继续在 Windows 8 上运行,但这并不意味着应用程序能够全面发挥自己的功能。如果在只能触控的设备中使用依赖于悬停或准确到像素的指点和选择操作,则对设计以及触摸的整合的构思将显得很关键。

没有完全一样的应用程序,但是您应当谨慎确定投入多少更合适。至少,要使用足够大的控件以支持只能触控的环境,让应用程序可触控。把握好控件的大小、间隔和布置方面的触摸原则,确保界面的干净整洁。

最后要注意的一点是,触摸虽然体验甚佳,但在超极本上它是键盘和鼠标之外的额外输入方式。有句格言说得好,“可以这样做并不意味着你应当这样做”,因此您应该将触摸用在最合适的地方,并发挥其他输入方式的优势。在设计应用程序时,外观以及使用模式将影响您内容的安排方式,对此有相应的数个视频和文章专门讨论了已做的相关研究(请参见下面提供的参考资料)。

支持触控的超极本是一种极佳的设备,将改变人们使用笔记本电脑的方式。马上开始利用新功能并探索构建支持触控的应用程序的方法吧。

参考

撰写本文所用的资源如下:

附件

下载 design-for-desktop-touch-and-the-ultrabook-ccefinal.pdf (890.92 KB)

新特性 英特尔® 线程构建模块 4.2

$
0
0

英特尔® 线程构建模块 (Intel® TBB) 是最为人们熟知的一种 C++ 线程库,其最新的版本现已更新至 4.2。 与之前的 4.1 版本相比,更新后的版本提供了多个重要的新特性。 一些特性已经在 TBB 4.1 更新中发布出来。

新的同步基元 speculative_spin_mutex 提供了对推测锁定的支持。 这使得在第 4 代英特尔® 酷睿™ 处理器上使用英特尔(R) 事务性同步扩展 (Intel® TSX) 硬件特性成为可能。 只要不出现可能会产生不同于非推测性锁定的结果的“冲突”,推测互斥锁在支持硬件事务性内存 (如英特尔® TSX) 的处理器上工作时就会允许多个线程获取同一个锁。 因此在非竞争性案例中就不会发生串行化。 这样就能在“短”的关键区域上大幅提高性能和可扩展性。 如果不为事务性同步提供硬件支持,推测互斥锁的作用将与非推测互斥锁类似,同时很可能会表现出更差的性能。

英特尔 TBB 现在支持准确的异常传播特性(基于 C++11 exception_ptr)。 借助 exception_ptr,异常对象可以在线程之间安全地拷贝。 这为多线程环境中的异常处理提供了灵活性。 现在准确的异常传播在所有平台的预构建库中都已提供,例如: OS X*、Windows* 和 Linux*。 OS X* 上存在两种库: 第一个库与 gcc 标准库相关联 — 默认情况下该库不支持准确的异常传播。 为了使用该特性,您应当使用与 libc++ (Clang 中的 C++ 标准库) 相关联的第二种库。 为了使用这些特性,请先创建 Intel TBB 环境然后按照以下方式构建您的应用:

# tbbvars.sh libc++
# clang++ -stdlib=libc++ -std=c++11 concurrent_code.cpp -ltbb

concurrent_unordered_setconcurrent_unordered_map容器之外,我们现在提供 concurrent_unordered_multisetconcurrent_unordered_multimap,基于 Microsoft* PPL 原型。借助 concurrent_unordered_multiset,您可以多次插入一项,而这在 concurrent_unordered_set中是不可能实现的。 同样,concurrent_unordered_multimap允许您使用同一个键值插入一个以上的 <键,值>对。 就“多” 容器而言,find会在带有一个匹配搜索键的表格中返回第一项(或者 <键,值> 对)。

Intel TBB 容器现在可以使用 C++ 11 指定的值列表(初始化程序列表)方便地进行初始化:

tbb::concurrent_vector<int> v ({1,2,3,4,5} );

当前,支持初始化程序列表的容器有以下几种:

concurrent_vector
concurrent_hash_map
concurrent_unordered_set
concurrent_unordered_multiset
concurrent_unordered_map
concurrent_unordered_multimap
concurrent_priority_queue

可扩展内存分配程序为每个线程内的已分配内存都提供了高速缓存。 这种做法虽然确保了性能,但通常会增加内存的使用率。 尽管该内存分配程序尽量避免过度使用内存,在复杂的情况下 Intel TBB 4.2 还是会把更多的控制权交给程序设计员: 现在可以通过使用 scalable_allocation_command()函数清理线程高速缓存,进而达到减少内存消耗的目的。 这也有助于大幅提高分配程序的整体性能。

Intel TBB 库已在多种不同平台上获得了广泛的使用。 移动开发人员现在可以在 Linux* 操作系统包中找到适合 Android 的预构建二进制文件。 Windows Store* 应用的二进制文件已经被添加到 Windows* 操作系统包中。

原子变量 tbb::atomic<T>现在在 C++11 中使用时已经具备了构造函数。 这允许程序设计员在声明时就对它们的值进行初始化,同时正确支持构造表达式。 此时,以下代码对 gcc 和 Clang 编译器是有效的:

tbb::atomic<int> v=5;

新社区预览特性允许等待,直到所有工作线程终止。 在应用程序分解进程时,这种情况可能很有必要,否则 TBB 动态库可能会从运行时中卸载掉(例如,假如 TBB 是一个插件的一部分)。 如果您想启用工作线程等待功能,请按以下方式对 task_scheduler_init对象进行初始化:

#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
tbb::task_scheduler_init scheduler_obj (threads, 0, /*wait_workers=*/true);

商用开源网站中找到最新的 TBB 4.2。 下载并开始使用全新功能!

用于开发移动应用的英特尔® HTML5 工具

$
0
0

by Egor Churaev

下载


用于开发移动应用的英特尔® HTML5 工具 [PDF 821.98KB]
iOS 源代码[ZIP file 168 KB]
HTML5 工具结果源代码[ZIP file 86KB]

HTML5 是最新的 HTML 标准。 英特尔公司于近日推出了一套可用于开发移动应用的 HTML5 工具。 本文将为您展示如何通过使用这些工具将一款 Apple iOS* 加速计应用移植到 HTML5 上。 请注意: 由 XDK 创建的自动生成代码可能会包含本文附录 A 中一个或多个许可协议许可的代码。如欲详细了解哪些库可用来支持您的应用,请参见 XDK 输出结果。

英特尔® HTML5 应用移植工具


我们需要做的第一件事就是选择一款 iOS 加速计应用,然后将 Objective-C* 源代码转换成 HTML5。 此时我们需要使用英特尔® HTML5 应用移植工具和此处的源代码: [iOS_source.zip] (注: 我们在附录 B 中的英特尔示例软件许可下已经提供了 IOS_source 示例代码)。您可以从此处的工具标签中下载英特尔 HTML5 应用移植工具:  http://software.intel.com/en-us/html5。 在填充完表格并使用您的电子邮件提交之后,您会得到该工具的下载链接。 有关本工具的使用说明,请访问网站:http://software.intel.com/en-us/articles/tutorial-creating-an-html5-app-from-a-native-ios-project-with-intel-html5-app-porter-tool

在您执行完所有的步骤之后,您会得到 HTML5 源代码。

英特尔® XDK


你可以在任何 IDE 中打开 HTML5 代码。 英特尔为您提供了一个可用于开发 HTML5 应用的方便工具: 英特尔® XDK – 跨平台开发工具包 (http://html5dev-software.intel.com/)。 借助英特尔 XDK,开发人员可以写出一种可在多个设备上部署的源代码。 该工具包的一个独特优势就在于您无需将其安装在您的电脑上即可使用。 您可以将其作为一个 Google Chrome* 扩展进行安装。 如果您使用的是另一个浏览器,您必须下载一个 JavaScript* 文件并运行该文件。 有时很有必要更新 Java*。

在安装完英特尔 XDK 之后,您会看到主窗口:

如果您想要移植现有的代码,请按下 “Start new” 按钮。

如果您正在创建一个新项目,请输入项目名称并检查 “Create your own from scratch”,如以下屏幕截图所示。

检查“Use a blank project”。 稍后您会看到 “Application Created Successfully!”信息。

点击“Open project folder”。

删除本文件夹中的所有文件并拷贝移植的文件。 我们现在仍然没有移植加速计应用。 我们必须创建一个适合它的接口。 有可能会删除由英特尔 HTML5 应用移植工具创建的所有钩子。 删除这些文件:

  • todo_api_application__uiaccelerometerdelegate.js
  • todo_api_application_uiacceleration.js
  • todo_api_application_uiaccelerometer.js
  • todo_api_js_c_global.js

如欲更新英特尔 XDK 中的项目,请转至 Windows 模拟器中的编辑窗口。

打开 index.html文件并从包含的文件中删除剩余的行。

打开 todo_api_application_appdelegate.js 文件并执行委托的未映射 “window” 属性。

application.AppDelegate.prototype.setWindow = function(arg1) {
    // ================================================================
    // REFERENCES TO THIS FUNCTION:
    // line(17): C:WorkBloggingechuraevAccelerometerAccelerometerAppDelegate.m
    //    In scope: AppDelegate.application_didFinishLaunchingWithOptions
    //    Actual arguments types: [*js.APT.View]
    //    Expected return type: [unknown type]
    //
    //if (APT.Global.THROW_IF_NOT_IMPLEMENTED)
    //{
        // TODO remove exception handling when implementing this method
       // throw "Not implemented function: application.AppDelegate.setWindow";
    //}
this._window = arg1;
};

application.AppDelegate.prototype.window = function() {
    // ================================================================
    // REFERENCES TO THIS FUNCTION:
    // line(20): C:WorkBloggingechuraevAccelerometerAccelerometerAppDelegate.m
    //    In scope: AppDelegate.application_didFinishLaunchingWithOptions
    //    Actual arguments types: none
    //    Expected return type: [unknown type]
    //
    // line(21): C:WorkBloggingechuraevAccelerometerAccelerometerAppDelegate.m
    //    In scope: AppDelegate.application_didFinishLaunchingWithOptions
    //    Actual arguments types: none
    //    Expected return type: [unknown type]
    //
    //if (APT.Global.THROW_IF_NOT_IMPLEMENTED)
    //{
        // TODO remove exception handling when implementing this method
       // throw "Not implemented function: application.AppDelegate.window";
    //}
return this._window;
};

打开 viewcontroller.js文件。 删除所有在旧的 iOS 应用中加速计工作时使用过的函数。 最终我们会得到这个文件:

APT.createNamespace("application");

document.addEventListener("appMobi.device.ready",onDeviceReady,false);

APT.ViewController = Class.$define("APT.ViewController");

application.ViewController = Class.$define("application.ViewController", APT.ViewController, {
    __init__: function() {
        this.$super();
    };>});

ViewController_View_774585933.css文件中,我们必须将数据元的颜色从黑色改成白色,使其在黑色背景中清晰可读: color: rgba(0,0,0,1); à  color: rgba(256,256,256,1);. 最终我们获得:

div#Label_590244915
{
	left: 20px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 320px;
	top: 0px;
	opacity: 1;
}
div#Label_781338720
{
	left: 20px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 29px;
	opacity: 1;
}
div#Label_463949782
{
	left: 20px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 51px;
	opacity: 1;
}
div#Label_817497855
{
	left: 20px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 74px;
	opacity: 1;
}
div#Label_705687206
{
	left: 70px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 29px;
	opacity: 1;
}
div#Label_782673145
{
	left: 70px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 51px;
	opacity: 1;
}
div#Label_1067317462
{
	left: 70px;
	color: rgba(256,256,256,1);
	height: 21px;
	position: absolute;
	text-align: left;
	width: 42px;
	top: 74px;
	opacity: 1;
}
div#View_774585933
{
	left: 0px;
	height: 548px;
	position: absolute;
	width: 320px;
	top: 20px;
	opacity: 1;
}

在更新了模拟器窗口之后,您会看到:

 

为了对加速计函数进行编码,我们需要使用 appMobi JavaScript Library。 有关该库的文件,请查看此处。 在您下载英特尔 XDK 时它已经被安装。

打开 index.html文件并将本行添加到脚本列表中:

<script type="text/javascript" charset="utf-8" src="http://localhost:58888/_appMobi/appmobi.js"></script>

打开 ViewController_View_774585933.html 文件。 为了使域名更符合逻辑,我们必须将其从:

<div data-apt-class="Label" id="Label_705687206">0</div>
<div data-apt-class="Label" id="Label_782673145">0</div>
<div data-apt-class="Label" id="Label_1067317462">0</div>

改为:

<div data-apt-class="Label" id="accel_x">0</div>
<div data-apt-class="Label" id="accel_y">0</div>
<div data-apt-class="Label" id="accel_z">0</div>

我们应该在 ViewController_View_774585933.css文件中执行同样的操作,此时我们必须对风格名称重新命名。

打开 viewcontroller.js文件并编写一些可以使用加速计的函数。

function suc(a) {
    document.getElementById('accel_x').innerHTML = a.x;
    document.getElementById('accel_y').innerHTML = a.y;
    document.getElementById('accel_z').innerHTML = a.z;
}

var watchAccel = function () {
    var opt = {};
    opt.frequency = 5;
    timer = AppMobi.accelerometer.watchAcceleration(suc, opt);
}

function onDeviceReady() {
    watchAccel();
}
document.addEventListener("appMobi.device.ready",onDeviceReady,false);

更新该项目,您可以在模拟器窗口中看到该过程:

借助“加速计”面板,您可以看到加速计如何在英特尔 XDK 上工作:

应用快照如下:

如欲了解完整的应用源代码,请查看 此处.
附录 A: 英特尔® XDK 代码许可协议

附录 B: 英特尔示例源代码许可协议

英特尔和 Intel 标识是英特尔公司在美国和/或其他国家的商标。
版权所有 © 2013 年英特尔公司。 保留所有权利。
*其他的名称和品牌可能是其他所有者的资产。

2013 英特尔® 创新应用大赛获奖名单

$
0
0

英特尔创新应用大赛已经正式结束,通过大赛涌现出了一批优秀的新应用。数百位开发者在俄罗斯(Habrahabr)、中国(CSDN)、印度(ThinkDigit)和美国(Code Project)四个地区网站积极参赛,为一体机和平板设备开发Windows 8应用。经过评选,获得大奖的应用是由Matthew Pilz开发的Scribblify。此外,基于平台和应用分类的其他8个分类奖项的获胜者也已产生。在此,祝贺所有提交应用的开发者和9位成绩突出的独立获奖者。

特别祝贺来自中国的参赛团队 同声(TheBestSync)公司获得(一体机)娱乐类别冠军。

 

获奖名单如下:

    大奖得主( AIO ) - Scribblify by Matthew Pilz (美国)

    AIO组别冠军 - Hot Shots by Adam H(英国)

    平板组别冠军 - One Touch Notation for MS Word by Dmitriy Golovanov(乌克兰)

    教育类别冠军(Tablet) - SensiGator by Bryan Brown(美国)

    娱乐类别冠军( AIO ) - Paint Your Music by Lin Yunfan (中国)

    金融组别冠军(Tablet) - Smart Replenishment by Vivek Anand(印度)

    游戏类别冠军( AIO ) - Wormhole Pinball by Dave Gannon(英国)

    医疗保健组别冠军(Tablet) - My Health Assistant by Tim Corey(美国)

    零售组别冠军(Tablet) - AR Jewellery by Serhiy Posokhin (乌克兰)

 

详情请点击:http://software.intel.com/en-us/blogs/2014/01/07/and-the-winners-areintel-app-innovation-contest-2013

Krita* Gemini* - 设备合二为一,性能同样卓著

$
0
0

Download PDF

为何选择二合一设备

二合一设备是一种可在笔记本电脑和平板电脑之间进行切换的 PC。 笔记本电脑模式(有时被称为台式机模式)支持将键盘和鼠标作为主要输入设备。 平板电脑模式依赖于触摸屏进行输入,因此需要手指或手写笔交互。 二合一设备(如英特尔® 超极本™ PC/平板二合一等)提供了多种精确、可控的输入选项,通过写入和触摸两种输入方式让您工作、娱乐两不误。

开发人员在修改应用时必须考虑到多个场景,才能充分利用这种新型的可变形电脑。 有些应用可能希望两种模式下的菜单和外观保持几乎相同。 而其它应用,如 Krita Gemini for Windows* 8 (参考资料 1)等,则希望慎重选择重点内容,并确保可同时应用于两种用户界面模式。 Krita 是一款素描与绘画程序,专为创建数字格式的全新绘画文件提供端到端解决方案(参考文献 2)。 本文将探讨 Krita 开发人员如何在应用中添加二合一模式感知功能,包括同时实施自动和用户自选模式切换等,以及开发人员在创建应用以便为其应用提供二合一体验时应考虑的几个方面。

简介

多年以来,计算机已经使用了多种输入方式,其中包括打孔卡、命令行和点击等。 自触摸屏推出之后,我们现在可以使用鼠标、手写笔或手指来进行点击输入。 然而,我们中的大多数人并不打算通过触摸完成所有输入操作,而借助模式感知型应用(如 Krita Gemini 等),我们无需这么做。 二合一设备(如英特尔® 超极本™ PC/平板二合一等)能够提供合适的用户界面模式,让用户在一台设备上享受到最佳的用户体验。

有多种方法可以实现二合一设备在笔记本和平板两种模式之间的来回切换(图 1 和图 2)。 英特尔网站上列举了更多二合一设备的例子(参考资料 3)。 通过分离屏幕与键盘,或者禁用键盘并将屏幕作为主输入设备(如将屏幕叠放在键盘上面等),计算机可以从笔记本模式切换至平板模式。 电脑制造商也都开始向操作系统提供这种硬件切换信息。 Windows* 8 API 事件、WM_SETTINGCHANGE 和“ConvertibleSlateMode”文本参数通过发送信号自动执行模式切换。 此外,为方便用户使用,开发人员也可添加手动模式切换按钮。

正如二合一设备可以采用多种方法在笔记本和平板模式之间进行切换一样,软件也可以有不同的切换响应方式。 在某些情况下,软件可能希望使用户界面尽可能接近笔记本电脑模式;而在其他情况下,您可能希望用户界面做出更多重要改变。 英特尔通过与众多厂商通力协作,帮助他们在其应用中添加二合一感知功能。 英特尔帮助 KO GmBH 将其 Krita Touch 应用的功能与其颇受欢迎的 Krita 开源绘画程序(笔记本电脑应用)融入全新 Krita Gemini 应用中。 Krita 项目是一个活跃的开发社区,社区成员乐于欢迎新创意和维护质量支持。 该团队添加了所需的相关机制,以支持笔记本电脑“鼠标与键盘”模式与平板电脑触摸界面模式之间的无缝切换。 观看图 3 短片中演示的 Krita Gemini 用户界面 (UI) 切换步骤。


图 3:视频 — Krita Gemini 用户界面切换—单击图标以运行

在平板电脑模式下创建,在笔记本电脑模式下完善

Gemini 团队致力于最大限度地提升两种操作模式下的用户体验。 在图 4 和图 5 中,您可以看到,在两种模式之间切换用户界面的方法有很多种,且每一种都足够出色。 借助这些方法,用户可以在平板电脑模式下“现场”作画,之后切换到笔记本电脑模式对细节进行润色和修改。


图 4:Krita Gemini 平板电脑用户界面


图 5: Krita Gemini 笔记本电脑用户界面

要使应用可在两种操作模式之间自由切换,需要执行三个主要步骤。

第一步,应用必需能够感知触摸。 幸运的是,触摸感知功能通常在二合一设备执行操作之前就已开启。 通常,这一步骤比执行模式切换重要的多。 英特尔发表了几篇关于为 Windows 8 应用添加触摸输入的文章(参考资料 4)。

第二步,添加二合一设备感知功能。 上述视频的前半部分(图 3)演示了自动传感器激活切换模式,在此例中即为旋转操作(图 6)。 后半部分演示了通过应用中的一个按钮执行的用户发起的切换模式(图 7)。


图 6:传感器状态激活的二合一设备模式切换


图 7:“切换到草图”切换按钮 — 用户发起从笔记本模式切换至平板模式的操作

自动切换支持需要定义和监控传感器状态,并在获悉状态之后执行适当的操作。 此外,如果在代码支持笔记本电脑模式的情况下,用户希望切换至平板电脑模式,那么应用也应默认支持用户发起模式切换 3。 您还可以参考英特尔文章《如何编写二合一设备感知应用》中的示例方法来添加基于传感器的切换方法(参考资料 5)。 您也可以搜索“SlateMode”,从其源代码中中找到 Krita 的模式切换管理代码(参考资料 6)。 Krita 遵守 GNU 公共许可发布。 请参考源代码库获取最新信息(参考资料 7)。

// Snip from Gemini - Define 2-in1 mode hardware states:

#ifdef Q_OS_WIN
#include <shellapi.h>
#define SM_CONVERTIBLESLATEMODE 0x2003
#define SM_SYSTEMDOCKED 0x2004
#endif

并非所有的触屏电脑均提供自动切换功能,因此,我们建议您参照本文列举的 Krita Gemini 团队的做法进行操作,通过在您的应用中添加一个按钮来支持用户手动发起模式切换。 Gemini 的按钮如图 7 中所示。按钮发起的用户界面切换执行与机械传感器发起的切换相同的功能。 屏幕信息和默认输入设备将从平板电脑模式下的触摸和大图标切换到笔记本电脑模式下的鼠标和小图标。 然而,由于传感器路径不存在,因此,按钮方法必须在没有传感器状态信息的情况下执行屏幕、图标和默认输入设备切换。 因此,开发人员应该为用户提供一种模式切换路径,且为防用户选择不恰当的模式,该路径需在没有按钮发起用户界面状态信息的情况下支持触摸或鼠标输入。

按钮定义 — Kaction() — 及其状态和操作如下述代码中所示(参考资料 6):

// Snip from Gemini - Define 2-in1 Mode Transition Button:

         toDesktop = new KAction(q);
         toDesktop->setEnabled(false);
         toDesktop->setText(tr("Switch to Desktop"));
SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), q, SLOT(switchDesktopForced()));
         connect(toDesktop,
SIGNAL(triggered(Qt::MouseButtons,Qt::KeyboardModifiers)), q, SLOT(switchToDesktop()));
sketchView->engine()->rootContext()->setContextProperty("switchToDesktop
sketchView->Action", toDesktop);

然后,工程师承担处理由按钮触发的事件的任务。 由于代码不能假定该系统就是二合一系统,因此首先要检查系统的最后一个已知状态,然后更改模式。 (参考资料 6):

// Snip from Gemini - Perform 2-in1 Mode Transition via Button:

#ifdef Q_OS_WIN
bool MainWindow::winEvent( MSG * message, long * result ) {
     if (message && message->message == WM_SETTINGCHANGE && message->lParam)
     {
         if (wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) message->lParam) == 0)
             d->notifySlateModeChange();
         else if (wcscmp(TEXT("SystemDockMode"), (TCHAR *) 
message->lParam) == 0)
             d->notifyDockingModeChange();
         *result = 0;
         return true;
     }
     return false;
}
#endif

void MainWindow::Private::notifySlateModeChange()
{
#ifdef Q_OS_WIN
     bool bSlateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);

     if (slateMode != bSlateMode)
     {
         slateMode = bSlateMode;
         emit q->slateModeChanged();
         if (forceSketch || (slateMode && !forceDesktop))
         {
             if (!toSketch || (toSketch && toSketch->isEnabled()))
                 q->switchToSketch();
         }
         else
         {
                 q->switchToDesktop();
         }
         //qDebug() << "Slate mode is now"<< slateMode;
     }
#endif
}

void MainWindow::Private::notifyDockingModeChange()
{
#ifdef Q_OS_WIN
     bool bDocked = (GetSystemMetrics(SM_SYSTEMDOCKED) != 0);

     if (docked != bDocked)
     {
         docked = bDocked;
         //qDebug() << "Docking mode is now"<< docked;
     }
#endif
}

第三步,解决测试过程中发现的问题。 虽然在触摸或鼠标模式下使用调色板相当容易,但工作区本身需要确保对焦和变焦与用户的期望保持一致。 因此,让一切变大的方法并不可取。 在平板电脑模式下,控件会变大以适应触摸交互,但屏幕图像本身需要在不同层面进行管理,以保持预期的用户体验。 请注意,在图 3 所示的视频中,在进行模式切换之后,编辑窗格中的图像与在其屏幕上时的尺寸保持相同。 开发人员通过创造性的解决方案预留了屏幕上的这一固定区域,以确保图像的一致。 另一个问题是,最初的解决方案旨在使两种用户界面均可正常运行,这反而影响了性能,因为两个用户界面共享相同的图形资源。 之后开发人员对两种用户界面进行了调整,以确保所分配的资源尽可能满足不同的需求,并尽可能优先满足活跃的用户界面。

总结

正如您所看到的,为您的应用添加二合一模式感知功能是一个非常简单的过程。 您需要了解您的用户如何在两种交互模式中与您的应用进行交互。 请阅读《为基于超极本™ 设计的二合一设备编写切换应用》的英特尔文章,了解有关应用创建和用户界面切换的更多信息(参考资料 8)。 Krita Gemini 开发这一应用的目的在于,通过在平板电脑模式下创作草图并在笔记本电脑模式下最后润色,让艺术创作变得简单。 在您向用户展示您的应用在平板和笔记本模式下的运行状况时,您可以突出显示什么内容?

参考资料

  1. Krita Gemini General Information
  2. Krita Gemini executable download (scroll to Krita Gemini link)
  3. Intel.com 2 in 1 information page
  4. Intel Article: Mixing Stylus and Touch Input on Windows* 8 by Meghana Rao
  5. Intel Article: How to Write a 2-in-1 Aware Application by Stephan Rogers
  6. Krita Gemini mode transition source code download
  7. KO GmbH Krita Gemini source code and license repository
  8. Intel® Developer Forum 2013 Presentation by Meghana Rao (pdf) - Write Transformational Applications for 2 in 1 Devices Based on Ultrabook™ Designs
  9. Krita 2 in 1 UI Change Video on IDZ or YouTube*

关于作者

Tim Duncan 是一名英特尔工程师,被朋友们形容为“小工具先生”。 他目前正在帮助开发人员将技术集成至解决方案,Tim 拥有数十年的丰富的行业经验,从芯片制造到系统集成均有涉猎。 在英特尔® 开发人员专区中搜索Tim Duncan (Intel),了解他的详细信息

 

英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。
版权所有 © 2013-2014 年英特尔公司。 所有权保留。
*其他的名称和品牌可能是其他所有者的资产。

Intel and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries.
Copyright © 2013-2014 Intel Corporation. All rights reserved.
*Other names and brands may be claimed as the property of others.

 

Gameplay: 触摸控制您最热衷的游戏

$
0
0

下载原文

Download Gameplay: Touch controls and 2-in-1 awareness for your favorite games [PDF 904KB]

GestureWorks Gameplay是实现与流行电脑游戏互动的革命性新方法。 Windows 8 Gameplay 软件可让游戏玩家使用和创建他们自己的触摸虚拟控制器,覆盖于现有电脑游戏之上。 每一虚拟控制器覆盖添加了按钮、手势和其他控制,可映射为游戏已理解的输入。 另外,玩家可使用上百种个性化手势在屏幕上互动。 Ideum 与英特尔的合作让他们可访问技术与工程资源,在 Gameplay 中实现触摸覆盖。

观看 1 分钟视频,了解 Gameplay 概念。

虚拟控制器

与传统游戏控制器不同,虚拟控制器可完全定制,玩家还能与朋友分享其虚拟控制器。 Gameplay 可在 Windows 8 平板电脑超极本二合一电脑一体机,甚至迷你触控本和大型触摸屏上运行。


图 1 - Gameplay 运行于基于英特尔凌动处理器的平板电脑中

Ideum 首席执行官和 GestureWorks Gameplay 制作者 Jim Spadaccini 表示:“虚拟控制器是真实的! Gameplay 扩展了上百种无法触摸的电脑游戏,使它们可以在全新一代便携式设备上运行。 相比物理控制器,Gameplay 的虚拟控制器更好,可支持定制和编辑。 我们迫不及待想看玩家如何使用 Gameplay 大展拳脚。”


图 2 - Gameplay 主屏幕

面向流行 Windows 游戏的几十种预建虚拟控制器都带有 GestureWorks Gameplay (现有超过 116 款)。 Gameplay 让用户不仅可以配置、布局,还能定制现有控制器。 该软件还包括易于使用的拖放编辑工具,支持用户为分布在 Steam 服务上的众多基于 Windows 的流行游戏创建虚拟控制器。


图 3 - 虚拟控制器布局图

用户可将操纵杆、 D-pad、交换器、滚轮和按钮置于屏幕任一位置,变换大小和暗度,还可添加颜色和标签。 而且,用户还可创建多个布局图,随时在游戏中切换。 这一功能支持用户根据不同游戏活动创建独特的视图,例如角色扮演游戏中的格斗与物件管理功能。


图 4 - 虚拟控制器布局图

借助 GestureWorks 手势处理引擎(又名 GestureWorks Core),Gameplay 可为超过 200 种世界通用手势提供支持。 基本世界通用手势(例如轻叩、拖、收缩/缩放,以及旋转)都是默认支持,也可定制。 这支持了覆盖触摸控制器的扩展,允许玩家访问多点触摸手势,为电脑游戏提供额外控制。 例如,在第一人称设计游戏中,简单的手势与按钮就可激活某些打斗招式。 Gameplay 甚至还包括试验性的加速器支持,这样您可倾斜您的超极本本™或平板电脑操纵竞速游戏的方向。当您将二合一设备切换至平板模式时,它可检测到这一变化,视需要打开虚拟控制器覆盖。

开发过程中克服的挑战

开发这种酷劲十足的产品并不容易,为了让 Gameplay 成为现实,需克服几个技术挑战。 有些挑战运用传统编程方法就可攻破,而有些挑战则需要更具创意的解决方案。

2 合 1 转换支持

Gameplay 开发早期,我们决定在一些新超极本上加入对于 2 合 1 转换(从翻盖模式到平板电脑模式)的基本支持。开发愿景为将这一支持如同正常开发工作一样,加入游戏之中,当游戏在翻盖模式下启动时,不显示覆盖层。游戏运行期间,如果系统转换至平板电脑模式,Gameplay 虚拟控制器覆盖层将会立即出现,支持通过触控进行游戏控制。您可在运行于支持 2 合 1 模式的任意超极本的虚拟控制器中看到这一功能。要激活此类支持,请在虚拟控制器编辑模式下,在设置选项卡的体验部分,启用 2 合 1 模式转换支持。Gameplay 开发早期,我们决定在一些新超极本上加入对于 2 合 1 转换(从翻盖模式到平板电脑模式)的基本支持。开发愿景为将这一支持如同正常开发工作一样,加入游戏之中,当游戏在翻盖模式下启动时,不显示覆盖层。游戏运行期间,如果系统转换至平板电脑模式,Gameplay 虚拟控制器覆盖层将会立即出现,支持通过触控进行游戏控制。您可在运行于支持 2 合 1 模式的任意超极本的虚拟控制器中看到这一功能。要激活此类支持,请在虚拟控制器编辑模式下,在设置选项卡的体验部分,启用 2 合 1 模式转换支持。


5虚拟控制器设置视图

.如欲了解关于如何检测 2 合 1 转换的更多信息,参考部分列出的示例应用可为您提供详尽指导。

DLL 注入

DLL 注入是一种通过加载外部动态链接库在另一程序的地址空间内执行代码的方法。 虽然 DLL 注入经常被外部程序用于不法企图,不过也有一些合法使用,包括以并非其作者最初预料或计划的方式扩展程序行为。 对于 Gameplay,我们需要一种方法将数据插入所玩程序(游戏)的输入线程中,以便触动输入可被转换成游戏理解的输入。 从大量 DLL 注入实施方法中, Ideum 选择使用 SetWindowsHookEx API 中的 Windows 挂钩呼叫。 最终,Ideum 从性能出发选择了进程特定挂钩而非全局挂钩。

从第三方启动器启动游戏

Ideum 探索了两种挂钩进入目标进程地址空间的方法。 应用可挂钩入正运行进程的地址空间,也可作为子进程启动目标可执行文件。 两种方法都没问题;然而,在实践中,当应用为目标进程的母程序时,监控和拦截目标进程创建的进程或线程则会容易得多。

这对用户登录时启动的应用客户端(例如 Steam 和 UPlay)造成问题,因为 Windows 不为启动进程提供保证次序, Gameplay 进程必须在这些进程前启动以正确钩入覆盖控制。 Gameplay 通过在安装时安装一项轻量级系统服务解决了这一问题,该服务可监控用户登录时的启动应用。当某一相关客户端应用启动时,Gameplay 可作为母程序钩入这一进程,确保覆盖控制如期显示。

经验总结

鼠标过滤

在开发过程中,发现一些游戏错误地处理触摸屏传来的虚拟鼠标输入。 这一问题在有着“鼠标外形”特征的第一人称射击游戏和角色扮演游戏中表现尤为突出。 该问题表现为从触控面板传来的鼠标输入对于显示屏上的一个点(因此在游戏环境中)不可覆盖。 这使得触摸屏就像“鼠标外形”设备一样几乎没有用。 最终解决方法就是拦截游戏的输入线程,过滤鼠标输入。 这一方法支持 Gameplay 通过屏幕上控制(例如面向“鼠标外形”功能的操纵杆)模仿鼠标输入。 尽管需要一段时间调试操纵杆反应性和盲区,感觉像鼠标一样,但一旦完成调试后,一切就变得完美了。 您可在 Fallout:新维加斯和上古卷轴:天际等游戏中 看到这种方法 的应用。

触控游戏适用评估

Ideum 花费了大量时间调整虚拟控制器以实现最佳的游戏设置。 游戏的几大元素决定了 Gameplay 的使用舒适度。 以下是几项通用指南,便于您了解哪些游戏与 Gameplay 的搭配最完美:

  • 不同游戏的 Gameplay 舒适性

更好

最好

  • 角色扮演游戏(RPG)
  • 模拟
  • 打斗
  • 体育
  • 竞赛
  • 拼图
  • 即时战略(RTS)
  • 第三人称射击
  • 平台游戏
  • Side Scrollers
  • 动作和冒险

尽管舒适度是评估 Gameplay 适用性的一个重要方面,最重要的判定标准还是稳定性。 有些游戏在采用挂钩技术、输入注入或覆盖技术后将无法运行。 导致这种情况的原因有多个,最常见的原因是游戏自行监测内存空间或输入线程以检查篡改。 虽然 Gameplay 本身是完全合法的应用,但采用了一些也可被坏人利用的技术,所以很不幸,有些游戏对这些技术非常敏感,除非本身支持触控,否则根本无法运行。

用户反馈

尽管处于开发初期,Gameplay 1.0 还是获得了关于在电脑上玩触控游戏的一些有趣的用户反馈。 收到的用户反馈明显表达出了一些倾向。 总体来看,很明显,人们普遍希望能够为游戏定制触摸界面。 其他的反馈则主要集中在以下方面的个性化游戏体验:

  • 许多虚拟控制器不适合左撇子,用户在上手后很快就会在控制器中改过来。
  • 按钮大小和位置更改为最常见功能,所以 Ideum 正考虑在未来版本 Gameplay 中添加自动手掌大小调节功能。
  • 许多用户喜欢滚动触摸输入,而非不连续的触摸和释放交互。

随着创建虚拟控制器的用户不断增多,我们期待更多的反馈。

结论

GestureWorks Gameplay 为你最热衷的游戏提供触摸控制。 这通过融合虚拟覆盖和额外交互支持(例如手势、加速器和 2-1转换)得以实现。 该项目实施过程中最有趣的部分就是用户反馈。 人们非常兴奋能在电脑上玩触摸式游戏,也非常开心能够继续享受许多以前以触摸形式玩的游戏。

About the Authors

Erik Niemeyer 现任英特尔公司软件与解决方案事业部的软件工程师。 过去 15 年来,Erik 一直致力于在英特尔微处理器上运行的应用的性能优化, 专攻全新 UI 开发和微架构调试。 业余时间里,Erik 喜欢爬山。 您可以发送电子邮件至 erik.a.niemeyer@intel.com 

Chris Kirkpatrick 是英特尔软件与服务事业部的一名软件应用工程师,隶属虚拟与交互式计算工程小组,负责为移动平台上的英特尔图形解决方案提供支持。 他拥有俄勒冈州立大学计算机科学学士学位。 您可以发送电子邮件至chris.kirkpatrick@intel.com 

资源

https://gameplay.gestureworks.com/

Related Articles

How to Write a 2-In-1 Aware Application: /en-us/articles/how-to-write-a-2-in-1aware-application
Krita Gemini Development of a 2-In-1 Aware Application with Dynamic UI for Laptop and Tablet Modes: /en-us/articles/krita-gemini-twice-as-nice-on-a-2-in-1
Detecting 2 in 1 Conversion Events & Screen Orientation in a 2 in 1 Device: /en-us/articles/detecting-slateclamshell-mode-screen-orientation-in-convertible-pc


2 合 1 用户体验

$
0
0

跟随大师级专家Luke Wroblewski 学习最新潮的用户体验, 解密2合1设备给你带来的不可思议的功能,机会和体验,我们还会为你介绍如何利用英特尔开发人员专区的资源来设计,编程,测试你的应用并开拓市场,绝对超出你的想象。

VideoWhat you will learn

如何为2合1电脑重新设计应用程序

专家Luke Wroblewski和Intel合作制作系列短片。 第一集, Luke展示2合1设备带来的惊人体验和机会。

Video ›


如何为2合1电脑重新设计界面导航

利用2合1的精彩体验,Luke展示了如何设计特殊的导航选项使应用给用户带来最佳体验。

Video ›


 

如何设计设备(待续)

在这个视频里,Luke Wroblewski介绍如何利用2合1设备里的每一个传感器制作出真实的沉浸式应用
.


新特性 英特尔® 线程构建模块 4.2

$
0
0

英特尔® 线程构建模块 (Intel® TBB) 是最为人们熟知的一种 C++ 线程库,其最新的版本现已更新至 4.2。 与之前的 4.1 版本相比,更新后的版本提供了多个重要的新特性。 一些特性已经在 TBB 4.1 更新中发布出来。

新的同步基元 speculative_spin_mutex 提供了对推测锁定的支持。 这使得在第 4 代英特尔® 酷睿™ 处理器上使用英特尔(R) 事务性同步扩展 (Intel® TSX) 硬件特性成为可能。 只要不出现可能会产生不同于非推测性锁定的结果的“冲突”,推测互斥锁在支持硬件事务性内存 (如英特尔® TSX) 的处理器上工作时就会允许多个线程获取同一个锁。 因此在非竞争性案例中就不会发生串行化。 这样就能在“短”的关键区域上大幅提高性能和可扩展性。 如果不为事务性同步提供硬件支持,推测互斥锁的作用将与非推测互斥锁类似,同时很可能会表现出更差的性能。

英特尔 TBB 现在支持准确的异常传播特性(基于 C++11 exception_ptr)。 借助 exception_ptr,异常对象可以在线程之间安全地拷贝。 这为多线程环境中的异常处理提供了灵活性。 现在准确的异常传播在所有平台的预构建库中都已提供,例如: OS X*、Windows* 和 Linux*。 OS X* 上存在两种库: 第一个库与 gcc 标准库相关联 — 默认情况下该库不支持准确的异常传播。 为了使用该特性,您应当使用与 libc++ (Clang 中的 C++ 标准库) 相关联的第二种库。 为了使用这些特性,请先创建 Intel TBB 环境然后按照以下方式构建您的应用:

# tbbvars.sh libc++
# clang++ -stdlib=libc++ -std=c++11 concurrent_code.cpp -ltbb

concurrent_unordered_setconcurrent_unordered_map容器之外,我们现在提供 concurrent_unordered_multisetconcurrent_unordered_multimap,基于 Microsoft* PPL 原型。借助 concurrent_unordered_multiset,您可以多次插入一项,而这在 concurrent_unordered_set中是不可能实现的。 同样,concurrent_unordered_multimap允许您使用同一个键值插入一个以上的 <键,值>对。 就“多” 容器而言,find会在带有一个匹配搜索键的表格中返回第一项(或者 <键,值> 对)。

Intel TBB 容器现在可以使用 C++ 11 指定的值列表(初始化程序列表)方便地进行初始化:

tbb::concurrent_vector<int> v ({1,2,3,4,5} );

当前,支持初始化程序列表的容器有以下几种:

concurrent_vector
concurrent_hash_map
concurrent_unordered_set
concurrent_unordered_multiset
concurrent_unordered_map
concurrent_unordered_multimap
concurrent_priority_queue

可扩展内存分配程序为每个线程内的已分配内存都提供了高速缓存。 这种做法虽然确保了性能,但通常会增加内存的使用率。 尽管该内存分配程序尽量避免过度使用内存,在复杂的情况下 Intel TBB 4.2 还是会把更多的控制权交给程序设计员: 现在可以通过使用 scalable_allocation_command()函数清理线程高速缓存,进而达到减少内存消耗的目的。 这也有助于大幅提高分配程序的整体性能。

Intel TBB 库已在多种不同平台上获得了广泛的使用。 移动开发人员现在可以在 Linux* 操作系统包中找到适合 Android 的预构建二进制文件。 Windows Store* 应用的二进制文件已经被添加到 Windows* 操作系统包中。

原子变量 tbb::atomic<T>现在在 C++11 中使用时已经具备了构造函数。 这允许程序设计员在声明时就对它们的值进行初始化,同时正确支持构造表达式。 此时,以下代码对 gcc 和 Clang 编译器是有效的:

tbb::atomic<int> v=5;

新社区预览特性允许等待,直到所有工作线程终止。 在应用程序分解进程时,这种情况可能很有必要,否则 TBB 动态库可能会从运行时中卸载掉(例如,假如 TBB 是一个插件的一部分)。 如果您想启用工作线程等待功能,请按以下方式对 task_scheduler_init对象进行初始化:

#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
tbb::task_scheduler_init scheduler_obj (threads, 0, /*wait_workers=*/true);

关于最新英特尔 TBB 4.2 的网站:商用开源。下载并开始使用全新功能!

2 合 1 设备用户体验

$
0
0

向世界级著名专家 Luke Wroblewski 学习领先的用户体验知识,发掘 2 合 1 设备可带来的令人惊叹的功能、机遇和用户体验。 此外,我们还将为您介绍如何利用英特尔® 开发人员专区计划资源来设计、构建、测试和推广应用,满足您的一切需求!

视频您可学到的知识

新! 如何设计跨设备应用

如何尽可能给用户最佳的跨设备体验. Luke Wroblewski分析了跨设备开发的要点. 更多信息请访问IDZ的用户体验专区UX Zone on IDZ.

Video ›


重新思考 2 合 1 设备的应用设计

可用性专家 Luke Wroblewski 携手英特尔创建了一系列简短、实用的视频。 首先,Luke 对 2 合 1 设备可提供的令人惊叹的机遇和体验进行了测试。

Video ›


重新思考 2 合 1 设备的导航

借助 2 合 1 设备能够提供的出色体验,Luke Wroblewski 介绍了如何设计具体的导航选项,以提供最佳的用户体验。.

Video ›


如何设计设备运动

在本视频中,Luke Wroblewski 展示了如何充分利用 2 合 1 设备的运动传感器,创建出真正的沉浸式体验。

Video ›


如何利用定位增强用户体验

定位数据可帮助开发人员创建出激动人心的全新用户与服务交互体验。 Luke Wroblewski 介绍了一些方法和技巧,可帮助您利用定位检测提供更出色的用户体验。

Video ›


英特尔® 集成式本机开发人员体验(英特尔® INDE)– 常见问题解答

$
0
0

目录

  1. 什么是英特尔® INDE?
  2. 英特尔® INDE 的关键特性是什么?
  3. 如何获得一套工具?
  4. 安装和运行英特尔® INDE 的系统硬件和软件要求是什么?
  5. 如何接收英特尔® INDE 提供的工具的许可?
  6. 如何接收英特尔® INDE 及其提供的工具的更新?
  7. 英特尔® INDE 可提供哪些工具?
  8. 英特尔 INDE 内的工具支持开发哪些目标设备?
  9. 我希望英特尔® INDE 支持的一款工具。 如何与英特尔分享我的反馈?
  10. 使用英特尔® INDE 是否需要互联网连接?

什么是英特尔® INDE?
英特尔® INDE是面向当今开发人员的一款测试版跨平台办公套件,可为开发人员提供工具、支持、集成和更新,以便为在 ARM* 上运行且在基于英特尔® 架构的设备上运行时可获得最佳性能的 Android* 创建高性能的 C++/Java* 应用。 首版英特尔® INDE 主要提供工具以便为 Android* 目标开发链的每个步骤提供支持,并为 Microsoft Windows* 目标提供支持。 其他的支持将在今年陆续添加。

英特尔® INDE 的关键特性是什么?
英特尔® INDE 可为环境设置、代码创建、编辑、调试和分析提供工具、样本和数据库,从而帮助开发人员更快地开发。 开发人员借助集成至常见 IDE 中的工具可快速编码,而且通过自动更新至最新的工具和技术来满足未来的需求。 英特尔® INDE 可支持运行 Microsoft Windows* 7-8.1 的 64 位主机系统、运行 Android 4.3 & up.= 的基于 ARM* 和英特尔® 架构的目标设备以及基于英特尔® 架构的 Microsoft Windows* 7-8.1 设备。 英特尔® INDE 是早期开放的测试版,可以从以下链接免费获取:intel.com/software/INDE

本版本中支持的主要特性包括:

  • 快速开发: 集成工具的常见 IDE 集成包括:Eclipse* & vs-android*
  • 易于使用: 构建、编译、分析和调试 Android* 应用的 C++/Java 工具 & 样本。
  • 适应未来需求:自动更新至最新的工具 & 技术。

如何获得一套工具?
英特尔® INDE 可作为测试版从 www.intel.com/software/INDE免费下载。

安装和运行英特尔® INDE 的系统硬件和软件要求是什么?
英特尔® INDE 可在 64 位 Microsoft Windows 7-8.1 主机系统上运行。 您的系统必须在 BIOS 中启用 英特尔® 虚拟化技术¹才能够运行英特尔® 硬件加速执行管理器(英特尔® HAXM)。 英特尔® HAXM 是英特尔® INDE 环境设置组件中的可选安装。

系统要求

  • Microsoft Windows* 7 64 位或更新版本
  • 4GB RAM
  • 6GB 可用磁盘空间

如何接收英特尔® INDE 提供的工具的许可?
英特尔® INDE 将提示您查看并接收您在工具安装期间通过英特尔® INDE 下载的所有工具的许可。

如何接收英特尔® INDE 及其提供的工具的更新?
英特尔® INDE 将定期检查软件更新。 软件更新可用时,您将会通过英特尔® INDE 接收到一条通知,且它将提示您在系统上安装该更新。

英特尔® INDE 可提供哪些工具?
英特尔® INDE 可提供主流英特尔和第三方工具可选安装包括:

英特尔工具:

  • 面向 Android* 的英特尔® INDE Media 软件包
  • 英特尔® 线程构建模块
  • Compute Code Builder
  • 面向 Android 的英特尔® C++ 编译器
  • 系统分析器 — 英特尔® 图形性能分析器(英特尔® GPA)组件
  • 平台分析器 — 英特尔® GPA 组件
  • 帧分析器 — 英特尔® GPA 组件
  • 英特尔® 帧调试器测试版
  • Environment Setup — 包括英特尔® 硬件加速执行管理器(英特尔® HAXM)的可选安装

第三方工具:

  • Google Android* SDK — Environment Setup 的可选组件
  • Android* NDK — Environment Setup 的可选组件
  • Android* Design — Environment Setup 的可选组件
  • Apache Ant* — Environment Setup 的可选组件
  • 面向 Microsoft* Visual Studio* 的 vs-android 插件 — Environment Setup 的可选安装

英特尔 INDE 内的工具支持开发哪些目标设备?
所有的工具均可用于开发 Android 4.3 及更高版本的 Android* 目标,除分析器和帧调试器之外,这两者可用于 Android 4.4 设备及更高版本。 此外,分析器、compute code builder 和线程工具还支持基于英特尔架构的设备上运行的 Microsoft Windows* 7-8.1 客户端目标。

我希望英特尔® INDE 支持的一款工具。 如何与英特尔分享我的反馈?
您的反馈对我们非常重要。 请将您的反馈提交至 英特尔® INDE 论坛

使用英特尔® INDE 是否需要互联网连接?
安装英特尔® INDE 及其中的可用工具需要稳定的互联网连接。 从英特尔® INDE 下载工具后,使用它们不需要互联网连接。 但是,维护和检查更新和通知需要使用它。

相关文章与资源:


1英特尔® 虚拟化技术要求计算机系统搭载兼容的英特尔® 处理器、基本输入输出系统(BIOS)及虚拟机监控器(VMM)。 其运行、性能及其他表现取决于硬件及软件的配置。 相关应用软件可能无法与所有的操作系统兼容。 详情请咨询您的电脑制造商。 更多信息敬请登陆 http://www.intel.com/content/www/cn/zh/virtualization/virtualization-technology/hardware-assist-virtualization-technology.html

Hot Shots* 为传统触控游戏带来变形效果

$
0
0

By William Van Winkle

Downloads


 原文 Hot Shots* Warps Conventional Touch Gaming [PDF 656KB]

Apple 将触控功能引进智能手机后,开发人员迅速获得巨大的新机遇。 现在,触摸屏 PC 再次为行业提供了同样的机遇。 超极本™设备的发展可能已经激发了触摸功能的潜力,但是目前,这种趋势正在向其他笔记本电脑类型、台式机显示器和一体式(AIO)设计不断蔓延。 该领域非常开放,英特尔正在全球范围内用竞赛的方式激发开发人员的创造力,其中一些竞赛为触控技术创新提供了良好的基础。 近来,英特尔® 应用创新竞赛联合英特尔® 开发人员专区向开发人员提出了一个挑战,让他们发掘触控领域的下一个重要目标, >Adam Hill凭借其屡获殊荣的 Hot Shots* 宇宙飞船游戏引起业界广泛关注(见图 1)。


图 1: Adam Hill 联想 Horizon* 一体机上对 Hot Shots* 主界面进行了测量。

起因、形式和功能


像许多开发人员一样,Hill 在编程方面保持了较高的职业水准,并沿承了许多传统视频游戏中的偏好,包括 Asteroids* (1979)、Micro Machines* (1991) 和 Geometry Wars* (2003)。 他是一位编写电子表格宏的管理员,并参加了软件程序员在职培训,而且一直关注娱乐方面的动态,希望有一天能够创建自己的游戏。 当英特尔在 2012 年开办第一次应用创新竞赛时,Hill 感觉自己可以大展身手。 这款名为 Celerity*的隧道游戏为 Hill 提供了许多有价值的见解。 Hill 知道自己应该将精力集中在少数几个有价值的想法上。 最重要的是,他知道自己的设计至少要吸引自己,毕竟他自己是第一位用户,如果他都感觉游戏没有趣,那么就不要提其他人了。

英特尔应用创新竞赛于 2013 年 7 月开办时,Hill 参加了竞赛。 英特尔宣布将为参赛者提供一台基于 27 英寸触摸屏的联想 Horizon 一体机,协调者特别要求“充分发挥”该平台的作用。 Hill 决心要给他们一个惊喜。 六个月内,他在该平台上工作了数百个小时,终于开发出一款游戏,这款游戏非常像早些年的两款游戏 AsteroidsGeometry Wars的结合体。 这款游戏融合了炫目的图形、重力效果和角逐激烈的玩家对抗合作设计(见图 2),Hill 承认这款游戏只有一个目的,那就是:热闹。


图 2: Hot Shots* 很明显更有利于基于触控的输入,但是它也能够与游戏控制器、键盘,甚至联想操纵杆输入兼容。

Hill 希望在游戏中复原以前多人游戏中面对面的感觉,而非通过互联网远程参与游戏赛。 玩家的宇宙飞船按照 Asteroids中的方式在屏幕中真实再现,迅速让玩家将疲倦抛诸脑后,集中全力向前方开火。 屏幕中的一颗行星能够对所有物体施加重力。 (此外,玩家还可以在屏幕上燃起第二颗恒星。) 这款游戏在整个游戏区的下方部署了一种金属丝网格,能够将上方因重力掉下的物体接住,为游戏营造出一种 3D 的效果,这是旧版的游乐场游戏所没有的。 这款游戏最多可支持九个玩家共同使用屏幕边缘的屏幕触摸控制,包括联想与触摸屏兼容的操纵杆和敲击杆(striker),其他玩家也可以通过键盘或与 Microsoft Xbox* 兼容的控制器加入游戏。 该款游戏的设计支持玩家多轮游戏 — 无论每轮持续多久。 玩家可以随时加入疯狂的破坏性大战,享受破坏的快感,然后可以随时离开,不会对其他玩家造成任何干扰。

如同大部分的现代触摸屏面板,联想的显示器支持 10 点触控。 Hill 将其玩家控制区设计在屏幕的边缘,但是他将其中一个边缘区域设计为游戏控制区,因此,最多可支持九个玩家而非十个(见图 3)。 这款游戏可以使用一根手指来玩,但是使用两根手指体验会更好,最多支持用户使用五根手指。


图 3: Hill 能够在显示器边缘配置 10 个触控区域。 其中一个用作游戏内的菜单控制。

Hill 表示:“我使用了屏幕图标按钮,因为我希望对游戏完全陌生以及不懂英语的玩家看一眼就能够了解如何控制应用。 许多控制都采用了二元的方式— 开或关,仿效了 Asteroids等经典游戏的控制方式。 此外,我还加入了大量的独立触摸设计。 当用户执行触摸操作时,为了简单起见,我希望了解几个用户中究竟是哪个用户创建了它,这样,当他们在同一个区域内触摸时将变得更简单。 从技术角度而言,这在大多数情况下是指了解 API 的情况,设计手势冲突并提供视觉反馈。”

为了让游戏更加完美,Hill 与自由作曲家 Patrick Ytting合作,邀请他在该款游戏中加入了星球配音。 而该款游戏中的炫目视觉效果要归功于游戏设计师兼图形艺术家 Thomas Tamblyn。 这两个人都希望从知识产权的所有权和收入中分一杯羹,Hill 只好满足他们的要求来完成这个项目。

解决的开发挑战


粒子系统和图形负载

毫无疑问,Hot Shots 后的图形负载可能会变得非常大。 当有两个玩家在使用时,GPU 负载尚可接受,但是玩家达到三人时,粒子和弯曲的网格就会变形,此外,恒星晨昏时刻的光线和其他效果可能会占用大量的处理资源。 如果下层引擎未正确编码,该负载将会加重。 因此,Hill 尽可能将显卡处理任务向 GPU 卸载。 为了能够在集成和独立显卡处理器之间实现流畅的性能,Hill 从头到尾编写了三遍粒子引擎。

Hill 表示:“只要我知道有东西会成为障碍,我就要着手处理它。 我不断改进,直至它成为系统中最快的部分,而非最慢的部分。 解决这一问题的一般做法是卸载到 GPU,但是对于粒子而言,解决办法是使用相对枯燥的阵列中的简单粒子池,而非有趣的链表或队列。 你所做的优化决策总是针对眼前的项目。

Hill 最初的粒子系统构基于具有粒子对象链表的一类对象。 他认为可以创建新的粒子,并将其添加到链表中,而且能够在不重建索引的情况下从列表中的任意位置删除失效的粒子。 但是,Hill 忽视了在 C# 中快速创建和销毁大量新实例对性能的影响,当实例创建和销毁达到一定的速度时,垃圾收集程序将会在繁重的负担下缓慢运行并导致性能明显下降。

为了诊断该性能低谷,Hill 开始调换软件组件。 当他删除粒子时,发现了问题的原因。 但是,他希望获得大量粒子为 Hot Shots带来的美观效果,因此,他开始浏览各种不同粒子引擎的源代码来寻找灵感。 他发现,通常情况下,其他人更倾向于使用对象池方法而非链表。 而且,他们会保留“无效”/自由粒子的 FIFO 请求。 这意味着,阵列的长度是固定的,粒子对象仅创建一次。 编程人员通过在粒子中加入一个参数来使其加入队列或从队列中删除(而非重建),从而根据需求在逻辑上激活或停用粒子。 因此,就不会用到垃圾收集程序,因为自一开始进行快速设置后,便没有再创建或销毁任何粒子。

Hill 表示:“我从中得到的教训是,在游戏中执行密集处理时,不要随便使用“新”关键词。 在项目开始时尽可能多加载关键词,然后尽量地循环使用。”

Hill 的第二个粒子引擎在速度上提高多个数量级,因此比上一个粒子引擎更稳定。 事实上,更多玩家能够在不知不觉间创建更多粒子。 但是,这款新引擎在管理自由粒子列表的队列时仍然存在效率低下的问题。 虽然不用每次都重新创建粒子,但是其效率仍然不高。 一些粒子(如弹道轨迹或刺击轨迹)的生命周期非常短,随着时间的推移,它们的重要性将会减弱或丧失。 Hill 意识到他无需回收已知状态为自由状态的粒子。 他无需不停地迭代操作列表直至找到自由粒子,而只需使用迭代中的下一个粒子即可。 借助这种方式,他只需保留一个索引值,而无需管理整个队列,从而能够大幅地减少工作量。 当索引打包至一颗已经使用的粒子时,该粒子可能已经失效或至少大部分为透明状态。 用户可能并未注意到粒子突然失效,尤其是在有其他视觉干扰的时候。 实质上,Hill 认为在这种环境中,他“...能够畏罪潜逃”。

他补充道:“面向 v3 进行优化不仅是出于技术原因,还因为我忽然发现了循环算法与用户感知大部分透明粒子的能力之间的模糊关系。 在你的游戏中,一定要考虑到这一点。 或许,你还有其他更好的方式可以采用?”

下列代码解释了 Hill 在重新修改前后的粒子引擎:

// Version 2 Init
public override void Initialize()
{
    this.particles = new FastParticle[MaxParticles];
    this.freeParticles = new Queue<FastParticle>(MaxParticles);

    for (int i = 0; i < particles.Length; i++)
    {
        particles[i] = new FastParticle();
        freeParticles.Enqueue(particles[i]);
    }

    base.Initialize();
}

// Version 3 Init - can't get much more simple than this
public override void Initialize()
{
    this.particles = new FastParticle[totalParticles];

    for (int i = 0; i < particles.Length; i++)
    {
        particles[i] = new FastParticle();
    }

    base.Initialize();
}

// Version 3 Update, with Version 2's redundant code commented out
public override void Update(GameTime gameTime)
{
    foreach (var p in particles)
    {
        if (p.Active)
        {
            this.UpdateParticle(gameTime, p);

// No need to Queue up free particles any more
// Just wrap round and re-use regardless
// Recycle First. Recycle Hard. NO MERCY (or indeed, queuing).
            //if (!p.Active)
            //{
            //    this.freeParticles.Enqueue(p);
            //}
        }
    }

    base.Update(gameTime);
}

语音识别

Hill 抽时间对不重要的游戏元素进行了试验(图 4)。 可能最值得注意的地方是游戏中“脏话警察”功能,它可以使用语音识别功能责骂对警察恶语相向的玩家。 (请记住,该游戏仅关注组设置,可能会混入年轻玩家。)但是事实证明,其执行非常困难。 底层引擎假定所有语音都是有意义的,但是此处的目的是忽略大部分的语音,只关注已知的脏话。 Hill 试图硬加入一个 API 来实现相反的目的。 不出所料,他得到的误报率很高。


图 4: Hot Shots* 的游戏设置极具吸引力。 Hill 实施了一个“脏话警察”功能,以便为各个年龄层的玩家提供相应体验。

Hill 表示:“因此,我没有提供字数受到限制的识别数据库,而提供了包括 20,000 个字的庞大字库。 通过这种方式,如果它认为听到了未包含在20,000 个随意的字之内的30多个主要脏字之一,则更可能出现了咒骂的情况。 我想到这一点的时候,还没有发现其他人这么做,但是我曾经看到过至少一款 EA Sports 游戏采用过这种类型的脏话管理方式。”

触控开发

Hill 非常喜欢使用 XNA4 处理任务,但是为 Windows* 8 上的触摸屏编写代码极具挑战,因为鉴于整个行业向 MonoGame* 迁移,内置的触摸板类型往往无法提供足够的支持。 幸运的是,Hill 已经从他以前的游戏 Celerity* 中找到了解决这一问题的方案。 Hill 强调:“解决方法是加入 Windows7.Multitouch.dll, 但是不要被它的名字所迷惑,因为它同时也对 Windows 8 解决方案非常有用。 它支持使用低级别触控处理,这能够提供出色的速度和可靠性。 虽然它支持打包版的 WM_GESTURE API,但是我更喜欢直接使用 WM_TOUCH API。”

访问 TouchUp、TouchDown 和 TouchMove 事件可通过下列基本 TouchHandler 来实现:

var touchHandler = Factory.CreateHandler<TouchHandler>(game.Window.Handle);

此外,Hill 还遇到了“触控卡住”的问题。 在某些情况下,抬起手指无法触发 TouchUp 事件。 很明显,例如,当阻止一艘船着火或添加其他用户时,这可能会导致出现严重的问题。 经验证发现,“触控选择”能够解决这一问题。

借助“选择”,每次从触控点接收到新信息时,倒计时就会重置。 这样,触控就能有效超时。 乍一看,这似乎可能导致按钮停止运行,但是实际上,触摸屏的传感器分辨率足以注册微小的手指运动 — 即使用户认为自己按住没有移动。 这些小运动注册为 TouchMove 事件,并可重启倒计时。

经验及建议


Hot Shots赢得 2013 年英特尔应用创新竞赛的一体机(AIO)类冠军出于以下几种原因。 毋庸置疑,该款游戏充分利用了大触摸屏界面,而且它还支持群体参与和互动。 Hot Shots沿承了一些经典的游戏元素,而且添加了多层图形向导,既能够让应用更现代,同时能够利用当代处理器的强大性能。 该款游戏的视效和音效非常棒,最重要的是,Hot Shots直观清晰地展现了未来的 AIO 系统如何采用全新的使用平台作为支持,并引领其不断向前发展。

有时,更多需要编码而非说明。 有时候,如要完美地确定一款应用,编程人员需要退一步考虑一下范例,尤其当涉及到新的硬件功能时。 Hill 表示:“我们必须接受,传统的按钮和滑动条的交互使用通常不是最佳的交互方式。 滑动手势非常简单,但非常有效。 比如,我们只需在一个平面上拖动指尖来操作,而非找到目标然后点击,前者轻松许多。 成功的手势通常有效且准确。 用户所需的精确度越低,他们所能达到的速度就越快。 您可以自行分析一下。 如要进一步增强性能,Hill 建议交互设计师先学习一下 Josh Clark 的 “Buttons are a Hack” 演讲。

有时候,经验将会引导编程人员在某些情况下对传统进行改变。 例如,Hill 表示,参加 2013 年英特尔应用创新竞赛等竞赛时,他并未使用单元测试。 许多编程人员都认为设备测试非常有必要,因为这能够确保质量。 但是,虽然他承认专业代码中需要单元测试。“...对于我个人而言,在这样一个竞赛中,我认为“仅编写代码”是一个极大地优势。”

Adam Hill 认为触摸屏和触觉技术拥有光明的未来。 目前,他准备开办一家公司,在 Windows 8 商店中发布Hot Shots,并帮助推广表计算。 Lenovo Horizon 证明该外形的设备具备较高的经济性,这意味着我们可以利用这一时机深入探索,通过丰富的想象力推动该平台进一步发展。

使用的资源


在开发 Hot Shots的过程中,Adam Hill 使用了英特尔的超极本™ 和平板电脑 Windows* 8 传感器开发指南,该指南位于英特尔® 开发人员专区。 此外,他还使用了 Visual Studio*Git/Bitbucket*Adobe Creative Suite*Stack Overflow。 Hill 强烈推荐MonoGame,来实现低级别的图形和效率之间的平衡。 最后,Hill 使用了 Farseer* Physics来处理撞击,虽然他对游戏的所有重力都进行了定制。

其它文章


Intel, the Intel logo, Intel Core, and Ultrabook are trademarks of Intel Corporation in the U.S. and/or other countries.
*Other names and brands may be claimed as the property of others.
Copyright © 2014. Intel Corporation. All rights reserved.

Scribblify如何借助Node.js*和Chromium*嵌入式框架交付跨平台GUI

$
0
0

By Edward J. Correia

 

简介

 

对于出生于威斯康辛州的开发人员 Matt Pilz 而言,“三”是幸运数字。 Pilz 是 LinkedPIXEL的创建者,他的创造力和勤勉连续三年赢得英特尔举办的开发人员挑战赛评委的一致好评。 近来,借助英特尔®开发人员专区的资源,其采用 10 点触控功能和基于 Google Chrome* GUI 的 Scribblify绘图应用在 2013 年英特尔® 应用创新竞赛中荣获大奖。 2013 年春,Pilz 凭借一款通过手势进行控制的绘图应用 Magic Doodle Pad在英特尔® 感知计算挑战赛上获胜。 2012 年,他凭借一款针对超极本™ 设备进行优化的动作游戏 Ballastic脱颖而出。

如同他以往的竞赛,Scribblify(图 1)的理念首次亮相也是在竞赛上,但是实际上,Scribblify 最初是用在手持设备上。 Pilz 与其他参赛者(共 200 名)从竞赛赞助方联想收到一台联想 Horizon* 一体机 (AIO) 电脑后,对于能够将自己的涂鸦应用扩展为全尺寸屏幕感到非常兴奋。 他表示:“当了解到联想 Horizon 一体机拥有 1920 高清分辨率以及支持触控功能的超大 27 英寸屏幕时,我就发现为这款应用创建一个巨大帆布尺寸的版本将会非常有趣,这样用户便能够在聚会餐桌或其它大型平面上绘制图画。 这就是当时我的设想。” 为了实现这一设想,Pilz需要修改程序,以配合比原始版本宽 4 至 6 倍的屏幕,并接受 10 个并发触点而非 1 个的输入。

图 1: Scribblify 支持用户创建各种形式的作品,从涂鸦到严肃艺术作品。

 

Scribblify 的来源

 

Pilz 首次开始开发移动应用是在 2010 年,也是在这一年,他拥有了自己的第一部 Apple iPod 触控* 移动设备。 第二年,他便发布了最早版本的 Scribblify。 Pilz 回想道:“第一个接口是针对 480x320 分辨率而设计。 为了支持当时非常有限的硬件,所有的设计都非常简单。” 2011 年 1 月,Scribblify for iOS* 进入应用市场。 Pilz 表示:“事实上,它一直不断发展,每个月都有改进。” 因此,一年前他开发了面向 Android*版本

Pilz 将 Scribblify 描述为一款包含一些特殊功能的随意绘制和涂鸦程序。 他表示:“它的特色之处在于其画笔和色彩效果。” 这种画笔(图 2)由他亲自设计,集成了其他此类绘画应用中没有的纹理。 他表示:“我更愿意相信它们非常独特。”但是,他很快继续表示,Scribblify 并非要与高端绘图应用竞争。 Pilz 表示:“iPad 上的应用(如 Photoshop*)需要大量的学习。 而且,你仅有一些有限的绘图应用,包括一个圆形画笔和少数几个选项。 我对 Scribblify 的设计完全不属于这种级别,它支持各个年龄段的人拿起来就能开始使用。”

 

图 2: Scribblify 应用拥有 62 支原始画笔。

 

挑战

 

Pilz 的第一个主要挑战是决定使用什么技术来构建面向 Microsoft Windows* 的 Scribblify 版本。 他首先使用了 TGC 的 App Game Kit* (AGK) 作为引擎来创建 Ballastic。 他表示:“这能够帮助我创建一个粗略的原型,[但是]对于许多我想要在这款应用中加入的功能,它并无法提供。” 为了符合这次竞赛的要求,应用必须面向联想的 Aura* 多用户界面构建,且不能依赖底层操作系统的主要部分。 指南中规定,开发人员不得使用任何原生 Windows 对话框。 Pilz 举了个例子说明在与文件系统集成时遇到的挑战:“通过我的应用,用户可以轻松地浏览一个标准的文件对话框来保存其作品或打开其他图像, 但这会失去英特尔所追求的那种体验...让每个应用都像一个沙箱。”

Pilz 的解决办法是使用 Node.js*,它是一个用于构建面向 V8 的网络服务的事件驱动型服务器端 JavaScript* 框架,其中 JavaScript 引擎位于 Chrome 浏览器中。 据 Node 创建者 Ryan Dahl表示,Node 框架能够通过使用事件循环解除 I/O 的阻拦,并可促进异步文件 I/O,这要归功于内建的事件池。

Pilz 表示:“使用 Node.js 的一个主要目的是开发 web 应用,并在台式机上本地使用它们 — 无论采用何种操作系统。 用户无需必须安装 Windows;Node.js 是为整个应用提供支持的后端。” 使用名为 Node-Webkit的框架和库,Pilz 可以通过自己使用标准 web 技术定制的接口和 gallery 系统轻松保存和加载图画文件。 应用可以在 Chromium* 嵌入式框架(CEF)上运行,它提供的能力可与Chrome 中强大的 HTML 和 JavaScript 渲染器媲美。

Scribblify 如何保存和删除图像
Scribblify 应用首次加载时,用户的公共文件目录将通过 Node.js 检索:


// Initialize Node.js file system
var fs = require('fs');

// Get User's Documents Folder (Win 7+)
var galleryPath = process.env['USERPROFILE'] + "\Documents\Scribblify\";
galleryPath = galleryPath.replace(/\/g, "/"); // Use forward slashes

// See if folder exists, otherwise create it
if(!fs.existsSync(galleryPath))
{
    fs.mkdir(galleryPath);
}



当用户请求保存图像时,HTML5 canvas 将转换为图像数据:


var saveImg = canvas.toDataURL();

A unique filename is generated based on timestamp, and Node.js saves the image data to the system.
// Write image data buffer to file
var data = saveImg.replace(/^data:image/w+;base64,/, "");
var buf = new Buffer(data, 'base64');
var fName = galleryPath + destFilename;
fs.writeFile(fName, buf, function(err) {
    if(err)
    {
        console.log(err);
    }
});

如果用户希望将图像从 gallery 中删除,Node.js 仅需运行下列命令即可实现:


fs.unlinkSync(galleryPath + targetImg);



获取一个现有文件列表并在 gallery 中显示会稍微有些复杂,因为我还需要检查以确保检索到的文件只有 PNG 文件(不是可能存在的其他目录或其他文件)。


var fileList = fs.readdirSync(currentPath);
var result = [];
for (var i in fileList) {
    var currentFileFull = currentPath + '/' + fileList[i];
    var currentFile = fileList[i];
    var fileExt = currentFile.split(".").pop().toUpperCase();
    var stats = fs.statSync(currentFileFull);
    if (stats.isFile() && fileExt == "PNG") {
       result.push(currentFile);
    }
    else if (stats.isDirectory()) {
         // Directory instead...
    }
}

列表生成后,阵列中存储的图像路径可以使用标准的 HTML 和 JavaScript 技术加载。 这既可用于 gallery 显示,也可用于将一件特殊的作品导回 canvas。

虽然 Pilz 能够使用自己已经熟悉的技术对应用的大部分进行建模,包括使用于前端的 HTML5 原生 canvas 元素和后端上的 Node.js,该款应用最具突破性的特性是区别于普通特性。 他表示:“我在尝试 web 应用中没有大范围尝试的方式,比如使用合成的有纹理的画笔而非程序中生成的形状来创建整个创造性绘画应用。”

最初,改程序运行良好,但是不久,Pilz 发现了一个问题。 关于其新应用的响应能力,他表示:“当使用多个触点或绘制太快时,由于 canvas 元素的性能,该款应用将会滞后几秒钟,然后再继续。” 在他这次寻找解决方案的时候,他发现了 Cocos2d-x,它是一款可在 MIT 协议下使用的跨平台开源框架,该协议近来将 WebGL 支持加入其 JavaScript 分支。

借助 Cocos2d-Javascript,Pilz 能够更轻松地将其代码移植到 WebGL,他表示,它运行更加顺畅,并能得到 AIO 开发系统内视频卡的紧密支持。 Pilz 表示:“现在,Cocos2d-Javascript 使用 WebGL 将图画渲染至屏幕...而且,它能够以每秒 60 帧的速度运行。 这既优化了体验,也增加了使用的趣味性。” Scribblify 使用针对接口元素和用户交互的标准 HTML;Pilz 介绍道,它是标准 HTML 和 JavaScript 的结合,并加入了其他的引擎,包括用于后端处理的 Node.js 以及用于简化 WebGL 渲染的 Cocos2d-Javascript。

为了解决常见问题,Pilz 采用了 Stack Overflow,它是一个面向开发专业人员和爱好者的免费问答站点。 他表示:“当我研究某个项目或遇到困难的时候,我就会去这个网站,我曾去过许多次。 它能够帮助我快速、轻松地了解其他人的建议。” 针对 Cocos2d-xNode.js,Pilz 广泛地参考了针对产品的 API;当然,他不仅在这一项目中使用了CodeProject*,多年来也在其他项目中使用过它。 他表示:“每当我想对某些编程话题进行深入调查时,我就会去那里。 他们创建了一个与竞赛相关的且非常有价值的论坛,以便能够快速地解答问题。”

此外,Pilz 还借助 Chromium 处理触控的方式以及联想 Horizon 驱动程序集找到了一个漏洞,该漏洞会导致触控无法释放,尤其在快速使用时。 他的解决方案是构建一个小型的“制衡系统”,如果错误记录了过量的触控,该系统将会发布警告。 他表示:“它将会自动将用户的作品保存到 gallery 中并提醒他们重启应用。” 然后,它将会显示将来如何阻止该问题的指南。 他表示:“[例如,]如果用户用整个手掌触碰它,它就会显示该警告:“你不可用这种方式操作,请使用指尖。” [此外,]它还会建议你重启。 在竞赛期间,我将其作为一份正式的漏洞报告提交给了 Chromium 开发人员。”


var canvas = document.getElementById('canvas');
canvas.addEventListener('touchstart', touchStartFunction, false);
canvas.addEventListener('touchend', touchEndFunction, false);
canvas.addEventListener('touchcancel', touchCancelFunction, false);
canvas.addEventListener('touchmove', touchMoveFunction, false);
canvas.addEventListener('touchleave', touchLeaveFunction, false);

hromium* 嵌入式框架(其中构建了 Google Chrome* )提供原生触控已经有一段时间,而且它易于实施。 各种形式的触控可以使用简单的事件处理程序来限制,包括touchstarttouchendtouchcanceltouchmovetouchleave

 

竞赛的时间限制以及 Pilz 正在处理的框架限制导致他延迟或放弃执行了一些 Scribblify 功能。 Pilz 表示:“我想要添加的一个重要功能是一个完整的解除和重新执行系统,但是,我并不是很熟悉如何在不影响系统的前提下来实现它。” 因此,现在我们使用一个橡皮和一个按钮来清除 canvas。 此外,他还希望再加入一些绘图模式和画笔。

调试

 

开发一款基于 web 的应用的优势是大部分的现代浏览器都配备了全面的调试工具,Pilz 表示,经证明,这在整个开发流程中非常有价值。

他表示:“对于我而言,可能最大的优势是 Chrome 开发人员工具支持全功能的 JavaScript 调试程序。 这能够帮助我创建断点,分步浏览代码,并从始至终监控特定变量和属性 — 尤其在遇到问题时。” 同时,Pilz 还能够分析明确的文档对象模型(DOM)元素和远程更新电子笔,从而更快地实现目标结果。 此外,Pilz 还发现联想在lenovodev.com上提供的开发人员资源非常有价值,尤其是 Horizon 应用集成要求(需要登录)。

多用户

 

面向 AIO 的 Scribblify 支持 10 点并发触点,这意味着,一次最多可支持 10 个用户在 canvas 上绘图。 考虑到竞赛的时间限制,Pilz 的首要考量就是用来集成多点触控功能的容易程度。 他表示:“当我最终决定使用 HTML 5 及相关技术来开发基于 web 的应用时,我知道如果我使用已经配备了桌面多点触控支持的 web 应用,处理多点触控的复杂性将会降低。”

幸运的是,CEF 在其桌面和移动版本的产品上提供了该支持。 Pilz 表示,借助整个通过 CEF 提供动力的应用,将可更轻松地存储和检索 AIO支持的触点的触控数据。

其它文章

 

更多创新

 

在使用 Scribblify或观看 LinkedPIXEL 演示视频之前,你可能很难了解到其画笔的与众不同之处。 Pilz 表示:“我认为画笔是 Scribblify 最具创新性的一个方面。 所有的设计和画笔都是我的创造,每一种都有不同的属性,当你在屏幕上绘图时,这些属性能够控制外观以及运行方式。 它们非常独特。”

此外,Pilz 还对用户接口感到很骄傲,用户接口是他在六周内从头开始构建起来的。 他表示:“为了能够借助 10 点触控功能同时使用十根手指进行绘制,或者支持两个人同时在不同端绘制,我考虑提供一种创新的体验。” Pilz 表示在需要的地方提供了几种快捷方式。 他说:“我使用了几种库,如高级拾色器。 一些获得 MIT 协议的库能够加速该进程,因此我便无需浪费时间重新进行创造了。”

此外,Scribblify 还提供了一种创新的方式来挑选和混合颜色。 Pilz 表示:“当有这么多的颜色效果供你添加时,你不会只挑选基础色。 事实上,你可以将两种颜色混到一起,使用血浆色,甚至可以添加我所称的“颜色变异(color variance)”,从而能够在绘制时将光影和黑色混在一起,从而创建出更自然的插图。”

近来,Pilz 一直在努力将 Scribblify 转化为原生 Windows 8 应用,这样,它便能够通过 Windows 商店来发布,包括通过定制的联想 Windows 8 商店。 为了以最简化的方式满足要求,即将推出的 Scribblify 版本将由 Internet Explorer* 11 而非 Chromium 提供支持,而且在停止支持 Node.js 后,将使用新的方式处理文件输入/输出。 Windows 商店版 Scribblify 预计于 2014 年 4 月至 5 月发布。

关于竞赛

 

2013 年英特尔应用创新竞赛号召来自 Code ProjectHabrahabrThinkDigitCSDN等领域的应用编程人员针对基于 Windows 的平板电脑和一体机电脑提交应用理念,范围包括金融、医疗、教育、游戏和娱乐行业。 胜出的理念将会获得赞助商联想提供的一个开发系统以及六周的时间将理念转化为演示应用;联想共提供了 200 台平板电脑和 300 台一体机电脑。 胜出的应用请见英特尔® 开发人员专区

大赛共有 500 个理念胜出,创建了 276 个演示应用,竞赛评选共分为 6 类,每类选出 5 个获胜者,因此共选出 30 个获胜者。 评选标准包括,每个应用演示其主机平台的功能的情况,满足其细分市场需求的情况,以及是否解决了目标最终用户的需求。 当然,获胜应用必须具备专业性,采用出色的图形,运行良好,无任何障碍,并能利用传感器(如有需要)。

My Health Assistant 背后的代码奥秘

$
0
0

作者:John Tyrrell

Download PDF

当身体抱恙时,许多人需要服用药品,有时每天需要服用多次。 确保按时服用正确剂量的药品需要人具备非常高的警惕性和纪律性。 软件开发人员 Tim Corey 希望利用技术提供一个从来不会忘记剂量并且具备非常好的记忆力的易用个人“医疗助手” ,以改进自我医疗过程中易出错的情况。 这一想法促使他创建了 My Health Assistant。

My Health Assistant 是一款能够帮助个人通过简单的界面管理和追踪药品使用的应用。 此外,该款应用还可提供健康日记、基于 GPS 的药店和 ER 定位器以及个人健康信息等功能。


图 1: My Health Assistant 的主菜单采用触摸 UI。

Corey 为参加 CodeProject联合英特尔® 开发人员专区举办的2013 年英特尔® 应用创新竞赛而开发了 My Health Assistant;该款应用转而获得“健康类别”的大奖。 该款应用首次创建是面向 Microsoft Windows* 台式电脑,终极目标是基于 Windows 的平板电脑,如 联想 ThinkPad* 平板电脑 2运行 Windows 8.1* 的 2 合 1 超极本™、Windows Phone* 8 及其他移动平台。

Corey 的主要开发目标是可移植性、易用性和安全性。 为了实现这些目标,他在开发过程中克服了诸多挑战,包括实施跨平台触摸 UI 并确保敏感医疗数据的安全性。 本案例研究对这些挑战、Corey 采用的解决方案以及他使用的资源进行了探讨。

决策和挑战

Corey 采用了模块化方法构建应用、处理 C# 中的每种功能并使用 XAML Windows Presentation Foundation (WPF) UI 通过 模型-视图-视图模型 (MVVM) 设计模式将其编写到一起。

选择 C#

在创建 My Health Assistant,Corey 在使用面向对象的 .NET 编程语言 C# 方面已积累了丰富的经验。 他选择 C# 作为构建应用的主要语言(使用 Microsoft Visual Studio*)出于诸多原因,包括其拥有微软的支持,这可提供整个生态系统的工具、函数库及其他资源。

C# 作为创建跨平台应用的主要方法,还可用于任何环境:从 PC、Linux* 或 Apple Mac* 到 Apple iPhone* 或 Google Android*。 此外,C# 的优势还包括,安全性和加密已深入地融入代码,将其中任何一种特性移除都非常困难,尤其在处理敏感数据(如医疗记录)时。

Corey 曾考虑过其他的语言,如 VB.NET、其他 .NET 语言以及 Java*, 但是 Corey 认为,这些语言均无法提供 C# 所提供的熟悉度和特性。

C# 函数库

微软针对 C# 提供的生态系统包括大量的优化库,Corey 认为,这些库能够显著简化编码流程。 在 My Health Assistant 中,应用数据存储在 XML 文件中以便支持跨平台移植,而且由于将函数库整合至编程框架的方式,Corey 仅需编写一行简单的代码即可处理所有数据。

除了微软的函数库以外,C# 还可使用多种第三方函数库。 对于 My Health Assistant 的 UI 框架,Corey 使用了 Caliburn.Micro,这能够支持他使用 MVVM 连接应用的前端和后端代码。 这种方法可在编写 UI 时提供极大的灵活性,且在修改后无需再进行复杂的编码。

WPF UI

为了构建 UI,Corey 选择了 Microsoft WPF 系统而未选择 Windows Forms,因为它对屏幕尺寸的变化具备出色的响应能力,这是跨平台开发的一个重要因素。 借助使用 WPF 的 Windows 8 台式电脑和 Windows Phone 8,Corey 为每个平台快速创建了不同版本的应用,并未大量进行 UI 重新编码。

在实际情况下,具备出色相应能力的 WPF UI 根据可用的屏幕大小提供特定数量和尺寸的元素。 全尺寸的台式机视图将会显示全部按钮,而移动视图仅显示 1 或 2 个按钮,并将其他按钮移动至下拉菜单中。

克服触摸和滚动问题

便携设备,无论是智能手机、平板电脑还是超极本设备上的任何应用都需要高效的触摸控制。 虽然台式机应用能够使用鼠标,但是 Corey 特别将其设计为支持触摸功能,以确保能够使用手指来进行简单的操作,如滚动菜单。 他甚至禁用了滚动条以鼓励大家使用手指来滚动屏幕。

Corey 在开发过程中所面临的最大问题是在触摸 UI 中实施菜单滚动。 该应用需要获得准确的屏幕方向以及菜单和其他应用可使用的屏幕空间尺寸;否则,应用就会认为有更多空间可用,从而将主要组件(如菜单按钮)渲染为不可见,因此便无法使用。

为了在 WPF 中支持触摸滚动, Corey 向 ScrollViewer 添加了一个属性,代表 PanningMode,请见以下代码片段。

<ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Disabled"
              VerticalScrollBarVisibility="Hidden" HorizontalAlignment="Center"
              PanningMode="VerticalOnly" Margin="0,0,0,0">

GPS 定位设备

My Health Assistant 的一个主要功能是,无论用户身在何处,它都能够帮助用户找到最近的药店或急诊室。 该功能使用了该设备的 GPS 功能和 Google Maps* API,并结合了通过 API 输入的相关位置数据,可提供精确、相关的地图信息。


图 2: Google Maps* API 集成支持用户轻松定位最近的药店或 ER。

以下代码是包含 GPS 代码的类,该类负责获取坐标并在进行定位后发起事件。 它是异步传输,这意味着,定位到坐标后,应用将继续正常运行。

public class GPSLocator
{
    public GeoCoordinateWatcher _geolocator { get; set; }

    public GPSLocator()
    {
        // Initializes the class when this class is loaded
        _geolocator = new GeoCoordinateWatcher();
    }

    // Asynchronously loads the current location into the private variables and
    // then alerts the user by raising an event
    public void LoadLocation()
    {
        try
        {
            _geolocator = new GeoCoordinateWatcher(GeoPositionAccuracy.Default);
        }
        catch (Exception)
        {
        }
    }
}

以下的代码部分调用了 GPSLocator 类,并可异步提供坐标。 此外,该代码还可提供继续获取新 GPS 坐标的选项,但是在 My Health Assistant 中,Corey 认为用户是固定的,因此将只需要一套坐标。 但是,需要保留 GPS 服务提供持续更新的坐标。

// Initializes the GPS
gps = new GPSLocator();

// Loads the watcher into the public property
gps.LoadLocation();

// Wires up the code that will be fired when the GPS coordinates are found.
// Finding the coordinates takes a couple seconds, so even though this code
// is here, it won't get fired right away. Instead, it will happen at the end
// of the process.
gps._geolocator.PositionChanged += (sensor, changed) =>
{
    // This code uses an internal structure to save the coordinates
    currentPosition = new Position();
    currentPosition.Latitude = changed.Position.Location.Latitude;
    currentPosition.Longitude = changed.Position.Location.Longitude;

    // This notifies my front-end that a couple of my properties have changed
    NotifyOfPropertyChange(() => CurrentLatitude);
    NotifyOfPropertyChange(() => CurrentLongitude);

    // A check is fired here to be sure that the position is correct (not zero).
    // If it is correct, we stop the GPS service (since it will continue to give
    // us new GPS coordinates as it finds them, which isn't what we need). If
    // the latitude or longitude are zero, we keep the GPS service running until
    // we find the correct location.
    if (currentPosition.Latitude != 0 && currentPosition.Longitude != 0)
    {
        gps._geolocator.Stop();
        LoadPharmacies();
    }
};

// This is where we actually kick off the locator. If you do not run this line,
// nothing will happen.
gps._geolocator.Start();

API 集成

Corey 知道对于提供本地药店和医院信息,选择合适的 API 至关重要,因为 My Health Assistant 必须能够提供全球各地的准确信息,而不仅是美国。 Corey 对多款具备出色潜力的 API 进行了考虑,包括 Walgreens 和 GoodRx API,但是不得不作罢,因为它们无法在美国以外的国家和地区使用。 Corey 最终选择了包含全球信息的 Factual Global Places API 数据库。 他在西班牙参加一次会议时对其效果进行了测试:当他请求最近的药店时,该应用生成了一个他所在位置数米内的药店列表。


图 3:用户能够在应用内存储其私人医生、药店和医保信息。

安全性选择

除了可移植性以外,Corey 将安全性作为该款应用的第二大要素。 该款应用的默认设置是本地存储数据,这代表将会带来较低的安全风险。 但是,在测试期间,Corey 发现用户希望在不同的设备上使用应用时访问存储的数据,这需要基于云的数据存储解决方案,从而会增加风险。

对于 XML 数据文件的云备份,Corey 没有在应用中实施复杂的 API 驱动解决方案,而是使用了更为简单的方式,将基于云的保存选项添加至本地选项旁边的资源管理器视图。 这种方法让数据备份更为直观,且支持用户在所选择的服务中实施加密技术和信任程度,以确保数据的安全 — 无论是 Microsoft SkyDrive*、Dropbox*、Box.net 还是其他服务。 以下截图展示了云存储保存选项在资源管理器视图中的显示状态。


图 4:用户可以在本地备份,或直接备份至其所选的使用资源管理器的云服务。

保存数据

最初,Corey 在处理备份功能时遇到困难,开始为 XML 文件实施复杂的存储和检索机制。 但是,一位朋友为他提供了一个简单但强大的代码,立刻帮他解决了这一问题。

将应用的所有数据都保存至 XML 文件,然后在运行时加载这些文件,以便再次为应用提供这些数据。 以下是实际保存数据的代码。

// This method saves the data to a XML file from a class instance that
// has been passed into this method. It uses generics (the T
// that is all over in here) so that any type can be used to pass
// data into this method to be saved.
public static void SaveData<T>(string filePath, T data)
{
    // Wraps the FileStream call in a using statement in order to ensure that the
    // resources used will be closed properly when they are no longer needed.
    // This file is created in read/write mode.
    using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
    {
        // This uses the XmlSerializer to convert our data into XML format
        XmlSerializer xs = new XmlSerializer(typeof(T));
        xs.Serialize(fs, data);
        fs.Close();
    }
}

以下是随后加载数据的代码。

// This method loads the data from a XML file and converts it back into
// an instance of the passed in class or object. It uses generics (the T
// that is all over in here) so that any type can be passed in as the
// type to load.
public static T LoadData<T>(string filePath)
{
    // This is what we are going to return. We initialize it to the default
    // value for T, which as a class is null. This way we can return the
    // output even if the file does not exist and we do not load anything.
    T output = default(T);

    // Checks first to be sure that the file exists. If not, don't do anything.
    if (File.Exists(filePath))
    {
        // Wraps the FileStream call in a using statement in order to ensure that the
        // resources used will be closed properly when they are no longer needed.
        // This opens the file in read-only mode.
        using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            // This uses the XmlSerializer to convert the XML document back into
            // the class format.
            XmlSerializer xs = new XmlSerializer(typeof(T));
            output = (T)xs.Deserialize(fs);
            fs.Close();
        }
    }

    // Returns the class instance, loaded with the data if the file was found
    return output;
}

代码在应用中的运行方式非常简单。 首先,使用以下命令将类中存储的数据保存至磁盘上的 XML 文件。

_records = Data.LoadData<RecordsPanelViewModel>(filePath);

使用以下命令将数据从 XML 文件加载回类,例如,当应用启动时,需要将数据重新加载回来。

Data.SaveData<RecordsPanelViewModel>(FilePath, this);
Data.SaveData<RecordsPanelViewModel>(FilePath, this);

测试

Corey 在第一开发阶段测试应用时遇到的第一个问题是出现了大量出乎意料的不良输入。 他在不同阶段分别将应用发放给几位朋友和家人,经证明,这能够有效地从用户角度公正地辨别问题,并改善 UI 和总体可用性。

模块化开发方法使得重新安排 UI 流程快速而简单,这使得能够对 Corey 收到的反馈快速迭代。

许多 UI 漏洞导致出现问题,尤其是滚动方面,最初并没有按照 Corey 预想的方式运行。 他修复的另一个漏洞出现在药品剂量计数器上。 例如,对一种药品进行 6 小时的倒计时将会导致后续药品的倒计时从 5 小时 59 分钟开始而非 6 小时。

Corey 表示,实际构建应用的过程更开心,而调试过程则艰难而漫长,但是,他尚未遇到无法解决的问题。

未来计划

当写这篇文章的时候,Corey 正准备发布 2014 年夏季版 My Health Assistant。 首版将面向 Windows 8 台式机,随后将面向 Windows Phone 8,然后是其他移动平台,包括 iOS 和 Android。 发布后,Corey 希望对用户的反馈进行收集,然后使用这些反馈进行迭代并不断改进应用。

Corey 调查的另一个特性是集成药品查找 API,以便为用户提供有关特定药店的药品以及它们在哪里的价格最便宜等信息。 GoodRx能够在美国境内提供该服务;Corey 正在寻找一个能够在全球范围内适用的解决方案。

结论

知识增长

虽然 Corey 在创建 My Health Assistant 前曾使用过 XAML,但是大多是从较简单的层面。 在应用上使用 XAML 让他显著地提高了 XAML 知识,并学习到以后如何设计和构建更出色的应用。

除了 XAML 之外,Corey 还显著地扩展了 Caliburn.Micro 知识,它是 Rob Eisenberg 为 WPF 和 XAML 创建的框架。 虽然需要在相对较短的时间内学习大量的内容,但是 Corey 认为他获得知识能够帮助他在未连接的框架环境中达成目标。

经验总结

当向他的软件开发学生提供建议时,Corey 强调了良好规划的必要性,他在开发 My Health Assistant 的过程强化了这种开发方法。 经验告诉他,在设计阶段花费更长的时间则意味着在开发和调试阶段花费的时间更少。

设计流程主要是在纸上进行的,Corey 经常会改变主意。 在开发阶段丢弃理念和特性会变得更加困难,这会导致浪费时间。 经证明,初期设计阶段的迭代更为有效。

此外,Corey 还了解到,不经测试便编入应用,并想当然地认为其应该怎么运行是非常危险的。 Corey 发现,在开发过程中,多次出现某些操作(如滚动)无法按照其预想的方式运行,从而导致不得不将代码丢弃。 Corey 建议在开发阶段构建小型应用,以测试关于特定功能和操作的假设。

开发人员介绍

Tim Corey 于 90 年代末开始成为软件开发人员和 IT 专业人员,职位是编程人员兼 IT 主管。 2011 年,Corey 获得 South University 的 IT 和数据库管理学士学位。 后来,他曾担任一家保险集团的主要编程分析师。 目前,他担任 Epicross 咨询公司的主要技术顾问;而且他还拥有自己的公司,致力于帮助企业通过优化现有技术实现更高的 IT 效率。 此外,他还教授软件开发方面的知识。

有用资源

Corey 大量依赖各种外部资源来寻找解决问题的方案。 其中最主要的是 Pluralsight,它可以提供基于注册的视频培训。 当 Corey 学习新课题或提高现有技能时,经常持续观看 3 或 4 个小时的视频。

对于特定问题,Corey 经常会访问 CodeProject并从收集的大量文章的“提示和技巧”部分,或通过在论坛上提问来寻找答案。 Corey 访问的其他资源还包括 Stack Overflow,他将其当作软件开发人员的 Wikipedia,在这里,几乎所有能想到的问题都得到解答,而且经常被解答了许多次。

Corey 有时候会使用微软文档,而且会经常从 Twitter上需求支持。 他还会向 Twitter 好友提问,或直接向特定的个人询问,如 Rob Eisenberg,Corey 说当向他求助时总会获益匪浅。

英特尔® 开发人员专区可提供跨平台应用开发工具和操作信息、平台和技术信息、代码示例以及其他专业知识帮助开发人员进行创新和不断取得进步。  加入我们的物联网Android英特尔® RealSense™ 技术Windows社区,下载工具、访问 dev 套件、与志趣相投的开发人员分享观点以及参与编程马拉松、竞赛、巡展和当地活动。

相关文章:

 

英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。
*其他的名称和品牌可能是其他所有者的资产。 
英特尔公司 © 2014 版权所有。 所有权保留。


使用 MonoGame* 开发游戏

$
0
0

作者:Bruno Sonnino

Download article as PDF

全球各地的开发人员都希望开发游戏。 为什么不呢? 游戏是计算机历史上销量最高的产品之一,游戏业务带来的财富不断吸引着开发人员的加入。 作为开发人员,我当然希望成为下一个开发愤怒的小鸟* 或光晕*的开发人员。

但是,事实上,游戏开发是软件开发最困难的领域之一。 你不得不牢记那些从来不会使用的三角函数、几何和物理类。 除此之外,你的游戏必须以吸引用户沉浸其中的方式来组合声音、视频和故事情节。 然后,你需要再编写一行代码!

为了简化难度,开发游戏使用的框架不仅要能够使用 C 和 C++,还要能够使用 C# 或 JavaScript*(是的,你可以使用 HTML5 和 JavaScript 开发适用于您的浏览器的三维游戏)。

其中一个框架是 Microsoft XNA*,该框架基于 Microsoft DirectX* 技术,支持为 Xbox 360*、Windows* 和 Windows Phone* 创建游戏。 微软已经初步淘汰了 XNA,但是与此同时,开源社区加入了一位新成员: MonoGame*。

MonoGame 是什么?

MonoGame 是 XNA 应用编程接口(API)的开源实施方式。 它不仅能够实施面向 Windows 的 XNA API,还能够实施面向 Mac* OS X*、Apple iOS*、Google Android*、Linux* 和 Windows Phone 的 XNA API。 这意味着,你只需进行较少的改动即可为所有平台开发游戏。 这种特性非常棒:你可以使用能够轻松移植至所有主要台式机、平板电脑和智能手机平台的 C# 来创建游戏。 该框架能够帮助开发人员开发出一款享誉全球的游戏。

在 Windows 上安装 MonoGame

甚至,你不需要使用 Windows 便可使用 MonoGame 进行开发。 你可以使用 MonoDevelop* (面向 Microsoft .NET 语言的开源跨平台集成开发环境 [IDE])或 Xamarin 开发的一款跨平台 IDE — Xamarin Studio*。 借助这些 IDE,你可以使用 C# 在 Linux 或 Mac 上进行开发。

如果你是一位 Microsoft .NET 开发人员,并且日常使用的工具是 Microsoft Visual Studio*,你可以像我一样将 MonoGame 安装到 Visual Studio 中并且用它来创建游戏。 在撰写本文时,MonoGame 的最新稳定版本是 3.2 版。该版本可在 Visual Studio 2012 和 2013 中运行,并支持创建支持触摸功能的 DirectX 桌面游戏。

MonoGame 安装在 Visual Studio 中随附了许多新模板,你可从中选择来创建游戏,如图 1 所示。

图 1.全新 MonoGame* 模板

现在,如要创建第一个游戏,请点击 MonoGame Windows Project,然后选择一个名称。 Visual Studio 可创建一个包括所有所需文件和参考的新项目。 如果运行该项目,则应如图 2 所示。

图 2.在 MonoGame* 模板中创建的游戏

很无聊,是吗? 只有一个蓝色屏幕;但是,构建任何游戏都要从它开始。 按 Esc,则可关闭窗口。

现在,你可以使用目前拥有的项目开始编写游戏,但是有一个问题: 如要添加任何资产(图像、子图、声音或字体),你需要将其编写为与 MonoGame 兼容的格式。 对于这一点,你需要以下选项之一:

  • 安装 XNA 游戏 Studio 4.0
  • 安装 Windows Phone 8 软件开发套件(SDK)
  • 使用外部程序,如 XNA 内容编译器

XNA Game Studio

XNA Game Studio 可提供为 Windows 和 Xbox 360 创建 XNA 游戏所需的一切组件。 此外,它还包括内容编译器,可将资产编译至 .xnb 文件,然后编译 MonoGame 项目所需的一切文件。 目前,仅可在 Visual Studio 2010 中安装编译器。 如果你不希望仅出于该原因来安装 Visual Studio 2010,则可在 Visual Studio 2012 中安装 XNA Game Studio(详见本文“了解更多信息”部分的链接)。

Windows Phone 8 SDK

你可以在 Visual Studio 2012 中直接安装 XNA Game Studio,但是在 Visual Studio 2012 中安装 Windows Phone 8 SDK 更好。 你可以用它创建项目来编译资产。

XNA 内容编译器

如果不希望安装 SDK 来编译资产,则可使用 XNA 内容编译器(详见“了解更多信息”中的链接),该编译器是一款开源程序,能够将资产编译至 MonoGame 中可使用的 .xnb 文件。

创建第一个游戏

使用 MonoGame 模板创建的上一个游戏可作为所有游戏的起点。 你可以使用相同的流程创建所有游戏。 Program.cs 中包括 Main 函数。 该函数可初始化和运行游戏:

static void Main()
{
    using (var game = new Game1())
        game.Run();
}

Game1.cs是游戏的核心。 有两种方法需要在一个循环中每秒钟调用 60 次: 更新和绘制。 在更新中,为游戏中的所有元素重新计算数据;在绘制中,绘制这些元素。 请注意,这是一个紧凑的循环。 你只有 1/60 秒,也就是 16.7 毫秒来计算和绘制数据。 如果你超出该事件,程序就会跳过一些绘制循环,游戏中就会出现图形故障。

近来,台式电脑上的游戏输入方式是键盘和鼠标。 除非用户购买了外部硬件,如驱动轮和操纵杆,否则我们只能假定没有其他的输入方法。 随着新硬件的推出,如超极本™ 设备、 2 合 1 超极本和一体机, 输入选项发生了变化。 你可以使用触摸输入和传感器,为用户提供更加沉浸式、逼真的游戏体验。

对于第一款游戏,我们将创建足球点球赛。 用户使用触摸的方式来“射门”,计算机守门员接球。 球的方向和速度由用户的敲击动作来决定。 计算机守门员将会随机选择一个方向和速度接球。 射门成功得一分。 反之,守门员的一分。

向游戏添加内容

游戏中的第一步是添加内容。 通过添加背景场地和足球开始。 如要执行该操作,则需要创建两个 .png 文件:一个文件用于足球场(图 3),另一个用于足球(图 4)。

 

图 3.足球场

 

 

图 4.足球

如要在游戏中使用这些文件,你需要对其进行编译。 如果正在使用 XNA Game Studio 或 Windows Phone 8 SDK,则需要创建一个 XNA 内容项目。 该项目不需要在同一个解决方案中。 你只需要用它来编译资产。 将图像添加至该项目并对其进行构建。 然后,访问项目目标目录,并将生成的 .xnb 文件复制至你的项目。

我更喜欢使用 XNA 内容编译器,它不需要新项目且支持按需编译资产。 仅需打开程序,将文件添加至列表,选择输出目录,并点击“编译(Compile)”。 .xnb 文件便可添加至该项目。

内容文件

.xnb 文件可用时,将其添加至游戏的 “内容( Content)” 文件夹下。 你必须为每个文件,包括“内容(Content)”“复制至输入目录(Copy to Output Directory)”以及“如果较新则复制(Copy if Newer)”,设置构建操作。 如果不执行该操作,则会在加载资产时出现错误。

创建两个字段存储足球和足球场的纹理:

private Texture2D _backgroundTexture;
private Texture2D _ballTexture;

这些字段可在 LoadContent 方法中加载:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    _spriteBatch = new SpriteBatch(GraphicsDevice);

    // TODO: use this.Content to load your game content here
    _backgroundTexture = Content.Load<Texture2D>("SoccerField");
    _ballTexture = Content.Load<Texture2D>("SoccerBall");
}

请注意,纹理的名称与内容(Content )文件夹中的文件名称相同,但是没有扩展名。

接下来,在 Draw 方法中绘制纹理:

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Green);

    // Set the position for the background
    var screenWidth = Window.ClientBounds.Width;
    var screenHeight = Window.ClientBounds.Height;
    var rectangle = new Rectangle(0, 0, screenWidth, screenHeight);
    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, rectangle, Color.White);
    // Draw the ball
    var initialBallPositionX = screenWidth / 2;
    var ínitialBallPositionY = (int)(screenHeight * 0.8);
    var ballDimension = (screenWidth > screenHeight) ?
        (int)(screenWidth * 0.02) :
        (int)(screenHeight * 0.035);
    var ballRectangle = new Rectangle(initialBallPositionX, ínitialBallPositionY,
        ballDimension, ballDimension);
    _spriteBatch.Draw(_ballTexture, ballRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

这种方法是用绿色清屏,然后绘制背景并绘制罚球点的足球。 第一种方法 spriteBatch Draw可绘制能够调整为窗口尺寸的背景,位置 0,0;第二种方法可绘制罚球点的足球。 它可调整为窗口大小的比例。 此处没有运动,因为位置不改变。 接下来是移动足球。

移动足球

如要移动足球,我们必须重新计算循环中每个迭代的位置,并在新的位置绘制它。 在 Update方法中执行新位置的计算:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition -= 3;
    _ballRectangle.Y = _ballPosition;
    base.Update(gameTime);

}

足球位置在每个循环中都会通过减去三个像素进行更新。 如果你希望让球移动地更快,则必须减去更多的像素。 变量 _screenWidth_screenHeight_backgroundRectangle_ballRectangle_ballPosition是私有字段,可在 ResetWindowSize方法中进行初始化:

private void ResetWindowSize()
{
    _screenWidth = Window.ClientBounds.Width;
    _screenHeight = Window.ClientBounds.Height;
    _backgroundRectangle = new Rectangle(0, 0, _screenWidth, _screenHeight);
    _initialBallPosition = new Vector2(_screenWidth / 2.0f, _screenHeight * 0.8f);
    var ballDimension = (_screenWidth > _screenHeight) ?
        (int)(_screenWidth * 0.02) :
        (int)(_screenHeight * 0.035);
    _ballPosition = (int)_initialBallPosition.Y;
    _ballRectangle = new Rectangle((int)_initialBallPosition.X, (int)_initialBallPosition.Y,
        ballDimension, ballDimension);
}

该方法可根据窗口的尺寸重置所有变量。 它可在 Initialize方法中调用:

protected override void Initialize()
{
    // TODO: Add your initialization logic here
    ResetWindowSize();
    Window.ClientSizeChanged += (s, e) => ResetWindowSize();
    base.Initialize();
}

这种方法在两个不同的位置调用:流程的开始以及每次窗口发生改变时。 Initialize可处理 ClientSizeChanged,因此当窗口尺寸发生改变时,与窗口尺寸相关的变量将进行重新评估,足球将重新摆放至罚球点。

如果运行程序,你将看到足球呈直线移动,直至字段结束时停止。 当足球到达目标时,你可以使用以下代码将足球复位:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition -= 3;
    if (_ballPosition < _goalLinePosition)
        _ballPosition = (int)_initialBallPosition.Y;

    _ballRectangle.Y = _ballPosition;
    base.Update(gameTime);

}

The _goalLinePosition variable is another field, initialized in the ResetWindowSize method:

_goalLinePosition = _screenHeight * 0.05;

你必须在 Draw方法中做出另一个改变:移除所有计算代码。

protected override void Draw(GameTime gameTime)
{
    GraphicsDevice.Clear(Color.Green);

   var rectangle = new Rectangle(0, 0, _screenWidth, _screenHeight);
    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, rectangle, Color.White);
    // Draw the ball

    _spriteBatch.Draw(_ballTexture, _ballRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

该运动与目标呈垂直角度。 如果你希望足球呈一定的角度移动,则需要创建 _ballPositionX字段,并增加(向右移动)或减少(向左移动)它。 更好的方法是将 Vector2用于足球位置,如下:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    _ballPosition.X -= 0.5f;
    _ballPosition.Y -= 3;
    if (_ballPosition.Y < _goalLinePosition)
        _ballPosition = new Vector2(_initialBallPosition.X,_initialBallPosition.Y);
    _ballRectangle.X = (int)_ballPosition.X;
    _ballRectangle.Y = (int)_ballPosition.Y;
    base.Update(gameTime);

}

如果运行该程序,将会显示足球以一个角度运行(图 5)。 接下来是让球在用户点击它时运动。

图 5.带有足球移动的游戏

触摸和手势

在该游戏中,足球的运动必须以触摸轻拂开始。 该轻拂操作决定了足球的方向和速度。

在 MonoGame 中,你可以使用 TouchScreen类获得触摸输入。 你可以使用原始输入数据或 Gestures API。 原始输入数据更灵活,因为你可以按照希望的方式处理所有输入;Gestures API 可将该原始数据转换为过滤的手势,以便只接受你希望接收的手势输入。

虽然 Gestures API 更易于使用,但是有几种情况不能使用这种方法。 例如,如果你希望检测特殊手势,如 X 型手势或多手指手势,则需要使用原始数据。

对于该游戏,我们仅需要轻拂操作,Gestures API 支持该操作,所以我们使用它。 首先需要通过使用 TouchPanel 类指明希望使用的手势。 例如,代码:

TouchPanel.EnabledGestures = GestureType.Flick | GestureType.FreeDrag;

. . . 仅支持 MonoGame 检测并通知轻拂和拖动操作。 然后,在 Update方法中,你可以按照如下方式处理手势:

if (TouchPanel.IsGestureAvailable)
{
    // Read the next gesture
    GestureSample gesture = TouchPanel.ReadGesture();
    if (gesture.GestureType == GestureType.Flick)
    {…
    }
}

首先,确定是否有可用手势。 如果有,则可以调用 ReadGesture获取并处理它。

使用触摸对运动执行 Initiate 操作

首先,使用 Initialize 方法在游戏中启用轻拂手势:

protected override void Initialize()
{
    // TODO: Add your initialization logic here
    ResetWindowSize();
    Window.ClientSizeChanged += (s, e) => ResetWindowSize();
    TouchPanel.EnabledGestures = GestureType.Flick;
    base.Initialize();
}

此时,足球在游戏运行时将会一直运动。 使用私有字段 _isBallMoving可在足球移动时通知游戏。 在 Update 方法中,当程序检测轻拂操作时,你将 _isBallMoving设置为 True,则足球将开始运动。 当足球到达球门线时,将 _isBallMoving设置为 False 并重置足球的位置:

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
        Keyboard.GetState().IsKeyDown(Keys.Escape))
        Exit();

    // TODO: Add your update logic here
    if (!_isBallMoving && TouchPanel.IsGestureAvailable)
    {
        // Read the next gesture
        GestureSample gesture = TouchPanel.ReadGesture();
        if (gesture.GestureType == GestureType.Flick)
        {
            _isBallMoving = true;
            _ballVelocity = gesture.Delta * (float)TargetElapsedTime.TotalSeconds / 5.0f;
        }
    }
    if (_isBallMoving)
    {
        _ballPosition += _ballVelocity;
        // reached goal line
        if (_ballPosition.Y < _goalLinePosition)
        {
            _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
            _isBallMoving = false;
            while (TouchPanel.IsGestureAvailable)
                TouchPanel.ReadGesture();
        }
        _ballRectangle.X = (int) _ballPosition.X;
        _ballRectangle.Y = (int) _ballPosition.Y;
    }
    base.Update(gameTime);

}

不再保持足球增量:程序使用 _ballVelocity字段从 x 和 y 方向上设置足球速度。 Gesture.Delta可返回上一次更新之后的运动变量。 如要计算轻拂操作的速度,请将该矢量与 TargetElapsedTime属性相乘。

如果足球正在移动,_ballPosition矢量将按照速度(每帧的像素数)增加直至足球到达球门线。 以下代码:

_isBallMoving = false;
while (TouchPanel.IsGestureAvailable)
    TouchPanel.ReadGesture();

. . .可以执行两个操作:它可以让足球停止,也可以移除输入队列的所有手势。 如果你不执行该操作,则用户能够在足球移动时进行轻拂操作,这将会使足球在停止之后再次移动。

当运行该游戏时,你可以轻拂足球,它能够以你轻拂的速度和方向进行移动。 但是,此处有一个问题。 代码无法检测到轻拂操作出现的位置。 你可以轻拂屏幕的任何位置(不仅是足球内部),然后足球将开始移动。 你可以使用gesture.Position检测轻拂的姿势,但是该属性将会一直返回 0,0,因此便无法使用该方法。

解决这一问题的方法是使用原始输入,获取触摸点,然后了解其是否在足球附近。 以下代码能够决定触摸输入是否可以触发足球。 如果可以,手势将设置 _isBallHit field

TouchCollection touches = TouchPanel.GetState();

TouchCollection touches = TouchPanel.GetState();

if (touches.Count > 0 && touches[0].State == TouchLocationState.Pressed)
{
    var touchPoint = new Point((int)touches[0].Position.X, (int)touches[0].Position.Y);
    var hitRectangle = new Rectangle((int)_ballPositionX, (int)_ballPositionY, _ballTexture.Width,
        _ballTexture.Height);
    hitRectangle.Inflate(20,20);
    _isBallHit = hitRectangle.Contains(touchPoint);
}

然后,运动仅在 _isBallHit字段为 True 时开始:

if (TouchPanel.IsGestureAvailable && _isBallHit)

如果运行游戏,你将仅可在轻拂操作启动足球时移动它。 但是,此处仍然存在一个问题:如果点击球的速度太慢或以其无法击中球门线的位置点击,则游戏将会结束,因为足球不会返回起始点。 必须为足球移动设置一个超时。 当到达超时时,游戏便会将足球复位。

Update 方法有一个参数: gameTime。 如果在移动开始时存储了 gameTime值,则可知道足球移动的实际时间,并可在超时后重置游戏:

if (gesture.GestureType == GestureType.Flick)
{
    _isBallMoving = true;
    _isBallHit = false;
    _startMovement = gameTime.TotalGameTime;
    _ballVelocity = gesture.Delta*(float) TargetElapsedTime.TotalSeconds/5.0f;
}

...

var timeInMovement = (gameTime.TotalGameTime - _startMovement).TotalSeconds;
// reached goal line or timeout
if (_ballPosition.Y <' _goalLinePosition || timeInMovement > 5.0)
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _isBallMoving = false;
    _isBallHit = false;
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

添加守门员

游戏现在可以运行了,但是它还需要一个制造难度的元素:你必须添加一个守门员,在用户踢出足球后一直运动。 守门员是 XNA 内容编译器编译的 .png 文件(图 6)。 我们必须将该编译文件添加至 Content 文件夹,为 Content 设置构建操作,并将“复制至输出目录 (Copy to Output Directory)”设置为“如果较新则复制(Copy if Newer)”。

图 6.守门员

守门员在 LoadContent方法中加载:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    _spriteBatch = new SpriteBatch(GraphicsDevice);

    // TODO: use this.Content to load your game content here
    _backgroundTexture = Content.Load<Texture2D>("SoccerField");
    _ballTexture = Content.Load<Texture2D>("SoccerBall");
    _goalkeeperTexture = Content.Load<Texture2D>("Goalkeeper");
}

然后,我们必须在 Draw方法中绘制它:

protected override void Draw(GameTime gameTime)
{

    GraphicsDevice.Clear(Color.Green);

    // Begin a sprite batch
    _spriteBatch.Begin();
    // Draw the background
    _spriteBatch.Draw(_backgroundTexture, _backgroundRectangle, Color.White);
    // Draw the ball
    _spriteBatch.Draw(_ballTexture, _ballRectangle, Color.White);
    // Draw the goalkeeper
    _spriteBatch.Draw(_goalkeeperTexture, _goalkeeperRectangle, Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

_goalkeeperRectangle 在窗口中可提供一个矩形的守门员。 它可在 Update 方法中更改:

protected override void Update(GameTime gameTime)
{…

   _ballRectangle.X = (int) _ballPosition.X;
   _ballRectangle.Y = (int) _ballPosition.Y;
   _goalkeeperRectangle = new Rectangle(_goalkeeperPositionX, _goalkeeperPositionY,
                    _goalKeeperWidth, _goalKeeperHeight);
   base.Update(gameTime);
}

_goalkeeperPositionY、_goalKeeperWidth_goalKeeperHeight字段可在 ResetWindowSize方法中更新:

private void ResetWindowSize()
{…
    _goalkeeperPositionY = (int) (_screenHeight*0.12);
    _goalKeeperWidth = (int)(_screenWidth * 0.05);
    _goalKeeperHeight = (int)(_screenWidth * 0.005);
}

守门员最初位于屏幕中央的球门线顶端附近。

_goalkeeperPositionX = (_screenWidth - _goalKeeperWidth)/2;

守门员将会在足球开始移动时开始移动。 它将会不停地以谐运动的方式从一端移动至另一端。 该正弦曲线可描述该运动:

X = A * sin(at + δ)

其中,A是运动幅度(目标宽度),t是运动时间, aδ是随机系数(这将会使运动具备一定的随机性,因此用户将无法预测守门员的速度和方向)。

该系数将会在用户通过轻拂踢出足球时进行计算:

if (gesture.GestureType == GestureType.Flick)
{
    _isBallMoving = true;
    _isBallHit = false;
    _startMovement = gameTime.TotalGameTime;
    _ballVelocity = gesture.Delta * (float)TargetElapsedTime.TotalSeconds / 5.0f;
    var rnd = new Random();
    _aCoef = rnd.NextDouble() * 0.005;
    _deltaCoef = rnd.NextDouble() * Math.PI / 2;
}

系数 a是守门员的速度,0 和 0.005 之间的数字代表 0 和 0.3 像素/秒之间的速度(1/60 秒内最大像素为 0.005)。 delta 系数是必须是介于 0 和 pi/2 之间的数字。 足球移动时,你可以更新守门员的位置:

if (_isBallMoving)
{
    _ballPositionX += _ballVelocity.X;
    _ballPositionY += _ballVelocity.Y;
    _goalkeeperPositionX = (int)((_screenWidth * 0.11) *
                      Math.Sin(_aCoef * gameTime.TotalGameTime.TotalMilliseconds +
                      _deltaCoef) + (_screenWidth * 0.75) / 2.0 + _screenWidth * 0.11);…
}

运动的幅度是 _screenWidth * 0.11(目标尺寸)。 将(_screenWidth * 0.75) / 2.0 + _screenWidth * 0.11 添加至结果,以便守门员移动至目标前方。 现在,开始构建让守门员接住球。

命中测试

如果希望了解守门员是否能够接住球,你需要知道球的矩形是否与守门员的矩形相交。 我们可以按照以下代码计算两个矩形后,在 Update方法中执行该操作:

_ballRectangle.X = (int)_ballPosition.X;
_ballRectangle.Y = (int)_ballPosition.Y;
_goalkeeperRectangle = new Rectangle(_goalkeeperPositionX, _goalkeeperPositionY,
    _goalKeeperWidth, _goalKeeperHeight);
if (_goalkeeperRectangle.Intersects(_ballRectangle))
{
    ResetGame();
}

ResetGame 仅可重构代码,将游戏重置为初始状态:

private void ResetGame()
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _goalkeeperPositionX = (_screenWidth - _goalKeeperWidth) / 2;
    _isBallMoving = false;
    _isBallHit = false;
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

借助该简单代码,游戏便可知道守门员是否能够接住球。 现在,我们需要知道足球是否能够命中。 当足球超过球门线时,执行以下代码。

var isTimeout = timeInMovement > 5.0;
if (_ballPosition.Y < _goalLinePosition || isTimeout)
{
    bool isGoal = !isTimeout &&
        (_ballPosition.X > _screenWidth * 0.375) &&
        (_ballPosition.X < _screenWidth * 0.623);
    ResetGame();
}

足球必须完全在目标中,因此,其位置必须在第一个球门柱之后(_screenWidth * 0.375)开始,并在第二个球门柱之前(_screenWidth * 0.625 − _screenWidth * 0.02)结束。 现在,我们开始更新游戏分数。

添加分数记录(Scorekeeping)

如要向游戏中添加游戏记录,我们必须添加一个新资产:spritefont,其字体可用于游戏。 spritefont是描述字体的 .xml 文件,包括字体家族及其尺寸和重量及其他属性。 在游戏中,你可以按照以下方式使用 spritefont:

<?xml version="1.0" encoding="utf-8"?><XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics"><Asset Type="Graphics:FontDescription"><FontName>Segoe UI</FontName><Size>24</Size><Spacing>0</Spacing><UseKerning>false</UseKerning><Style>Regular</Style><CharacterRegions><CharacterRegion><Start> </Star><End></End></CharacterRegion></CharacterRegions></Asset></XnaContent>
你可以使用 XNA 内容编译器来编译该 .xml 文件,并将生成的 .xnb 文件添加至项目的 Content 文件夹;将其构建操作设置至 Content,并将“复制至输出目录(Copy to Output Directory)”设置为“如果较新则复制(Copy if Newer)”。 字体可在 LoadContent方法中加载:
_soccerFont = Content.Load<SpriteFont>("SoccerFont");

ResetWindowSize中,重置得分情况:

var scoreSize = _soccerFont.MeasureString(_scoreText);
_scorePosition = (int)((_screenWidth - scoreSize.X) / 2.0);

如要保持记录,需要声明两个变量: _userScore_computerScore。 命中时,_userScore变量增加,未命中、超时或守门员接住球时,_computerScore增加:

if (_ballPosition.Y < _goalLinePosition || isTimeout)
{
    bool isGoal = !isTimeout &&
                  (_ballPosition.X > _screenWidth * 0.375) &&
                  (_ballPosition.X < _screenWidth * 0.623);
    if (isGoal)
        _userScore++;
    else
        _computerScore++;
    ResetGame();
}
…
if (_goalkeeperRectangle.Intersects(_ballRectangle))
{
    _computerScore++;
    ResetGame();
}

ResetGame 可重新创建得分文本,并设置其情况:

private void ResetGame()
{
    _ballPosition = new Vector2(_initialBallPosition.X, _initialBallPosition.Y);
    _goalkeeperPositionX = (_screenWidth - _goalKeeperWidth) / 2;
    _isBallMoving = false;
    _isBallHit = false;
    _scoreText = string.Format("{0} x {1}", _userScore, _computerScore);
    var scoreSize = _soccerFont.MeasureString(_scoreText);
    _scorePosition = (int)((_screenWidth - scoreSize.X) / 2.0);
    while (TouchPanel.IsGestureAvailable)
        TouchPanel.ReadGesture();
}

_soccerFont.MeasureString 可使用选中字体测量字符串,你可以使用该测量方式来计算得分情况。 得分可在 Draw 方法中进行绘制:

protected override void Draw(GameTime gameTime)
{
…
    // Draw the score
    _spriteBatch.DrawString(_soccerFont, _scoreText,
         new Vector2(_scorePosition, _screenHeight * 0.9f), Color.White);
    // End the sprite batch
    _spriteBatch.End();
    base.Draw(gameTime);
}

打开球场灯光

作为最后一个触摸设计,该款游戏可在室内光线较暗时打开球场灯光。 全新超极本和 2 合 1 设备通常具备一个光线传感器,你可以用它来确定室内光线的程度并更改背景的绘制方式。

对于台式机应用,我们可以使用面向 Microsoft .NET Framework 的 Windows API Code Pack,它是一款支持访问 Windows 7 及更高版本操作系统特性的库。 但是,在该游戏中,我们采用了另一种方式:WinRT Sensor API。 这些 API 虽然面向 Windows 8 而编写,但是同样适用于台式机应用,且不经任何更改即可使用。 借助它们,你无需更改任何代码即可将应用移植到 Windows 8。

英特尔® 开发人员专区(IDZ)包括一篇如何在台式机应用中使用 WinRT API 的文章(详见“了解更多信息”部分)。 基于该信息,你必须在 Solution Explorer 中选择该项目,右击它,然后点击 Unload Project。 然后,再次右击该项目,并点击 Edit project。 在第一个 PropertyGroup中添加 TargetPlatFormVersion标签:

<PropertyGroup><Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
…
  <FileAlignment>512</FileAlignmen><TargetPlatformVersion>8.0</TargetPlatformVersion></PropertyGroup>

再次右击项目,然后点击Reload Project。 Visual Studio 将重新加载该项目。 当向项目中添加新标签时,将能够在 Reference Manager 中看到 Windows标签,如图 7 所示。

图 7.Reference Manager 中的 Windows* 标签

向项目中添加 Windows 参考。 此外,你还需要添加 System.Runtime.WindowsRuntime.dll参考。 如在汇编程序列表中看不到,则可浏览 .Net Assemblies文件夹。 在我的设备上,路径为 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5

现在,你可以开始编写代码来检测灯光传感器:

LightSensor light = LightSensor.GetDefault();
if (light != null)
{

如果有灯光传感器,GetDefault方法可返回一个非空变量,以便用来检查灯光变化。 通过编写 ReadingChanged事件来执行该操作,如下:

LightSensor light = LightSensor.GetDefault();
if (light != null)
{
    light.ReportInterval = 0;
    light.ReadingChanged += (s,e) => _lightsOn = e.Reading.IlluminanceInLux < 10;
}

如果读取的值小于 10,则变量 _lightsOn为真,你可以用它以不同的方式来绘制背景。 如果你看到 spriteBatchDraw方法,将会发现第三个参数为颜色。 到目前为止,你只使用过白色。 该颜色用于为位图着色。 如果你使用白色,则位图中的颜色将保持不变;如果你使用黑色,则位图将会全部变为黑色。 你可以使用任何颜色为位图着色。 你可以使用颜色来打开灯光,当灯光关闭时使用绿色,开启时使用白色。 在 Draw方法中,更改背景的绘制:

_spriteBatch.Draw(_backgroundTexture, rectangle, _lightsOn ? Color.White : Color.Green);

现在,当你运行程序时,当灯光关闭时你将会看到深绿色背景,当灯光开启时将会看到浅绿色背景(图 8)。

图 8.完整游戏

现在你拥有了一款完整的游戏。 但是,它尚且未完成,它还需要大量改进(命中时的动画,守门员接住球或球击中球门柱时的反弹画面),但是我把它作为家庭作业留给你。 最后一步是将游戏移植到 Windows 8。

将游戏移植至 Windows 8。

将 MonoGame 游戏移植至其他平台非常简单。 你只需要在 MonoGame Windows Store Project类型的解决方案中创建一个新项目,然后删除 Game1.cs文件并将 Windows Desktop 应用 Content文件夹中的四个 .xnb 文件添加至新项目的 Content 文件夹。 你无需向源文件中添加新文件,只需添加链接。 在 Solution Explorer 中,右击 Content 文件夹,点击 “添加/现有文件(Add/Existing Files)”,在 Desktop 项目中选择四个 .xnb 文件,点击“添加(Add)”按钮旁边的下箭头,并选择“添加为链接(Add as link)”。 Visual Studio 可添加四个链接。

然后,将 Game1.cs文件从以前的项目添加至新项目。 重复对 .xnb 文件所执行的流程:右击项目,点击“添加/现有文件(Add/Existing Files)”,从其他项目文件夹中选择 Game1.cs 文件,点击“添加(Add)”按钮旁边的下箭头,然后点击“添加为链接(Add as link)”。 最后需要改动的地方是 Program.cs,你需要对 Game1类的命名空间进行更改,因为你现在使用的是台式机项目中的 Game1类。

完成 — 你创建了一款适用于 Windows 8 的游戏!

结论

游戏开发本身是一项困难重重的任务。 你需要记住三角、几何和物理类,并运用这些概念来开发游戏(如果教授者在教授这些课题时使用的是游戏,会不会很棒?)

MonoGame 让该任务更简单。 你无需处理 DirectX,可以使用 C# 来开发游戏,并且能够完全访问硬件。 你可以在游戏中使用触摸、声音和传感器。 此外,你还可以开发一款游戏,对其进行较小的修改并将其移植至 Windows 8、Windows Phone、Mac OS X、iOS 或 Android。 当你希望开发多平台游戏时,这是一个巨大的优势。

 

了解更多信息

关于作者

Bruno Sonnino 是巴西的微软最有价值专家(MVP)。他是一位开发人员、咨询师兼作家,曾编写过五本有关 Delphi 的书籍,并由 Pearson Education Brazil 以葡萄牙语出版,此外,他还在巴西和美国的杂志和网站上发表过多篇文章。

采用由英特尔® 核芯显卡和锐炬™ 显卡增强的开放标准的 Adobe Photoshop*

$
0
0

Download PDF [1.13MB]

介绍

在本文中,我们将探讨过去几年内,Adobe 工程师使用 OpenGL* 和 OpenCL™ 增强 Photoshop 以提高硬件可用性方面所取得的进步。 Adobe 团队选择了两种特性模糊锐化(Blur Sharpen)和智能锐化(Smart Sharpen)作为近期工作的重心,因为此两者提供的处理速度和质量都不够理想。 我们将在本文中讨论这两种特性的效果。 

开放标准语言、Adobe Photoshop 和英特尔

数年以来,人们一直使用 OpenGL(开放图形语言)提升不同平台间的渲染性能和资源利用率。 OpenCL(开放计算语言)是一款免费的开放标准,支持中央、图形和其他处理器进行可移植、通用及并行编程。 OpenCL 标准是现有 OpenGL API 的补充,可为 OpenGL 使用图形处理器进行渲染提供常规计算例程。 OpenCL 可为开发人员提供统一的编程环境在既定平台内的所有处理资源上执行代码。

Adobe Photoshop是一款领先的图形产业应用,可用于图形编辑和操作。 需要大量处理和内存资源的用户 — Photoshop 是一款强大的应用,要求计算机具备最高的性能。 为支持其图形处理能力,Adobe 在许多代 Photoshop 中使用了开放标准。 它现在已经进行了更新,可利用 OpenCL,这能够提供更高的性能。 

英特尔为该报告提供了测试。 此外,英特尔还提供了大量工具和 SDK 来加速视觉计算的开发。 其中包括适用于英特尔® 处理器的开发人员指南(页面上每一代英特尔图形处理器的指南链接)。 最新指南包括针对第四代英特尔® 酷睿™ 处理器图形的图形开发人员指南 — 现在包括 OpenGL)、针对 OpenCL 应用的英特尔® SDK以及视觉计算专用网站。 

对于一款强大的应用,如 Photoshop,使用诸如 OpenGL 和 OpenCL 等开放标准能够提高性能,支持处理例程跨平台使用,并支持更轻松地使用其他 Adobe 产品。 

Photoshop 之使用 OpenGL 和 OpenCL 标准

数年前,在 Adobe Creative Suite* 4 Photoshop 版(Photoshop CS4)中,Adobe 开发人员将 OpenGL 工作的重心放在增强 Canvas 和 3D 交互上。 他们使用 OpenGL API 实施了 Smooth Zoom、Panning、Canvas Rotate、Pixel Grid 和 3D Axis/Lights 来增强性能。 打开这些特性(在首选项中),启用 “Use Graphics Processor”,选择 “Advanced Settings” 按钮,从下拉菜单中选择 “Advanced Drawing Mode”,勾选“Use Graphics Processor to Accelerate Computation” 和 “Use OpenCL” 的复选框。参考图 1 和图 2,了解 Photoshop 用户界面中的建议设置。

Photoshop on Intel

图 1: Photoshop* 首选项对话框中的图形设置

Photoshop Settings图 2: 在 Drawing Mode 下拉菜单中选择 “Advanced”

借助 Photoshop CS5,开发人员使用了 OpenGL 来加速用户界面(UI)和添加 Pixel Bender 插件。目标 UI 特性包括 Scrubby Zoom、HUD Color Picker、Color Sampling Ring、Repousse 和 3D Overlays。 借助这些新特性,OpenGL 模式扩展至基本、常规和高级方法。

然后,在 Photoshop CS6 中,该团队使用 OpenGL 和 OpenCL 中的标准化特性强化了内容编辑。 开发人员使用 OpenGL 添加了 Adaptive Wide Angle、Liquify、Oil Paint、Puppet Warp、Lighting Effects 和 3D Enhancements。 他们还使用 OpenCL 标准添加了 Field/Iris Tilt/Shift 功能和 Blur 功能。

今天,借助最新版 Adobe Creative Suite,Creative Cloud 可使用 Smart Sharpen 以及可选的 “Use Graphics Processor” 和 “Use OpenCL” 模式进一步增强 Photoshop 应用。

支持 OpenGL 和 OpenCL 的英特尔核芯显卡设备

以下英特尔图形设备需要默认面向 OpenGL 和 OpenCL 图形加速启用:

  • 第四代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 4200、4400、4600、P4600、P4700
    • 核芯显卡 5000
    • 锐炬™ 显卡 5100
    • 锐炬™ Pro 显卡 5200
  • 第三代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 4000、P4000
  • 第二代英特尔® 酷睿™ 处理器
    • 英特尔® 核芯显卡 3000、P3000

开发特定 Photoshop 增强特性

开发人员如何实现这些成果? Photoshop 使用了一套图层将许多高级特性应用至图像。 图 3 解释了这一概念,它将一个非常简单的图像的三个图层展示为白色空间。 示例中的效果、红色和蓝色图层在堆栈中是单独图层。 可应用到图层中的效果包括锐化、模糊和红眼去除。 无需改变源文件即可将效果应用至最终图像。 此外,用户还可对这些图层进行整理、堆叠和结合以提供混合效果(见右图),如将红色和蓝色组合在一起得到紫色(PURPLE)。 此外,还包括一些特殊图层,称 “mask layer”,它可以限制应用至指定图像区域的效果。

Photoshop on Intel图 3: 单独(左侧)和组合(右侧)图层

此外,图像结合也适用于 Photoshop 纹理。 Photoshop 纹理是指使用其他图层与现有图层混合,或对其进行覆盖,从而使图像呈现“纹理化”。 注意下图中,左下侧的砖块如何在透明度较低的情况下,为中间图像中雕像的斗篷提供纹理。

Photoshop on Intel图 4: 使用 Photoshop* 中的纹理的示例

Adobe 使用了 OpenGL API 来增强 Photoshop 纹理/图层效果。 在 OpenGL Advanced Mode 中,OpenCL 的 “”调用支持着色工具(Shader Tool)应用棋盘格滤镜合成、色调映射和配色。

锐化焦点

运动照片中广泛使用锐化步骤,因为只需增加一些控制便可对动态照片产生很大的影响。 图 5 展示了如何通过在照片编辑时应用锐化步骤来改进细节。 注意,右侧的“锐化后”图像中,文本、星星甚至笔触细节都更加显著。

Photoshop on Intel图 5: 原始图像(左)和锐化后图像(右)

但是,锐化后步骤可能会产生一些多余的负效果。 原始图像中相对清晰或不重要的细节会产生人造的效果,这类似于增加了图像的“噪音”,从而产生光晕效果。 在该版本中,Adobe 采用了使用 OpenCL 标准实施的基于分块的“降噪和锐化”算法,对传统智能锐化进行了革新。 全新的基于分块的算法可生成没有任何光晕效果的清晰图像。 此外,降噪步骤抑制了“进行锐化时“噪音”增强”的问题。 比较以下图 6、图 7 和图 8 中的图像。 借助该结果,Adobe 希望使用这些标准进一步改进所有的锐化工具。

Photoshop on Intel图 6: 原始文本图像

Photoshop on Intel图 7: 应用了传统智能锐化的图像(带有光晕效果)

Photoshop on Intel图 8: 应用可基于分块的智能锐化的图像

在焦点中应用模糊(Blur)功能

使用 OpenCL 能够改善的另一种编辑工具功能是 Blur 工具。 有许多方法可以强调和模糊图像的某一部分。 许多质量是在照片拍就时形成的,但是经过一些后期处理,能够改进,至少改变照片的效果。 红眼去除和裁剪是非常常见的后期处理任务,而图像的清晰度也能够进行改进。 特定图像区域锐化能产生很大的影响。

Photoshop on Intel图 9: 蒙娜丽莎(Francesco del Giocondo 的妻子 Lisa Gherardini 的画像)画家:列奥纳多·达·芬奇

在作品《蒙娜丽莎》中,列奥纳多·达·芬奇(图 9)[8]通过将蒙娜丽莎的图像置于有些许散焦的乡村风景之前来强调其在肖像中的主题。 通过对背景进行模糊处理,他帮助观者将焦点放在其主题(画作中最重要的部分)而非背景。 以下是模糊处理如何改进现代图像的示例。 我们很难找到照片的主题,模糊处理能够帮助突出图像的主题。 我以图 6 中使用的锐化图像为例,通过应用 Blur 工具进一步强调图像中央的星星,这将会让星星在右下方的图像中更清晰(图 10)。 模糊处理能够改变我们看图像的角度,因此星星能够更突出。 毋庸置疑,有许多方法可以对图像进行模糊处理(出于特定目的),而这种方法最新。

Photoshop on Intel
图 10: 原始图像(左)锐化(中)后,添加了 Blur(右)进行强调

向图像添加 Blur 如同使用了彩色蜡笔,只是在这里,鼠标是蜡笔,颜色是 Blur 功能。 如要应用 Blur,需要选择 Blur 工具,调整 “笔刷(brush)”工具(可从 1 个屏幕像素调整至整个图像尺寸的光标)的尺寸,以符合想要进行模糊处理的图像区域的尺寸,然后点击并按住鼠标并对想要进行模糊处理的图像区域 “着色或擦除(coloring or scrubbing)”。 执行越多的着色操作,就会有越多的模糊效果应用到图像区域。

英特尔增强图形性能

添加 OpenCL Blur 工具的操作提出了一些挑战,也提供了一些好的学习机会。 该团队希望利用主机平台上的所有资源来平衡工作负载。 跨平台操作包括 Windows* 和 Mac* OS 至关重要。 这些因素促使他们选择了 OpenCL。 该团队最终选择了 Photoshop 中现有的模糊化工具,并将其从优化的 CPU 代码中移植至 OpenCL 内核。

Adobe 希望降低 Blur 的复杂性,未采用 OpenCL 以前需要在多个线程上运行多个命令队列。 此外,他们还在低端视频子系统上遇到资源限制的问题,如超时和内存不足故障。 最终,他们通过使用基于 OpenCL 的解决方案降低了平台变量,如驱动程序堆栈以及多种编译器的使用。  借助 OpenCL,他们能够将部分图像缓存至本地内存并为图形处理器将图像分解为 2k X 2k 数据块,从而大幅降低挑战。 这些改进带来更高的可靠性,并通过利用 GPU 将过滤速度提高了 4-8 倍。

英特尔的测试表明,以下 Photoshop 操作的性能得到提升,因为随着英特尔核芯显卡不断更新换代,可用的执行单元和内存带宽不断提升,如下图所示(图 11)。[1]

Photoshop on Intel
图 11: 基于多代英特尔核芯显卡的具备 OpenGL* 性能的 Photoshop*

在进行测试时启用和禁用 OpenGL 或 OpenCL 特性,我们发现例程将会大幅提升 Liquify Filter 和 Field Blur 工具的性能,详见下图(图 12)。 在英特尔® 核芯显卡 4600 上,关闭/开启 1 GPU 加速时 Liquify 和 Blur 处理时间一般为数秒钟。[1]

Photoshop on Intel图 12: 开/关标准时的 Photoshop* 工具性能

该操作非常有用。 在开、关 OpenCL 硬件加速的情况下进行测试时,该款全新 Blur 功能的处理速度提高了 3 倍,具体取决于工作负载和正在渲染的范围尺寸(图 13)。[1]

Photoshop on Intel
图 13: 样本模糊化处理功能执行时间(单位:秒)比较

一般的应用处理所需的时间仅占较小工作负载的大部分,因此较大的工作负载在处理时间上能够获得更大的改进。 当启用 OpenCL 加速时,CPU 和 GPU 都能够有效利用,而且许多多线程应用的核心都能够向图形处理器提交工作。 图形处理单元的最低利用率为 70%,内存利用率为 10%-36%,具体取决于图形子系统。 最后,图形管线中没有停顿,这能够提供更出色的用户体验。

总结

添加基于标准的处理例程让 Adobe 能够继续其在每个版本中增强 Photoshop 性能的传统。 通过在英特尔核芯显卡设备上添加基于 OpenCL 的加速,用户能够获得更高的性能,并且能够在整个图像中实时评估模糊滤波器。 向这些过滤器中添加 OpenCL 之前根本无法获得如此完整的图像体验,而且 OpenCL 的添加还支持更有效地创建出色图像。 在添加 OpenCL 之前,应用效果之前只能预览一小部分的图像。 而现在,用户能够在进行调整时全屏查看只能锐化过滤器,并能够更快地获得所需的最终图像。 采用 OpenCL 后,Photoshop 的性能得到显著提升。



[1]结果基于英特尔内部分析结果,仅供参考。 任何系统硬件、软件的设计或配置的不同均可能影响实际性能。

 

参考资料和资源

作者介绍

Tim Duncan 是一位英特尔工程师,被朋友们成为“Gidget-Gadget 先生”。 Tim 目前负责帮助开发人员将技术集成至解决方案,他在芯片制造和系统集成领域有着数十年的经验。 如欲对其有更多了解,请访问英特尔® 开发人员专区:Tim Duncan (英特尔)

Murali Madhanagopal 是英特尔视觉与并行计算事业部的一员,他在其中担任首席图形架构师。 他获得了德州农工大学学院站(Texas A&M University, College Station)计算机信息系统专业的理学硕士,并获得印度安那大学金奈工程学院(College of Engineering Guindy, Anna University)计算机工程学士学位。 Madhanagopal 主要负责开发和执行英特尔工作站处理器图形策略,以支持 ISV 软件在当前和未来基于处理器显卡的平台上高效运行。 此外,他还积极参与到业内领先的 CAD、CAE 和数字内容创建 ISV 和 OEM 优化应用和系统的活动中。

英特尔、Intel 标识、Iris 和锐炬是英特尔公司在美国和/或其他国家的商标。
OpenCL 和 OpenCL 标识是苹果公司的商标,需获得 Khronos 的许可方能使用。
英特尔公司 © 2014 年版权所有。 所有权保留。
* 其他的名称和品牌可能是其他所有者的资产。

OpenCL™ 主机代码基本示例

$
0
0

Download PDF [686.3 kB]

Download Sample OCL ZIP [10.89 mB]

目录

  1. 介绍
  2. 示例介绍
  3. OpenCL 实施。
  4. 限制
  5. OpenCL 应用基本原理。
  6. 项目结构。
  7. 所使用的 OpenCL API。
  8. 控制示例。
  9. 参考文献。

介绍

新接触 OpenCL 的编程人员可能会发现,最完整的文档 Khronos OpenCL 规范并不适合作为 OpenCL 编程的开始。 该规格介绍了许多选项和备选方案,最初可能会让编程人员晕头转向。   其他面向 OpenCL 编写的代码示例可能主要使用设备内核代码,或使用用 OpenCL “包装器”库编写的主机代码,这会隐藏如何直接使用标准 OpenCL 主机 API 的具体细节。  

本文中介绍的 SampleOCL旨在呈现清晰、可读的复杂(non-trivial)OpenCL 程序的基本元素。 该示例代码是面向主机(CPU)而非内核代码或性能 OpenCL™ 代码。  它展示了如何使用 OpenCL v1.2 规范构建一个简单的 OpenCL 应用的基本原理。[1] 同样,本文主要介绍了主机代码的结构以及该代码使用的 OpenCL API。

示例介绍

该代码示例使用的 OpenCL 内核与 ToneMapping 示例相同(参见下文参考文献),后者曾在面向 OpenCL 应用的英特尔® SDK 中发布[2]。 该简单内核旨在帮助由于太暗或太亮而分辨不清的图片清晰可见。 它从输入缓冲区中读取像素,对其进行修改,然后将其编写至输出缓冲区的同一位置。 关于该内核如何运行的更多信息,请参见文档高动态范围色调映射后期处理效果(High Dynamic Range Tone Mapping Post Processing Effect )[3]。

OpenCL 实施

SampleOCL 示例应用并不是要“包装” OpenCL,也就是说,它并非要使用“更高级的” API 来替换 OpenCL API。 总体而言,我发现,这些包装器不比直接使用 OpenCL API 更简单或更整洁,而且,虽然最初创建包装器的编程人员认为其使用起来更简单,但是包装器会对维护代码的 OpenCL 编程人员带来很大负担。 OpenCL API 是一个标准。 如要在专门的“改进” API 中对其进行包装,则需要丢弃许多使用该标准时的值。

依次说法,SampleOCL 实施的确使用了一些 C++ 类及相关方法将 OpenCL API 分成了几组。 该应用主要分为两大类,以区分通用应用元素和与 OpenCL 相关的元素。 前者是 C_SampleOCLApp,后者是 C_OCL。

限制

该示例代码仅关注 OpenCL 应用的基本原理,如版本 1.2 中的说明。 它并没有介绍与其他修订版之间的不同,但是其大部分信息应与最新修订版相关。

该示例的主机端应用代码并非要展示最优性能。 简便起见,我们将多个明显的优化略去。

OpenCL 应用基本原理

接下来,我们将对基本 OpenCL 应用程序序列进行完整的介绍。 我们在此强调“基本”,因为有许多选项并未涉及。 更多信息请参见 OpenCL 规范[1]。

OpenCL 应用需要能够在多处理设备上大规模并行,如采用 SIMD 指令和图形处理单元(GPU)的多核 CPU — 无论是独立还是集成至 CPU。 因此,OpenCL 应用首先需要能够确定哪些设备可用,并选择一台或多台设备进行使用。 一个平台可能支持多种设备,如包括集成 GPU 的 CPU,而且应用能够使用多个平台。

OpenCL 应用的每个可用平台都包括相关的名称、厂商等。该信息可通过使用 OpenCL API clGetPlatformIDs(),然后再使用 clGetPlatformInfo() 来获取,而且可用于选择目标平台。

选定平台后,必须创建一个环境(context)来实施应用所需的 OpenCL 设备、内存和其他资源。 拥有所选平台 ID 和目标设备类型(CPU、GPU 等)的规范后,应用便能够调用 clCreateContextFromType(),然后使用 clGetContextInfo() 来获取设备 ID。 或者,它可以直接使用 clGetDeviceIDs() 在给定平台 ID 上请求设备 ID,然后使用带有这些设备 ID 的 clCreateContext() 创建环境。 本示例使用了第二种方法来创建带有一个 GPU 设备的环境。

拥有目标设备 ID 和环境后,我们便可使用 clCreateCommandQueue() 为每台要使用的设备创建命令队列。 命令队列用于主机应用至 GPU 或其他设备的“排队”操作,例如,申请执行某个 OpenCL 内核。 本示例代码为 GPU 设备创建了一个命令队列。

初始化操作完成后,通常我们接下来将会使用 clCreateProgramWithSource() 创建一个或多个 OpenCL 程序对象。 程序创建后,它还需要使用 clBuildProgram() 进行构建(基本的编写和链接)。 该 API 支持为编译器设置选项,如设置 #defines 以修改程序源代码。

最后,借助创建和构建的程序,我们可创建链接至该程序中的函数的内核对象,从而为每个内核函数名称调用 clCreateKernel()。

运行 OpenCL 内核前,需要先设置要处理的数据,通常通过使用 clCreateBuffer() API 函数创建线性内存缓冲区来完成。 (本示例中未使用映像作 为 OpenCL 内存对象类型。) clCreateBuffer 函数可为既定尺寸的缓冲区分配内存,并可随意从主机内存复制数据,而且,它能够设置缓冲区,以直接使用主机代码已经分配的空间。 (后者能够避免从主机内存复制至 OpenCL 缓冲区,这是常见的性能优化。)

一般而言,内存将至少使用一个输入和一个输出缓冲区以及其他参数。 每次只能设置一个参数,以便内核在执行时访问。访问时只需调用每个参数的 clSetKernelArg() 函数即可。 该函数可使用内核函数参数列表中的一个特殊参数 — 数字索引进行调用。 第一个参数使用 index 0 传递,第二个参数 index 1 等。

借助参数集,调用包含内核对象和命令队列的函数 clEnqueueNDRangeKernel(),申请运行该内核。 内核排队后,主机代码可以做其他的事情,或者可以通过调用 clFinish() 函数等待内核(及之前加入队列的所有任务)完成。 本示例可以调用 clFinish(),因为它包括能够记录一个循环中总内核执行(包括所有排队开销)的时间,该循环需要等待所有执行都完成后, 才能记录最终时间或得出平均时间。

以上是构建 OpenCL 应用的部分。 此外,还有一些清除操作,如调用 clReleaseKernel、clReleaseMemObject、clReleaseProgram 等。虽然 OpenCL 在程序退出时应自动释放所有资源,但是本示例中仍包括这些操作。 较为复杂的程序可能希望即时释放资源以避免内存泄露。

最后应注意的一点是:虽然本示例没有使用“事件”,但是它们对于(比如)希望覆盖 CPU 和 GPU 处理的复杂应用非常有用。 但是,应注意到,任何将指针传递至事件的 clEnqueueXXXXX() 函数(其中 “XXXXX” 用众多可行函数中一个的名称进行替换)都将分配一个事件,然后调用代码负责在某一时刻将包含指针的 clReleaseEvent() 调用至事件。 如果该操作未完成,随着事件累积,程序将会出现内存泄露。

常见的错误是使用 clCreateUserEvent() 函数分配事件以传递至 clEnqueueXXXX 函数,这种操作认为完成后 OpenCL 将会标记该事件。 OpenCL 不会使用该事件,clEnqueueXXXX 将会返回新事件,覆盖指针传递的事件变量的内容。 这种方式很容易导致内存漏洞。 除了本示例的范围以外,用户事件还有其他目的。 关于 OpenCL 事件的更多详细信息,请参见 OpenCL 规范。[1]

项目结构

_tmain ( argc, argv ) - Main.cpp文件中的主要接入点函数。

创建 C_SampleOCLApp类的实例。

调用 C_SampleOCLApp::Run() 以启动应用。

这是它的全部功能! 参见以下 C_MainApp 和 C_SampleApp 类了解更多信息。

C_MainApp类 - C_MainApp.h文件中的通用 OpenCL 应用超类(super-class)

构建时,创建 OpenCL 类 C_OCL的实例。

 

定义通用应用 “run” 函数:

Run()

Run() 是读取代码以理解 OpenCL 应用如何初始化、运行和清理的良好起点。

Run() 可调用具有代表性的简单应用序列中的虚拟函数(见下文)。

 

声明要由 C_SampleOCLApp定义的虚拟函数(见下文):

AppParseArgs ()

解析命令行选项

AppUsage ()

打印使用说明

AppSetup ()

应用设置,包括 OpenCL 设置

AppRun ()

特定应用操作

AppCleanup ()

应用清除

 

C_SampleOCLApp类 - 来自 C_MainApp,可专门针对本示例定义函数。

SampleApp.cpp SampleApp.h文件中的 C_MainApp虚拟函数实施应用特定代码。 (参见 C_MainApp类(见上文),了解实施的虚拟函数。)

ToneMap_OCL.cpp 文件中定义 "ToneMap" OpenCL 内核设置和运行函数:

RunOclToneMap ()

为 ToneMap 执行一次性设置,然后调用 ToneMap()。

ToneMap ()

设置 ToneMapping 内核参数并运行该内核。

 

C_OCL类 - 大部分的主机端 OpenCL API 可设置并清理代码。

构建时,初始化 OpenCL。 销毁时,在 OpenCL 之后清除。

C_OCL.cpp C_OCL.h文件中定义 OpenCL 服务函数:

Start ()

为适当平台的英特尔® 锐炬™ 显卡设置 OpenCL 设备。

ReadAllPlatforms ()

获取所有可用 OpenCL 平台,保存其名称。

MatchPlatformName ()

辅助函数,可通过名称来选择平台。

GetDeviceType ()

辅助函数,可确定设备类型是 GPU 还是 CPU。

CheckExtension ()

检查某个 OpenCL 扩展名是否能够在目前的设备上使用。

ReadExtensions ()

获取列出当前设备的所有 OpenCL 扩展名的字符串。

SetCurrentDeviceType ()

设置目标设备类型并创建 OpenCL 环境和命令队列。

CreateProgramFromFile ()

加载包含 OpenCL 内核的文件,创建 OpenCL 程序并对其进行构建。

ReadSourceFile ()

将 OpenCL 内核源文件读入字符串,准备将其构建为程序。

CreateKernelFromProgram ( )

从以前构建的程序中创建 OpenCL 内核。

GetDeviceInfo ()

获取设备特定信息的两个辅助函数:其一可分配内存以接收和返回结果;其二可通过指针将结果返回至调用程序提供的内存。

ClearAllPlatforms ()

释放与以前选中的平台相关的所有内容。

ClearAllPrograms ()

释放所有现有 OpenCL 程序。

ClearAllKernels ()

释放所有现有 OpenCL 内核。

 

所使用的 OpenCL API

clBuildProgram

clCreateBuffer

clCreateCommandQueue

clCreateContext

clCreateKernel

clCreateProgramWithSource

clEnqueueMapBuffer

clEnqueueNDRangeKernel

clEnqueueUnmapMemObject

clFinish

clGetDeviceIDs

clGetDeviceInfo

clGetPlatformIDs

clGetPlatformInfo

clReleaseCommandQueue

clReleaseContext

clReleaseDevice

clReleaseDevice

clReleaseKernel

clReleaseMemObject

clReleaseProgram

clSetKernelArg

控制示例

本示例从 Microsoft Windows* 命令行控制台运行。 它支持以下命令行和可选参数:

ToneMapping.exe [ ? | --h ] [-c|-g] [-list] [-p "platformName] [-i "full image filename"]

? OR --h

打印该帮助消息

-c

在 CPU 上运行 OpenCL

-g

在 GPU 上运行 OpenCL — 默认

-list

显示平台名称字符串列表

-p "platformName"

提供平台名称(如果有空间将会用引号标出)以供检查和使用。

-i "full image filename"

提供图像文件名称(如果有空间将会用引号标出)以供处理。

参考文献

  1. OpenCL Specifications from Khronos.org:

    http://www.khronos.org/registry/cl/

  2. Intel® SDK for OpenCL™ Applications:http://software.intel.com/en-us/vcsource/tools/opencl-sdk
  3. High Dynamic Range Tone Mapping Post Processing Effect:

    http://software.intel.com/en-us/vcsource/samples/hdr-tone-mapping

 

英特尔、Intel 标识、 Iris 和锐炬是英特尔在美国和其他国家的商标。
* 其他的名称和品牌可能是其他所有者的资产。
OpenCL 和 OpenCL 标识是苹果公司的商标,需获得 Khronos 的许可方能使用。
英特尔公司 © 2014 年版权所有。 所有权保留。

为使用英特尔® 通用连接框架的 Windows* 8 开发数据传输应用

$
0
0

Download PDF

英特尔® 通用连接框架(英特尔® CCF)是一款面向移动设备上运行的应用的连接软件。 使用英特尔 CCF 的应用能够将所有用户连接在一起,无论其在世界的另一端使用者不同的防火墙,还是同处一室但没有连接互联网。 英特尔 CFF 适用于 iOS*、Android*、Windows* Desktop 和 Windows 商店的所有应用,这些应用可在任意平台上使用任何外形的英特尔 CCF。 使用英特尔 CCF,开发人员能够开发在手机、平板电脑、PC 和其他智能设备上使用的应用。

英特尔 CFF 的通信模型是对等的方式。 它支持人们直接与彼此连接,并分享其所有移动计算设备间的信息。

本文中,我将介绍如何使用英特尔 CCF 3.0 为 Windows 8 设备开发应用。 我曾负责开发能够在 Windows 8 和 Android 设备之间传输文件的应用的项目,在该项目中,我独立开发了一款 Windows 应用商店应用。 在这里,我将与大家分享使用英特尔 CCF 的经验。

首先,你需要在 Microsoft Visual Studio* 中将 lib 文件与该项目相关联。 英特尔 CCF SDK 包含两个 dll 文件:libMetroSTC 和 WinRTSTC,所有英特尔 CFF 应用都需要这两个文件。 如要使用英特尔 CCF API,需要将 Intel.STC.winmd 添加至项目参考。 winmd 文件包含使用英特尔 CFF SDK 构建 Windows 应用商店应用的元数据。

身份设置

在将会话显示前,英特尔 CCF 用户必须先设置身份,包括用户名、设备名和 avatar。 这是远程用户将看到的身份。 在面向 Windows 应用商店应用的 SDK 中,InviteAssist 类支持用户设置英特尔 CCF 身份。

                string displayName = await UserInformation.GetDisplayNameAsync();
                _inviteAssist = InviteAssist.GetInstance();
                _inviteAssist.SetUserName(displayName);
                _inviteAssist.SetStatusText("Status");
                _inviteAssist.SetSessionName("Win 8");
                if (_AvatarStorageFile == null)
                {
                    Windows.Storage.StorageFile imgfile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Device.png"));
                    _AvatarStorageFile = imgfile;
                }
                await _inviteAssist.SetAvatarAsync(_AvatarStorageFile);

实施 SetUserProfile() 函数获取 InviteAssist 类的实例,通过调用 InviteAssist.SetUserName()、InviteAssist.SetSessionName() 和 InviteAssist.SetAvatarAsync() API 设置配置文件,如下所示。 我将用户名设置为 Windows 账户名,我的 Windows 8 设备将连接的所有设备上都能看到该指派。 状态文本和会话名可由用户在 UI 中定义。 在我的案例中,这些参数不能被用户更改,且一直使用我的符号。 现在,配置文件已设置完成并可由远程用户发现。

发现

英特尔 CCF 远程用户发现可通过调用 Intel.STC.Api.STCSession.GetNeighborhood() API 来完成,它能够返回发现的所有远程 STCSessions 的 IObservableVector<object>。 开发人员需要负责在 observable collection 与 UI 之间实施数据绑定(Data Bind),或从背后的代码更新 UI 以显示用户列表。 我使用了 Grid APP (XAML),它是 Visual Studio 中渲染 GUI 的标准模板。 GridList 结果中显示的所有用户。

为 NeighborhoodUsers 类对象创建一个 ObservableCollection。 _userList 是 STCSession 类对象的列表,并包括周围用户(neighborhood user)列表。

private static List<STCSession> _userList;
	IObservableVector<object> _hood;
	ObservableCollection<NeighborhoodUsers> _neighborhoodList = new ObservableCollection<NeighborhoodUsers>();
        ObservableCollection<NeighborhoodUsers> neighborhoodList
        {
            get { return _neighborhoodList; }
        }
通过调用 STCSession.GetNeighborhood()API 获取 IObservableVector,并为 IObservableVector 设置 VectorChanged 事件处理程序。
	async void GetNeighborhoodList()
        	{
            		await Task.Run(() =>
          		  {
               	 	_hood = STCSession.GetNeighborhood();
                		_hood.VectorChanged += _hood_VectorChanged;
                		STCSession.LockNeighborhood();
                		IEnumerator<object> en = _hood.GetEnumerator();
                		while (en.MoveNext())
                		{
                    			STCSession session = en.Current as STCSession;
                    			if (session != null)
                        				hood_DiscoveryEvent(session, CollectionChange.ItemInserted);
                		}
                		STCSession.UnlockNeighborhood();
            		});
        	}

        	void _hood_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs evt)
        	{
            		STCSession session = null;
            		lock (sender)
            		{
                		if (sender.Count > evt.Index)
                    			session = sender[(int)evt.Index] as STCSession;
            		}
            		if (session != null)
                		hood_DiscoveryEvent(session, evt.CollectionChange);
        	}

我们添加 hood_DiscoveryEvent() 回调函数以捕获矢量变化事件。 当远程会话可以进行连接,或无法在周围(neighborhood)继续使用时,该回调函数将会发出通知。 当新会话可用时,将会接收到 CollectionChange.ItemInserted 事件;当远程 STCSession 离开周围(neighborhood)或 STCSession 参数发生改变时,将会接收到 CollectionChange.ItemRemoved 和 CollectionChange.ItemChanged 事件。 添加 STCSession.ContainsGadget(),以查看远程设备上是否安装了相同的应用。

private async void hood_DiscoveryEvent(STCSession session, CollectionChange type)
        	{
            		switch (type)
            		{
                		case CollectionChange.ItemInserted:
                    			await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        			_userList.Add(session);
                        			AddPeopleToList(session, "Not Connected");
                    });

                    		break;

                		case CollectionChange.ItemRemoved:
			// Handle this case to check if remote users have left the neighborhood.
                    			if (_neighborhoodList.Count > 0)
                    			{
                        				NeighborhoodUsers obj;
                        				try
                        				{
                            				obj = _neighborhoodList.First((x => x.Name == session.User.Name));
                            				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                            {
                                	_neighborhoodList.Remove(obj);
                                	_userList.RemoveAll(x => x.Id.ToString() == session.Id.ToString());
                            });
                        				}
                        				catch
                        				{
                            				obj = null;
                        				}
                    			}
                   		 break;
                		case CollectionChange.ItemChanged:
			// Handle this case to check if any STCSession data is updated.
                   		 {
                        			STCSession item;
                        			try
                        			{
                            			item = _userList.First(x => x.Id == session.Id);
                        			}
                        			catch
                        			{
                            			item = null;
                        			}
                        			if (item != null)
                           			 item.Update(session);
                        			break;
                  		}
                		default:
                    		break;
            		}
       	 }

 

邀请(Invitation)

我们已经知道了如何发现远程用户(设备),现在应该了解发送连接的流程。 在英特尔 CCF,该流程成为“邀请”。 在英特尔 CCF 3.0, 发送和接收“邀请”通过 STCInitiator 和 STCResponder 进行控制。 STCInitiator 用于向远程用户发送“邀请”,STCResponder 用于响应入站请求。 远程用户接收请求后,将成功建立英特尔 CCF 连接。 使用 STCInitiator 对象发送“邀请”没有任何限制。 一个对象可以发送多个“邀请”。

我们将在以下函数中介绍向远程用户发送邀请。

private void InitializeInitiator(STCApplicationId appId)
        	{
            		initiator = new STCInitiator(appId, true);
            		initiator.InviteeResponded += initiator_InviteeResponded;
            		initiator.CommunicationStarted += initiator_CommunicationStarted;
            		initiator.Start();
        	}

设置完所有调用处理程序后,则调用 STCInitiator.Start() API。 现在,如要向发现的远程用户发送“邀请”,则需要调用 STCInitiator.Invite() API。

initiator.Invite(_userList[itemListView.Items.IndexOf(e.ClickedItem)].Id);

如要查看所发送的“邀请”的状态,需要实施 STCInitiator.InviteeResponded() 回调。

async void initiator_InviteeResponded(STCSession session, InviteResponse response)
{
		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
		{
  			switch(response)
			{
				case InviteResponse.ACCEPTED:
                			// You are connected to the user.
				break;
				case InviteResponse.REJECTED:
                			//Invite was rejected by the remote user.
				break;
		        		case InviteResponse.TIMEDOUT:
                			//No response. Invite time-out.
				break;
                		}
        		});
}

“邀请”已发送,远程用户需要接收它。 实施调用 InitializeResponder() 的函数,通过传递 STCApplicationId 对象初始化 STCResponder 对象。 注册 STCResponder.InviteeResponded() 和 STCResponder.CommunicationStarted() 处理程序。 当远程用户响应“邀请”,或当两个英特尔 CCF 用户之间的通信通道成功建立时,将会调用这些处理程序。

	private void InitializeResponder(STCApplicationId appId)
        	{
            		responder = new STCResponder(appId);
          		  responder.InviteReceived += responder_InviteReceived;
            		responder.CommunicationStarted += responder_CommunicationStarted;
            		responder.Start();
      	  }

远程用户发送的“邀请”可在 STCResponder.InviteReceived() 回调中接收。 接收到“邀请”后,可以接受也可以拒绝。 为响应该“邀请”,需要调用 STCResponder.RespondToInvite() API。

STCResponder.RespondToInvite() API is called.
	async void responder_InviteReceived(STCSession session, int inviteHandle)
        	{
            		if ((_initiatorDataStream == null) && (_responderDataStream == null))
            		{
                		try
                		{
                    			if (!checkPopUp)
                    			{
                        				_inviteHandle = inviteHandle;
                        				_session = session;
                        				Debug.WriteLine("Several windows " + _inviteHandle);
                        				checkPopUp = true;
                        				await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                        			{
                            				InviteeName.Text = session.User.Name + " wants to connect";
                            				InviteePopup.IsOpen = true;
                            				checkPopUp = true;
                        			});
                		    	}
                		}
                		catch (Exception ex)
                		{
                    			Debug.WriteLine(ex.Message);
                		}
            		}
            		else
            		{
                		responder.RespondToInvite(session, inviteHandle, false);
            		}
        	}

通信和数据传输

发送和接收“邀请”后,initiator_CommunicationStarted() 和 responder_CommunicationStarted() 回调将提供流处理(Stream handle)。 我们将使用该 NetStream 处理在两个互联用户之间传输数据。 如要获得数据流处理,则需要实施 initiator_CommunicationStarted() 和 responder_CommunicationStarted() callbacks 并创建 NetStream 对象。 可以注册对 NetStream.StreamClosed 和 NetStream.StreamSuspended 事件的回调。 当通信通道关闭或暂停时,将会接收到这些事件。

void initiator_CommunicationStarted(CommunicationStartedEventArgs args)
        	{
            		_initiatorDataStream = args.Stream;

            		objWrapper.SetStream(_initiatorDataStream);

            		_initiatorDataStream.StreamClosed += DataStream_StreamClosed;
            		_initiatorDataStream.StreamSuspended += DataStream_StreamSuspended;
            		_initiatorDataStream.DataReady += objWrapper.StreamListen;
       	 }
        	void responder_CommunicationStarted(CommunicationStartedEventArgs args)
        	{
            		_responderDataStream = args.Stream;

            		objWrapper.SetStream(_responderDataStream);

            		_responderDataStream.StreamClosed += DataStream_StreamClosed;
            		_responderDataStream.StreamSuspended += DataStream_StreamSuspended;
            		_responderDataStream.DataReady += objWrapper.StreamListen;
      	  }

	private async void DataStream_StreamClosed(int streamId, Guid sessionGuid)
        	{
            		await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            		{
               		 UpdateConnectionStatus(_session.User.Name, "Not Connected");
              			  if (_inviter)
               		 {
                   			 _initiatorDataStream.Dispose();
                    			_initiatorDataStream = null;
                    			_inviter = false;
                		}
                		else if (_responder)
                		{
                    			_responderDataStream.Dispose();
                    			_responderDataStream = null;
                    			_responder = false;
                		}
                		if (isTransferFrame)
               		{
                    			if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
                		}
                	ResetUIScreen();
            		});
        	}

现在,我们来看一下数据传输流程。 首先,我们选择想要发送的文件。 对于这一点,我开发了自己的文件管理器,但是选择文件更简单的方式是使用 FileOpenPicker。 选择文件后,将数据编写至接收到的 NetStream 处理中。 如要在通信通道上编写数据,则需要使用 NetStrem.Write()。

async void SendFileData()

async void SendFileData()
       	{
           		uint size = 1024 * 4;
           		byte[] buffer = new byte[size];
           		int totalbytesread = 0;
           		using (Stream sourceStream = await storedfile.OpenStreamForReadAsync())
           		{
               		do
               		{
                   			int bytesread = await sourceStream.ReadAsync(buffer, 0, buffer.Length);
                   			_objNetStream.Write(buffer, (uint)bytesread);
                   			totalbytesread += bytesread;
                   			TransferedBytes = totalbytesread;

                   			if (args.nState != TransferState.FT_SEND_PROGRESS)
                   			{
                       				args.nState = TransferState.FT_SEND_PROGRESS;
                       				args.FileName = storedfile.Name;
                       				args.FileSize = (int)storedfileProperties.Size;
                       				args.DataBuffer = null;
                       				args.readbytes = 0;
                       				OnTransferUpdates(args);
                   			}
               		} while (totalbytesread < sourceStream.Length);
           		}
       	}

如要接收文件,需要实施 NetStream.Read() 事件回调,这已在“通信”部分进行了介绍。

readBytes = _objNetStream.Read(receivebuffer, (uint)bytesToRead);

最后,我希望该信息能够帮助你了解英特尔 CCF SDK,并希望你能够使用该 SDK 为 Windows 8 和 Android 开发出色的应用。

 

 

英特尔和 Intel 标识是英特尔在美国和/或其他国家的商标。

英特尔公司 © 2014 年版权所有。 所有权保留。

* 其他的名称和品牌可能是其他所有者的资产。

从英特尔媒体软件开发套件向 OpenGL 分享纹理

$
0
0

Code Sample

要点综述

通常,在 Windows* OS,使用 Direct3D 进行视频处理。 但是,也有许多应用使用 OpenGL*,因为它具备出色的跨平台能力,能够在不同的平台上提供相同的 GUI 和外观与体验。  最新的英特尔图形驱动程序支持使用 NV_DX_interop 从 D3D 向 OpenGL 曲面共享,并可与英特尔® 媒体软件开发套件结合使用。 英特尔® 媒体软件开发套件可配置使用 Direct3D 和加入 NV_DX_interop,OpenGL 可使用英特尔媒体软件开发套件的帧缓冲区,而不用执行将纹理从 GPU 复制至 CPU 再复制回 GPU 这一昂贵过程。 本示例代码和白皮书演示了如何设置英特尔® 媒体软件开发套件以使用 D3D 进行编码和解码,从 NV12 色域(媒体软件开发套件的自然颜色格式)向 RGBA 色域(OpenGL 的自然颜色格式)进行颜色转换,然后将 D3D 曲面应设置 OpenGL 纹理。 本管线完全绕过将纹理从 GPU 复制至 CPU 这一过程,该过程曾经是配合英特尔® 媒体软件开发套件使用 OpenGL 时的最大瓶颈。

系统要求

本示例代码使用 Visual Studio* 2013 编写,旨在 (1) 展示 Miracast 和 (2) 利用英特尔® 媒体软件开发套件实现英特尔® 媒体软件开发套件/ OpenGL 纹理共享,其中不用进行任何复制即可与 OpenGL 纹理分享解码曲面,这能够显著地提升效率。 MJPEG 解码器面向 Haswell 和更高版本的处理器执行了硬件加速,较低版本的处理器中的媒体软件开发套件可自动使用软件解码器。 在任何情况下,它都需要与 MJPEG 兼容的摄像头(无论是板载还是 USB 摄像头)。
除了辨认 Miracast 连接类型以外,该示例代码和白皮书中使用的大部分技术都适用于 Visual Studio 2012。 该示例代码基于 Intel Media SDK 2014 for Client,可通过以下链接进行下载:(https://software.intel.com/sites/default/files/MediaSDK2014Clients.zip。) 安装媒体软件开发套件后,将会为 Visual Studio 创建一套环境变量,以便为头文件和库查找正确的路径。

应用概述

该应用将摄像头作为 MJPEG 输入,并对 MJPEG 视频解码,将视频流编码至 H264,然后再对 H264 进行解码。 MJPEG 摄像头视频流(解码后)和最终以 H264 标准解码的视频流将会在基于 MFC 的 GUI 上显示。 在 Haswell 系统上,2 个解码器和 1 个编码器(1080P 分辨率)将会按顺序运行以提供出色的可读性,但是由于硬件加速,它们的速度非常快,这使得摄像头速度成为 fps 的唯一限制因素。 在实际情况下,编码器和解码器将会在不同的线程中运行,性能不会成为障碍。

在单个显示器配置上,摄像头馈入将会在基于 OpenGL 的 GUI 中以 H264 标准解码的视频上方的 PIP 中显示(图 1)。 当 Miracast 连接时,软件将会自动辨认与 Miracast 相连的显示器,并使用全屏窗口播放以 H264 标准解码的视频,而 GUI 将显示原始摄像头视频,因此原始视频和加密视频之间的区别便清晰可见。 最后,查看->监控拓扑(View->Monitor Topology)菜单不仅能够检测到当前的显示器拓扑,还能够更改拓扑。 但是很可惜,它无法启动 Miracast 连接。 它只能在 OS charm 菜单上完成(从右侧滑入-> 设备->项目),目前尚且没有能够创建 Miracast 连接的 API 。 有趣的是,通过将显示器拓扑设置为仅限内部使用可以将 Miracast 连接断开。 如果通过线路连接了多台显示器,菜单可以随时更改拓扑。

图 1 单个显示器拓扑。 MJPEG 摄像头在右下角显示。 以 H264 标准加密的视频在 GUI 中播放。 当启用多台显示器(如 Miracast)时,该软件可检测到变化,MJPEG 摄像头视频和以 H264 加密的视频将会自动分至不同的显示器。

管线设置的主要接入点

本示例代码基于 MFC,设置管线的主要接入点是 CChildView::OnCreate (),它能够启动摄像头,从 MJPEG 转码至 H264,使用 H264 解码,并将转码器和解码器上的纹理与 OpenGL 渲染器绑定。 转码器仅为在基础解码器上添加编码器的解码器子类。 最后,OnCreate 可启动持续获取序列化摄像头馈入的线程。 在工作线程中读取摄像头馈入后,它可向 OnCamRead 函数发送消息,该函数可对 MJPEG 进行解码,编码至 H264,解码 H264,并将纹理更新至 OpenGL 渲染器。  从最高层面而言,整个管线整洁、简单,易于执行。

启动解码器/转码器

解码器和转码器都是使用 D3D9Ex 进行启动。  我们可对英特尔® 媒体软件开发套件进行配置以使用软件、D3D9 或 D3D11。 在本示例中,D3D9 用于简化颜色转换。 英特尔® 媒体软件开发套件的自然颜色格式是 NV12;IDirect3DDevice9::StretchRect 和 IDirectXVideoProcessor::VideoProcessBlt 都可用来将色域转换至 RGBA。 简单起见,本白皮书使用的是 StretchRect,但是一般情况下,我们推荐使用 VideoProcessBlt,因为它在后期处理过程中有出色的附加功能。 可惜的是,D3D11 不支持 StretchRect,因此颜色转换可能非常复杂。 此外,本文中的解码器和转码器使用了独立的 D3D 设备进行各种实验,如混合软件和硬件,但是 D3D 设备可以在二者之间进行共享以节约内存。 以该方式设置管线后,解码输出将设置为 (mfxFrameSurface1 *) 类型。 这仅为面向 D3D9 的封装,mfxFrameSurface1-> Data.MemId 可换算为 (IDirect3DSurface9 *),并在解码后用于 CDecodeD3d9::ColorConvert 函数中的 StretchRect 或 VideoProcessBlt。 媒体软件开发套件的输出曲面不可共享,但是必须要进行颜色转换才能供 OpenGL 使用,并且需要创建一个共享曲面存储颜色转换的结果。

启动转码器

转码器的解码结果将会直接输入编码器,并确保在分配曲面时使用该 MFX_MEMTYPE_FROM_DECODE。

绑定 D3D 和 OpenGL 之间的纹理

绑定纹理的代码位于 CRenderOpenGL::BindTexture 函数中。 请确保对 WGLEW_NV_DX_interop 进行了定义,然后使用 wglDxOpenDeviceNV、wglDXSetResourceShareHandleNV 和 wglDXRegisterObjectNV。  这将会把 D3D 曲面绑定至 OpenGL 纹理。 但是,它无法自动更新纹理,而且调用 wglDXLockObjectsNV / wglDXUnlockObjectsNV 将会更新纹理(CRenderOpenGL::UpdateCamTexture 和 CRenderOpenGL::UpdateDecoderTexture)。 对纹理进行更新后,便可像使用 OpenGL 中的其他纹理一样使用它。

多显示器拓扑变更注意事项

理论上,在外置显示器中提供另一个窗口并根据拓扑变化检测对其进行控制似乎相当简单。 但是实际情况下,从操作系统开始转换,到显示器配置完成,以及内容显示都需要时间。 当结合使用编码器 / 解码器 / D3D / OpenGL 及其优势时,调试将会非常复杂。 本示例尝试重新使用切换过程中的大部分管线,但是实际上,关闭整个管线并重新启动将会更简单,因为添加显示器需要 10 多秒钟的时间,在这期间可能会出现任何故障 — 甚至 HDMI 或 VGA 连接故障。

未来展望

本白皮书中的示例代码面向 D3D9,且不可为 D3D11 实施提供支持。 目前我们尚不清楚,在没有 StretchRect 或 VideoProcessBlt 时,哪种方式能够最有效地将色域从 NV12 转换至 RGBA。 D3D11 实施退出后,白皮书/代码将进行更新。

贡献

感谢 Petter Larsson、Michel Jeronimo、Thomas Eaton 和 Piotr Bialecki 对本文的贡献。

 

英特尔、Intel 标识、Xeon 和至强是英特尔在美国和其他国家的商标。
* 其他的名称和品牌可能是其他所有者的资产

英特尔公司© 2013 年版权所有。 所有权保留。

Viewing all 154 articles
Browse latest View live