文章目录

有利的部分

erlang是好的,吸引了很多人的兴趣。不少人甚至将erlang体系的影响带到了自己所在的其他语言项目中,构建一些类似erlang的基础设施。包括我。

  1. 随意挥霍的process。 端游从早期的单进程支持一个游戏服,发展到现在的多进程支持一个游戏服。其中涉及多个进程协作的逻辑越来越多,异步任务相互之间由于时间差带来的问题也越来越频繁。
    通常我总会利用状态机或者类似的办法管理异步任务,但并不能顾及到每一处,而且状态机增加了理解代码的难度。
    erlang轻量的process使我能为每个异步任务创建一个独立的执行过程,同时变量不可变的机制几乎消除了多线程中的资源共用的问题。
  2. 发送消息太简单。
    用C++,发送消息从socket干起,还只能发给一个真正的系统进程,然后switch分发处理。
    在异步任务逐渐增多的环境下,有时候很希望语法糖是:能将消息发送给某个异步任务。需要消息平台是一种逻辑上的抽象,而不是底层的socket。
    这个可以C++包装一个,而erlang提供了一个极其完善的面向process的消息系统,process又可以映射到异步任务中。
  3. ETS,还有Mnesia,it’s great
    在多进程支持一个游戏功能的情况下,有大把的数据需要在不同的进程之间同步共享。也用C++包装一个类似的系统能降低很多重复的数据同步工作。
    erlang提供了ETS甚至Mnesia,几乎无条件的为我们提供了数据的分布、持久和恢复。

困难的部分

用erlang开发游戏最困难的地方就是实现场景逻辑。这里没有异步任务,这里是效率、指针和角色相互操作的天堂,但是对erlang来说可能是地狱。
常见的是player/NPC角色之间的立即相互修改,从地图区域查询一批player/NPC角色等。在指针环境下这些操作非常有效率。
一个实时战斗的MMORPG要求核心逻辑要达到25帧/S,区域地图在线1000人。

  1. 如果我们为每个player/NPC映射到process用于交互,那么他们必然使用消息去操作访问对方。 这很美,但是效率不行。因为player/NPC的操作访问实在太频繁了,这一来erlang就变成一个消息繁忙的系统,真正的游戏计算反而耽误了。
  2. 每个场景一个process,场景中所有的player/NPC集中保存到tuple,list中,通过参数传递。
    这样具体操作player/NPC的数据确实快了,但是erlang的原生list类型不是利于搜索的类型,这一趟趟查下来也就将计算时间花光光了。
    另外通过参数传递也会导致每个相关的子函数都要留一个口子。
  3. 每个场景一个process,场景中的所有player/NPC都保存到进程字典中。
    进程字典的存取速度在erlang中算快了,插入100ns,查询40ns。ETS的速度是us。参见进程字典到底有多快

游戏的三种逻辑

如果要用erlang来做MMORPG,那规划一下游戏的基本逻辑模块,根据模块的特性选择不同的erlang模式,是有意义的。像C++那样一种模式就行得通的做法,并不适用于erlang。

  1. 自我修改逻辑
    比如升级,强化之类,就是改改自己的属性,改改自己的技能。
    这种逻辑erlang可以为每个player/NPC创建process负责,也可以一个process处理多个player/NPC的类似逻辑。客户端对于这种操作的延时总能容忍1,2秒,慢慢来,性能没关系。
  2. 低频角色交互逻辑
    比如组队,领取任务,NPC思考等等,角色需要相互操作对方数据。同样也是延时容忍较高,可以尽情发挥erlang在这种交互逻辑中的异步任务支持能力。
  3. 高频角色交互逻辑
    同一个场景中,角色交互频率最高的就是移动和战斗。
    移动影响相互间的视野,战斗则直接读取修改彼此的数据。不要忘了,1000人25帧/S的计算。

移动和战斗

这一块比较纯粹,由一个process为一个场景的player/NPC提供服务,基本上有下面几样内容就搞定计算:

  1. pos,角色坐标
  2. atb,角色属性
  3. skill,技能列表
  4. state,状态列表
  5. 同屏表
  6. 地图数据
  7. 事件列表

前4条属于角色数据,简单操作即可。
同屏表通过四叉树管理角色的空间,为各种类型的群攻判定提供快目标的快速查询。
地图数据为角色检测技能释放的空间合法性,以及战斗寻路。
事件列表则每帧更新技能、状态等数值的计算。

效率优化

仅仅是纯粹的技能效果计算,erlang在虚拟机上的效率肯定不及C++。不过属性计算这块要求的性能并不高,猜测还是能扛下这个计算。
费时、难写的计算可能有两块,同屏表和地图数据。
erlang的数据类型很难高效的处理关系型结构,空间四叉树和地图三角关系用erlang实现起来相当凑合。那么,同屏表和地图的功能到底作为场景战斗process的一个功能,还是以独立process的形式服务呢?
process发送消息的性能大概是1us。
通常一个角色的一次战斗计算需要访问同屏表和地图功能各一次,4us。1000人的话是4ms。1帧40ms,那么每帧大概有30ms左右的时间用于完整的战斗计算,包括同屏计算和地图计算。
为了进一步提高同屏计算和地图计算的性能,可以用C++实现erlang的内置函数。此外,原先逐个角色串行计算同屏功能和地图功能,可以改并行:

  1. 先收集全部角色的同屏计算需求
  2. 将全部计算需求均匀发送到多个同屏表process进行计算
  3. 一边收集结果一边继续计算剩下的战斗部分。

地图计算也采用类似的并行处理,即可提高效率。

Mac下的启动服务主要有三个地方可配置:

1,系统偏好设置->帐户->登陆项

2,/System/Library/StartupItems 和 /Library/StartupItems/

3,launchd 系统初始化进程配置。

前两种优化比较简单,本文主要介绍的是第三种更为复杂的launchd配置优化。

launchd是Mac OS下,用于初始化系统环境的关键进程。类似Linux下的init, rc。

我们先来看一下Mac OS X的启动原理:

1,mac固件激活,初始化硬件,加载BootX引导器。

2,BootX加载内核与内核扩展(kext)。

3,内核启动launchd进程。

4,launchd根据 /System/Library/LaunchAgents , /System/Library/LaunchDaemons , /Library/LaunchDaemons, Library/LaunchAgents , ~/Library/LaunchAgents 里的plist配置,启动服务守护进程。

看完了Mac OS X的启动原理,我们不难发觉 /System/Library/LaunchAgents , /System/Library/LaunchDaemons , /Library/LaunchDaemons, Library/LaunchAgents 五个目录下的plist属性文件是优化系统的关键。

下面再来理解几个基础概念:

/System/Library和/Library和~/Library目录的区别?

/System/Library目录是存放Apple自己开发的软件。

/Library目录是系统管理员存放的第三方软件。

~/Library/是用户自己存放的第三方软件。

LaunchDaemons和LaunchAgents的区别?

LaunchDaemons是用户未登陆前就启动的服务(守护进程)。

LaunchAgents是用户登陆后启动的服务(守护进程)。

上面提到的五个目录下的plist文件格式及每个字段的含义:

Key Description Required
Label The name of the job yes
ProgramArguments Strings to pass to the program when it is executed yes
UserName The job will be run as the given user, who may not necessarily be the one who submitted it to launchd. no
inetdCompatibility Indicates that the daemon expects to be run as if it were launched by inetd no
Program The path to your executable. This key can save the ProgramArguments key for flags and arguments. no
onDemand A boolean flag that defines if a job runs continuously or not no
RootDirectory The job will be chrooted into another directory no
ServiceIPC Whether the daemon can speak IPC to launchd no
WatchPaths Allows launchd to start a job based on modifications at a file-system path no
QueueDirectories Similar to WatchPath, a queue will only watch an empty directory for new files no
StartInterval Used to schedule a job that runs on a repeating schedule. Specified as the number of seconds to wait between runs. no
StartCalendarInterval Job scheduling. The syntax is similar to cron. no
HardResourceLimits Controls restriction of the resources consumed by any job no
LowPriorityIO Tells the kernel that this task is of a low priority when doing file system I/O no
Sockets An array can be used to specify what socket the daemon will listen on for launch on demand no

看不懂上面地plist配置吗?没关系,我们的优化策略是完全卸载服务,所以我们不用关心plist里的配置含义。

开始优化禁用服务,我们需要用到Mac OS提供的一个工具指令-launchctl

launchctl 指令会针对服务设置一个禁用标志,launchd启动时会先检查这个服务是否被禁用,从而确定是否需要启用这个服务。

禁用服务的方法1

先找到禁用标志文件 /var/db/launchd.db/com.apple.launchd/overrides.plist,查看你要禁用的服务是否已被禁用了。

有些服务已被禁用,但未列在overrides.plist里。此时,你还需要检查这个服务的plist文件Label字段是否已经标记为 Disable。

确认这个服务未禁用后,我们就可以通过调用如下命令,来禁用服务:

sudo launchctl unload plist文件路径

sudo launchctl unload -w plist文件路径

比如,我想禁用spotlight,则输入

sudo launchctl unload /System/Library/LaunchAgents/com.apple.Spotlight.plist

sudo launchctl unload -w /System/Library/LaunchAgents/com.apple.Spotlight.plist

禁用完服务以后,重启Mac OS即可生效。

禁用服务的方法2,一种更有效且暴力的方法(推荐)

先卸载服务

sudo launchctl unload /System/Library/LaunchAgents/com.apple.Spotlight.plist

然后将plist文件mv到其他目录备份。重启。搞定。是不是很简单!

我个人比较喜欢这种禁用服务的方式,所以推荐一下。

如果发现服务禁用后,系统或软件出现异常,可以通过如下命令,还原服务:

方法1:

sudo launchctl load -wF plist文件路径

方法2:

将备份的plist文件mv回原来的文件夹。

sudo launchctl load plist文件路径

注意:系统级服务的禁用要异常小心,请在禁用前google,确保你熟知这个服务的作用。否则可能导致系统无法启动。

最安全的做法就是不要去禁用它了。

当然,用户服务我们还是可以放心禁用的,有问题最多再启用呗。

下面是我禁用的服务列表:

/System/Library/LaunchDaemons/com.apple.metadata.mds.plist (禁用spotlight的前提)

/System/Library/LaunchAgents/com.apple.Spotlight.plist (Spotlight)

/Library/LaunchDaemons/com.google.keystone.daemon.plist (Google Software Update)

/Library/LaunchAgents/com.google.keystone.root.agent (Google Software Update)

~/Library/LaunchAgents/com.google.keystone.agent.plist (Google Software Update,用户下的进程不需要加 sudo)

~/Library/LaunchAgents/com.apple.CSConfigDotMacCert-ken.wug@me.com-SharedServices.Agent.plist (me.com的共享服务,我不用)

/System/Library/LaunchDaemons/org.cups.cupsd.plist (打印机)

/System/Library/LaunchDaemons/org.cups.cups-lpd.plist (打印机)

/System/Library/LaunchDaemons/com.apple.blued.plist (蓝牙)

/System/Library/LaunchAgents/com.apple.AirPortBaseStationAgent.plist (apple无线基站,我没有这个设备)

知道守护进程(服务)名,如何找到对应的plist文件?

将进程(服务)名拷贝,然后到 /System/Library/LaunchAgents , /System/Library/LaunchDaemons , /Library/LaunchDaemons, Library/LaunchAgents , ~/Library/LaunchAgents 五个目录里,通过以下命令查找:

ll|grep 进程(服务)名

比如

ll|grep blued

在 /System/Library/LaunchDaemons 中找到了它。接下来,请按上面指导的步骤,禁用该服务。

 

link: http://www.3lian.com/edu/2013/04-26/67191.html

文章目录

在Mac OS X中,有三种方式来实现启动项的配置:1)Login Items;2)StartupItems;3)launchd daemon。

1.Login Items

打开System Preferences,选择System -> Accounts,选择Login Items选项卡,将/Applications目录下的.app直接拖进右边的列表中。重启电脑之后就会发现列表中的程序在开机之后就自动启动了。

2.StartupItems

StartupItems,顾名思义,就是在系统启动过程中运行的程序,它们可以是运行完就立即终止的程序(比如,开机清空废纸篓),也可以是一直持续在系统运行周期的后台进程。

StartupItems一般存放在以下两个路径下:

1)/System/Library/StartupItems

2)/Library/StartupItems

大部分与系统相关的StartupItems都放在/System/Library/StartupItems这个路径下,它们会先于/Library/StartupItems路径下的执行,因为前者路径下的StartupItems提供了系统级的基础服务,比如crash reporting,core graphics services,system accounting等,而后者路径在默认情况下是不存在的,需要自己手动创建。

这里我们以/Library/StartupItems目录下的IcebergControlTower为例。

简单来说,在Mac OS X上,一个StartupItems包含以下两个方面的内容:

1)可执行程序;

2)包含依赖进程关系的plist文件(StartupParameters.plist)。

2.1 The Property List

2.1.1 Plist的key值与含义

StartupParameters.plist 是一个属性列表,包含了运行可执行程序的必要条件。

该plist需要获得root权限,包含了几个方面的内容:

1)Description;

对该服务的一个简单的描述,仅仅是描述,并不是说明实际的进程名称。

2)Provides;

指定StartupItems提供的服务。如图plist文件Provides中说明,StartupItems开启的后台进程名为:Iceberg Control Tower。

Provides可以指定多个服务,反映在图中就是Item0,Item1…等。这里只有Item0。

3)Uses;

指定了在StartupItems加载之前需要开启的服务。Mac OS X系统先尝试着加载Uses中指定的服务,然后再加载StartupItems。也就是说,即使Uses中指定的服务没有加载成功,系统仍然会加载StartupItems。

4)OrderPreference;

指定执行StartupItems的时间顺序。这个顺序的重要程度排在Uses之后,是指定执行完Uses之后的顺序。可能的取值包括:First, Early, None(default), Late, Last。

5)Messages。

2.1.2 创建一个StartupParameters.plist文件

  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <!DOCTYPE plist PUBLIC “-//Apple Computer//DTD PLIST 1.0//EN”
  3.     “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
  4. <plist version=“1.0”>
  5. <dict>
  6.     <key>Description</key>
  7.     <string>Iceberg Control Tower Initilaization</string>
  8.     <key>Provides</key>
  9.     <array>
  10.         <string>Iceberg Control Tower</string>
  11.     </array>
  12.      <key>Uses</key>
  13.     <array>
  14.         <string>Disks</string>
  15.     </array>
  16.     <key>OrderPreference</key>
  17.         <string>None</string>
  18. </dict>
  19. </plist>

 

2.2 The Executable File

注意:1)可执行文件的名称和它所在的文件夹的文件名是一样的,这是系统默认的规则。

2)操作可执行文件需要获得root权限。

3)可执行文件是一个shell脚本。

打开IcebergControlTower文件目录下同名的可执行文件,可以看到脚本的具体内容:

一般的可执行文件包含这样几个方面的内容:

1)./etc/rc.common

Apple提供的一个脚本库,该脚本库里包含了为可执行文件引进参数的接口。在这里load这个库主要是调用RunService。

2)StartService(), StopService(), RestartService()

当可执行文件接收到的参数为start,stop或者restart时,执行相对应的函数。

参数含义:

start:开机过程中开启服务;

stop:关机过程中停止服务;

restart:在特定条件下重启服务。

3)RunService  “$1”

执行传递给该脚本的第一个参数指定的服务。

“$1” 表示传给该脚本的第一个参数。例如,传入的参数为start,则执行StartService()。

3. Launchd Daemon

launchd是Mac OS下用于初始化系统环境的关键进程,它是内核装载成功之后在OS环境下启动的第一个进程。

采用这种方式来配置自启动项很简单,只需要一个plist文件,通常(同时也是系统推荐)是将plist放在~/Library/LaunchAgents路径下。

3.1 plist文件格式及每个字段的含义:

1)Label【required】

该项服务的名称。

2)OnDemand【optional】

10.4提供的一个key值,功能与KeepAlive的基本功能相似,在10.5及之后的系统中被KeepAlive替代。KeepAlive扩展了更多的功能,除了使用单一的boolean作为key值之外,还能使用字典结合多个key值。

3)Program【ProgramArgument是required的,在没有ProgramArgument的情况下,必须要包含Program这个key】

指定可执行文件的路径。

4)RunAtLoad【optional】

标识launchd在加载完该项服务之后立即启动路径指定的可执行文件。默认值为false。

5)WorkingDirectory【optional】

该key在开启可执行文件之前,指定当前工作目录的路径。

6)KeepAlive【optional】

这个key值是用来控制可执行文件是持续运行呢,还是满足具体条件之后再启动。默认值为false,也就是说满足具体条件之后才启动。当设置值为ture时,表明无条件的开启可执行文件,并使之保持在整个系统运行周期内。

3.2 创建一个plist文件:

  1. <?xml version=“1.0” encoding=“UTF-8”?>
  2. <!DOCTYPE plist PUBLIC “-//Apple Computer//DTD PLIST 1.0//EN”
  3.     “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
  4. <plist version=“1.0”>
  5. <dict>
  6.     <key>Label</key>
  7.     <string>com.yourcompany.HSPA_USB_MODEM</string>
  8.     <key>OnDemand</key>
  9.     <false/>
  10.     <key>Program</key>
  11.     <string>/Application/HSPA USB MODEM.app/Running</string>
  12.     <key>RunAtLoad</key>
  13.     <true/>
  14.     <key>WorkingDirectory</key>
  15.     <string>/Application/HSPA USB MODEM.app</string>
  16. </dict>
  17. </plist>

4.三种方式的区别

初步了解了系统的启动过程之后(http://blog.csdn.net/abby_sheen/article/details/7817132),再来看这三种配置启动项的方式,就很容易理解这三种方式之间的差异了。

总的来说,LoginItems 和StartupItems的区别较明显。

StartupItems

LoginItems

Depedency Ordering

Need

Do not Need

Load Timing

during startup

after a user logs in

Launched by WHO

by root, but not necessarily

the user

Processes types

background processes and processes that terminate after running

any Mac OS X executable

对于我们自定义的Launchd daemon,通常(同时也是系统推荐)是放在~/Library/LaunchAgents路径下。launchd进程需要在用户login之后才能加载。这种方式与LoginItems最大的区别在于,启动的进程不同。LoginItems是通过loginwindow去启动的,而Launchd daemon是通过com.apple.launchd.peruser启动。

 

link: http://blog.csdn.net/abby_sheen/article/details/7817198

Intellij IDEA的默认启动JVM版本是1.6*,如果你系统中的java版本高于此版本请将

/Applications/IntelliJ IDEA 13.app/Contents/Info.plist中的

<key>JVMVersion</key>
 <string>1.6*</string>

修改为正确的版本号即可。比如我的是1.7

则修改为:
<key>JVMVersion</key>
<string>1.7*</string>

第一种:
     修改 ccConfig.h   

将#define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 0 改为 #define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1

/** @def CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
If enabled, the texture coordinates will be calculated by using this formula:
– texCoord.left = (rect.origin.x*2+1) / (texture.wide*2);
– texCoord.right = texCoord.left + (rect.size.width*2-2)/(texture.wide*2);

The same for bottom and top.

This formula prevents artifacts by using 99% of the texture.
The “correct” way to prevent artifacts is by using the spritesheet-artifact-fixer.py or a similar tool.

Affected nodes:
– CCSprite / CCSpriteBatchNode and subclasses: CCLabelBMFont, CCTMXTiledMap
– CCLabelAtlas
– CCQuadParticleSystem
– CCTileMap

To enabled set it to 1. Disabled by default.

@since v0.99.5
*/
#ifndef CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
#define CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL 1
#endif

 

第二种:     

调用瓦片地图对应CCTexture2D的setAliasTexParameters接口。     

若调用之后还有黑线,则还调用 CCDirector::sharedDirector()->setProjection(kCCDirectorProjection2D);     

1、ETC1图片是android下通用的压缩纹理,几乎所有的android机器都支持,是opengles2.0的标准。不像pvrtc4只是部分powervr的显卡支持。

ETC1图片不支持半透明(有替代方案可以使etc1图片兼容半透明显示),内存占用只有正常RGBA8888的八分之一(一个像素0.5个字节),并且具备极高的加载速度。ETC1的图片大小只跟图片尺寸相关,在大小上无法媲美jpg或者png8的图片。

2、cocos2d-x早期使用android提供的ETC1Util来加载纹理,后面经过一次优化,改变成直接读取文件的加载方式。 也就是说ETC1文件前面16个字节是文件头,包含文件宽高等信息。 除开这16个字节,剩下的就是图片像素数据,这些数据可以直接传递给显卡使用glCompressedTexImage2D来创建纹理。

3、同样在这次优化中,加入了软件解压ETC1的功能,这样windows等桌面平台也可以使用ETC1的图片了(虽然没有任何优势可言)。但是实现有一些bug,导致不兼容非2的整次幂的图片。修改如下

[cpp]

  1. //if it is not gles or device do not support ETC, decode texture by software
  2.        int bytePerPixel = 3;
  3.        GLenum fallBackType = GL_UNSIGNED_BYTE;
  4.        /*bool fallBackUseShort = false;
  5.        if(fallBackUseShort)
  6.        {
  7.            bytePerPixel = 2;
  8.            fallBackType = GL_UNSIGNED_SHORT_5_6_5;
  9.        }
  10.        */
  11.        unsigned int stride = _width * bytePerPixel;
  12.        std::vector<unsigned char> decodeImageData(((stride + 3) &~ 3) * ((_height + 3) &~3));
  13.        etc1_decode_image(etcFileData + ETC_PKM_HEADER_SIZE, &decodeImageData[0], _width, _height, bytePerPixel, ((stride + 3) &~ 3));
  14.        //set decoded data to gl
  15.        glGenTextures(1, &_name);
  16.        glBindTexture(GL_TEXTURE_2D, _name);
  17.        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  18.        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  19.        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  20.        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, fallBackType, &decodeImageData[0]);
  21.        glBindTexture(GL_TEXTURE_2D, 0);
  22.        delete[] etcFileData;
  23.        etcFileData = NULL;
  24.        return true;

注意其中两句

std::vector<unsigned char> decodeImageData(((stride + 3) &~ 3) * ((_height + 3) &~3));

etc1_decode_image(etcFileData + ETC_PKM_HEADER_SIZE, &decodeImageData[0], _width, _height, bytePerPixel, ((stride + 3) &~ 3));

分配内存必须能够容纳下图片数据,而ETC1图片会进行4字节对齐(圆整),所以宽高不能直接使用原始图片数据。  当然,不修改的话对于2的整次幂的图片也是没有问题的,因为本身就是对齐的,不需要圆整了。

4、android下部分机器兼容非2的整次幂的etc1图片,但是同样也有部分机器不兼容。遇到非2的整次幂的图片会渲染错误甚至崩溃。所以android下使用etc1图片需要进行2的整次幂的扩展。如果大量零碎文件的话,考虑使用TexturePacker打包图片

5、etc1对透明图片的支持。  etc1不支持透明图片,同样cocos2d-x对etc1也不支持透明图片的显示。虽然图片格式上面不支持,但是我们可以通过技术手段间接达到透明etc1图片渲染的目的。详细内容可以参考这里 。

有两种方案可以选择,一种是通过Mali工具生成pkm文件时选择Create atlas,这样就生成了一张拼接在一起的纹理。这张纹理上半部分是原始图片(无alpha信息),下半部分是alpha信息图片。在渲染的时候使用特殊的shader进行渲染。这个改动是比较小的。

另一种方案是创建两张分离的图片,分别是原始图片和alpha图片。渲染时加载这两张纹理,然后alpha图片当做参数传递给原始图片的shader。

我使用的是第一种方案。修改后的shader如下(注意,这个shader是新增的,并且是只有这种打包的etc1图片才使用这个shader,未打包的无透明色的etc1图片和png图片依然使用原来的shader)  只需要修改像素着色器代码,顶点着色器代码不变。  由于现在etc支持透明显示了,所以bool CCTexture2D::initWithETCFile(const char* file)中m_bHasPremultipliedAlpha要置为false,开启alpha blend来渲染图片

[cpp]

  1. #ifdef GL_ES                
  2. precision lowp float;
  3. #endif                      
  4. varying vec4 v_fragmentColor;
  5. varying vec2 v_texCoord;
  6. uniform sampler2D CC_Texture0;
  7. void main()
  8. {
  9.     gl_FragColor = vec4(texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y)).xyz, texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y + 0.5)).r);
  10. }

 

6、使用etc1图片可以极大的减少内存,并且加快加载速度。  我做过一个简单的测试,80k的png8的图片加载需要消耗117ms,同样的etc1图片(经过扩展有1mb大小)加载消耗40ms。这个已经是极限情况。  一般来说同样大小的etc1图片加载速度要快5~10倍。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~下面新的研究成果~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

7、关于PremultipliedAlpha的理解。  cocos2d-x的CCTexture2D中有一个m_bHasPremultipliedAlpha的属性。我们使用TexturePacker中导出pvr图片时也有提示开启PVRImagesHavePremultipliedAlpha这个选项。  虽然PremultipliedAlpha就是图片的颜色在输出的时候已经预先乘以alpha色了,所以渲染的时候图片的RGB就需要再次乘以alpha色了,这个在一定程度上可以提高运行效率。所以TexturePacker推荐开启PremultipliedAlpha选项,XCode导出png图片的时候以及UIImage加载图片的时候都会使用PremultipliedAlpha。   这个有一点恶心的地方就是,我们无法通过一个图片属性判断它是否是是PremultipliedAlpha的,只能通过肉眼或者是一个并不准确的公式来判断。

我们还可以进一步去理解这个设置。一般来说,半透明图片渲染使用的是alpha blend 参见CCSprite::updateBlendFunc()这个函数。

[cpp]

  1. void CCSprite::updateBlendFunc(void)
  2. {
  3.     CCAssert (! m_pobBatchNode, “CCSprite: updateBlendFunc doesn’t work when the sprite is rendered using a CCSpriteBatchNode”);
  4.     // it is possible to have an untextured sprite
  5.     if (! m_pobTexture || ! m_pobTexture->hasPremultipliedAlpha())
  6.     {
  7.         m_sBlendFunc.src = GL_SRC_ALPHA;
  8.         m_sBlendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
  9.         setOpacityModifyRGB(false);
  10.     }
  11.     else
  12.     {
  13.         m_sBlendFunc.src = CC_BLEND_SRC;
  14.         m_sBlendFunc.dst = CC_BLEND_DST;
  15.         setOpacityModifyRGB(true);
  16.     }
  17. }

正常来说,半透明图片渲染使用的是 GL_SRC_ALPHA  GL_ON_MINUS_SRC_ALPHA这个选项 代表的意思就是: 源(图片)像素*源因子(源alpha) + 目标(屏幕)像素*目标因子(1-源alpha)。  通过这个公式可以达到渲染半透明图片的目的。

如果图片有PremultipliedAlpha,再使用这个公式就不对了,图片明显变暗,因为图片的rgb已经乘以alpha了,再乘一次图片自然就变黑一点。  这个时候渲染的公式就变为:

源像素 + 目标像素*(1-源alpha)。  虽然图片依然是半透明的,但是处理源像素时不再分别乘alpha了。

8、为什么要特意提这个属性呢?  因为ETC1图片在加载的时候默认开启了PremultipliedAlpha,一般不透明的图片处理起来没有问题(正常的etc1图片就是不透明的),但是参见上面我们的透明etc1图片渲染解决方案,实际图片在渲染的时候是可以达到半透明的效果的。所以我们有两个选择,一个是默认关闭PremultipliedAlpha,另一个是默认开启PremultipliedAlpha然后shader中分别把rgb乘以alpha。  具体是alpha blend效率高还是shader中效率高我还没有测试。

9、使用上面的shader在渲染的时候windows下正常,但是android下会出现大量的锯齿。一开始以为是mipmap没有开启的缘故,但是使用mipmap(后面会介绍)后,依然无法解决问题。后面发现cocos2d-x中shader默认使用的低精度浮点数

[cpp]

  1. #ifdef GL_ES                                \n\
  2. precision lowp float;                       \n\
  3. #endif                                      \n\

低精度浮点数有效位数因显卡而异,但是不高是肯定的。如果我们没有特殊的运算,低精度足够使用。但是一旦我们有*0.5之类的运算,那么低精度浮点数很容易丢失数据,那表现出来就是各种锯齿。  所以在新的shader代码中删除了这个指令。   另外某些文档说,使用低精度无助于效率提升,因为最终渲染的时候还是要转回中精度(中精度是默认选项,部分高级显卡支持高精度)

10、最终修改后的shader如下

顶点shader  (我们把部分运算移动到顶点shader中,而不是每个像素进行计算,这个可以提升运行效率)

[cpp]

  1. attribute vec4 a_position;
  2. attribute vec2 a_texCoord;
  3. attribute vec4 a_color;
  4. varying vec4 v_fragmentColor;
  5. varying vec2 v_texCoord;
  6. varying vec2 v_alphaCoord;
  7. void main()
  8. {
  9.     gl_Position = CC_MVPMatrix * a_position;
  10.     v_fragmentColor = a_color;
  11.     v_texCoord = a_texCoord * vec2(1.0, 1.0);
  12.     v_alphaCoord = v_texCoord + vec2(0.0, 0.5);
  13. }

像素shader

[cpp]

  1. varying vec4 v_fragmentColor;
  2. varying vec2 v_texCoord;
  3. varying vec2 v_alphaCoord;
  4. uniform sampler2D CC_Texture0;
  5. void main()
  6. {
  7.     vec4 v4Colour = texture2D(CC_Texture0, v_texCoord);
  8.     v4Colour.a = texture2D(CC_Texture0, v_alphaCoord).r;
  9.     v4Colour.xyz = v4Colour.xyz * v4Colour.a;
  10.     gl_FragColor = v4Colour * v_fragmentColor;
  11.     //gl_FragColor = vec4(texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y)).xyz, texture2D(CC_Texture0, vec2(v_texCoord.x, v_texCoord.y + 0.5)).r);
  12. }

关于shader需要说明三点,在顶点shader中有这么一条指令  v_texCoord = a_texCoord * vec2(1.0, 1.0);   因为ETC1需要2的整次幂,所以我们的图片基本上都有扩展,那也就意味着会设置setTextureRect,如果设置了这个,那么a_texCoord就是我们指定的大小,所以这里去的是(1.0, 1.0),如果没有setTextureRect,那么a_texCoord就是全部的贴图大小,也就是两倍的正常大小,那么这个时候取的就应该是(1.0,  0.5)。  最终我的解决方法是所有的使用这个shader的图片都设置一下大小。这样shader就统一了。

在像素着色器代码中有v4Colour.xyz = v4Colour.xyz * v4Colour.a;  这个就跟上面说的PremultipliedAlpha有关系。我们在shader中预先乘以alpha。

这个shader的使用条件,只有带透明的etc1图片(通过工具导出时进行了自动拼接)才能使用这个shader进行渲染,否则都会出错。这个我们要在代码中进行判断。

 

11、关于图片拼接时的黑边问题。
这个可以单独开一个话题,但是由于是我处理ETC1图片时遇到的,所以统一都在这里解析了。 网上经常看到有人说图片拼接的时候有黑边,比如tilemap地图拼接的时候。这个分三种情况,一种是最简单的图片对齐计算有问题,拼接的时候由于浮点数计算多了一个像素或者是少了一个像素,这个计算的时候有意向做移动一个像素就可以解决。
第二种是图片导出的问题(使用TexturePacker),不仅仅是地图拼接黑边,可能其他资源也会有黑的虚线,这个在导出的时候选择–border 2 –shape 2 (TexturePacker中有对应的设置,默认为0,但是我之前手欠给修改成了0)。 另外还有一个Exclude选项也是用来解决这个问题的。
第三种是最本质的问题,比如我碰到的使用png图片渲染正常,但是使用etc1图片渲染就出现黑边,若隐若现,一拖动界面就出现。 这个可以在纹理创建的时候设置这个来解决(png等图片创建的时候有设置,但是etc1没有)

[cpp]

  1. glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  2.         glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

一般来说,纹理通过

[cpp]

  1. if (isMipmapped) {
  2.             /* Enable bilinear mipmapping */
  3.             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  4.         } else {
  5.             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  6.         }

这个来进行抗锯齿等操作,但是如果在图片边缘的时候计算就会有问题,因为外部没有像素了,而图片本身像素为半透明,那么计算的时候很有可能计算出黑色,那么就显示出黑边了。

12、最后要说下mipmap,mipmap就是图片如果有缩小,那么渲染的时候使用小的图片(比如256*256的图片如果缩小一半来渲染,就取128*128的图片),这个小的图片可以直接使用函数生成

[cpp]

  1. void CCTexture2D::generateMipmap()
  2. {
  3.     CCAssert( m_uPixelsWide == ccNextPOT(m_uPixelsWide) && m_uPixelsHigh == ccNextPOT(m_uPixelsHigh), “Mipmap texture only works in POT textures”);
  4.     ccGLBindTexture2D( m_uName );
  5.     glGenerateMipmap(GL_TEXTURE_2D);
  6.     m_bHasMipmaps = true;
  7. }

也可以在生成图片的时候直接创建mipmap的图片。 etc1貌似不支持内存中直接生成。 开启mipmap进行渲染会多30%左右的内存开销,但是如果图片缩小渲染的话,会提高运行效率,并且会提高画质(直接缩小可能某些像素通过11中提到的纹理过滤计算起来会有偏差,但是使用预先缩小的图片就可以达到自己满意的效果)。 而etc1的话在创建图片的时候开启mipmap会多创建n张缩小纹理,对应文件体积就增大了,最大会增加30%~50%。 这个我们看情况使用,部分核心的重要的图片开启mipmap。 加载图片成为mipmap比较简单 glTexImage2D(GL_TEXTURE_2D, 0, s_compressFormat_RGBA, (GLsizei)pixelsWide, (GLsizei)pixelsHigh, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); 这个是提交纹理数据的函数,其中第二是mipmap等级,穿n就对应n级的mipmap,也就是说,如果pkm的etc1图片要支持mipmap,就需要自己写代码,另加载1~n张纹理,然后使用glTexImage2D这个函数把这n张纹理提交给显卡。

13、cocos2d-x中对etc1的支持比较初级。 既没有透明色的支持,也不支持mipmap。
etc1图片格式有两种,一种是pkm,这种是简单的etc1格式,现在cocos2d-x支持的就是这种格式。另外一种是ktx格式,这个是opengles组织提供的官方格式。可以把多个mipmap打包到一个ktx文件里面。 现在我的代码里面使用的就是ktx格式。使用ktx图片需要到这里下载ktx的loader库,把这个库加入到cocos2d-x中,核心加载代码如下

[cpp]

  1. bool CCTextureETC::initWithKtxData(etc1_byte* pData, int len)
  2. {
  3.     GLuint texture = 0;
  4.     GLenum target;
  5.     GLboolean isMipmapped;
  6.     GLenum glerror;
  7.     GLubyte* pKvData;
  8.     unsigned int  kvDataLen;
  9.     KTX_dimensions dimensions;
  10.     KTX_error_code ktxerror;
  11.     KTX_hash_table kvtable;
  12.     GLint sign_s = 1, sign_t = 1;
  13.     ktxerror = ktxLoadTextureM(pData, len, &_name, &target, &dimensions, &isMipmapped, &glerror, &kvDataLen, &pKvData);
  14.     if (KTX_SUCCESS == ktxerror) {
  15.         _width = dimensions.width;
  16.         _height = dimensions.height;
  17.         ktxerror = ktxHashTable_Deserialize(kvDataLen, pKvData, &kvtable);
  18.         if (KTX_SUCCESS == ktxerror) {
  19.             GLubyte* pValue;
  20.             unsigned int valueLen;
  21.             if (KTX_SUCCESS == ktxHashTable_FindValue(kvtable, KTX_ORIENTATION_KEY,
  22.                 &valueLen, (void**)&pValue))
  23.             {
  24.                 char s, t;
  25.                 if (_snscanf((const char*)pValue, valueLen, KTX_ORIENTATION2_FMT, &s, &t) == 2) {
  26.                     if (s == ‘l’) sign_s = -1;
  27.                     if (t == ‘d’) sign_t = -1;
  28.                 }
  29.             }
  30.             ktxHashTable_Destroy(kvtable);
  31.             free(pKvData);
  32.         }
  33.         // 加载成功
  34.         if (isMipmapped) {
  35.             /* Enable bilinear mipmapping */
  36.             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
  37.         } else {
  38.             glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  39.         }
  40.         glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  41.         glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  42.         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  43.                 glBindTexture(target, 0);// 这句很重要,否则会有一些诡异的渲染问题
  44.         return true;
  45.     }
  46.     return false;
  47. }

转载自: http://blog.csdn.net/langresser_king/article/details/9339313

介绍了各种移动设备所使用的GPU,以及各个GPU所支持的压缩纹理的格式和使用方法。

1. 移动GPU大全
目前移动市场的GPU主要有四大厂商系列:

1)Imagination Technologies的PowerVR SGX系列

    

代表型号:PowerVR SGX 535、PowerVR SGX 540、PowerVR SGX 543MP、PowerVR SGX 554MP等
代表作  :Apple iPhone全系、iPad全系,三星I9000、P3100等

2)Qualcomm(高通)的Adreno系列

    

代表型号:Adreno 200、Adreno 205、Adreno 220、Adreno 320等
代表作  :HTC G10、G14,小米1、2等

3)ARM的Mali系列

    

代表型号:Mali-400、Mali-T604等
代表作  :三星Galaxy SII、Galaxy SIII、Galaxy Note1、Galaxy Note2(亚版)等

4)nVIDIA(英伟达)的Tegra系列

    

代表型号:nVIDIA Tegra2、nVIDIA Tegra3等
代表作  :Google Nexus 7,HTC One X等

2. 压缩纹理的必要性
1)首先要说一下图像文件格式和纹理格式的区别。
常用的图像文件格式有BMP,TGA,JPG,GIF,PNG等;
常用的纹理格式有R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等。

文件格式是图像为了存储信息而使用的对信息的特殊编码方式,它存储在磁盘中,或者内存中,但是并不能被GPU所识别,因为以向量计算见长的GPU对于这些复杂的计算无能为力。这些文件格式当被游戏读入后,还是需要经过CPU解压成R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8, A8R8G8B8等像素格式,再传送到GPU端进行使用。
纹理格式是能被GPU所识别的像素格式,能被快速寻址并采样。
举个例子,DDS文件是游戏开发中常用的文件格式,它内部可以包含A4R4G4B4的纹理格式,也可以包含A8R8G8B8的纹理格式,甚至可以包含DXT1的纹理格式。在这里DDS文件有点容器的意味。

OpenGL ES 2.0支持以上提到的R5G6B5,A4R4G4B4,A1R5G5B5,R8G8B8,A8R8G8B8等纹理格式,其中 R5G6B5,A4R4G4B4,A1R5G5B5每个像素占用2个字节(BYTE),R8G8B8每个像素占用3个字节,A8R8G8B8每个像素占用 4个字节。

    

    对于一张512*512的纹理的话,R5G6B5格式的文件需要占用512KB的容量,A8R8G8B8格式的文件需要占用1MB的容量;如果是1024*1024的纹理,则各需要2M和4M的容量,这对于动辄需要几十、几百张甚至更多纹理的游戏,上G容量的游戏在移动平台上是不容易被接受的(当然,还是有1、2G的大作的,里面包含了几千张的纹理)。

聪明的设计师们在想,有没有其他办法,既能表现丰富的色彩和细节,又能是最小失真的情况下,达到更小的纹理容量呢。压缩纹理格式应运而生(当然,并不是在移动平台后才有的产物)。

3. 常见的压缩纹理格式
基于OpenGL ES的压缩纹理有常见的如下几种实现:
1)ETC1(Ericsson texture compression)
2)PVRTC (PowerVR texture compression)
3)ATITC (ATI texture compression)
4)S3TC (S3 texture compression)

ETC1:
ETC1格式是OpenGL ES图形标准的一部分,并且被所有的Android设备所支持。
扩展名为: GL_OES_compressed_ETC1_RGB8_texture,不支持透明通道,所以仅能用于不透明纹理。
当加载压缩纹理时,<internal format>参数支持如下格式:
GL_ETC1_RGB8_OES(RGB,每个像素0.5个字节)

PVRTC:
支持的GPU为Imagination Technologies的PowerVR SGX系列。
OpenGL ES的扩展名为: GL_IMG_texture_compression_pvrtc。
当加载压缩纹理时,<internal format>参数支持如下几种格式:
GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG (RGB,每个像素0.5个字节)
GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG (RGB,每个像素0.25个字节)
GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG (RGBA,每个像素0.5个字节)
GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG (RGBA,每个像素0.25个字节)

ATITC:
支持的GPU为Qualcomm的Adreno系列。
支持的OpenGL ES扩展名为: GL_ATI_texture_compression_atitc。
当加载压缩纹理时,<internal format>参数支持如下类型的纹理:
GL_ATC_RGB_AMD (RGB,每个像素0.5个字节)
GL_ATC_RGBA_EXPLICIT_ALPHA_AMD (RGBA,每个像素1个字节)
GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD (RGBA,每个像素1个字节)

S3TC
也被称为DXTC,在PC上广泛被使用,但是在移动设备上还是属于新鲜事物。支持的GPU为NVIDIA Tegra系列。
OpenGL ES扩展名为:
GL_EXT_texture_compression_dxt1和GL_EXT_texture_compression_s3tc。
当加载压缩纹理时,<internal format>的参数有如下几种格式:
GL_COMPRESSED_RGB_S3TC_DXT1 (RGB,每个像素0.5个字节)
GL_COMPRESSED_RGBA_S3TC_DXT1 (RGBA,每个像素0.5个字节)
GL_COMPRESSED_RGBA_S3TC_DXT3 (RGBA,每个像素1个字节)
GL_COMPRESSED_RGBA_S3TC_DXT5 (RGBA,每个像素1个字节)

由此可见,Mali系列GPU只支持ETC1格式的压缩纹理,而且该纹理不支持透明通道,有一定局限性。
以上压缩纹理格式每个像素大小相对A8R8G8B8格式的比例,最高压缩比是16:1,最低压缩比是4:1,对于减小纹理的数据容量有明显作用,相应在显存带宽上也有明显优势,从而提高游戏的运行效率(此特性没有绝对数值,根据每个游戏的用法和瓶颈点不同而有差别)。

4. OpenGL中相关API的使用

1) 获得GPU的型号

    glGetString(GL_RENDERER)

2) 获得GPU的生产厂商

    glGetString(GL_VENDOR);

3) 获取GPU支持哪些压缩纹理

    string extensions = (const char*)glGetString(GL_EXTENSIONS);

    a. 判断是否支持ETC1格式的压缩纹理

    return (extensions.find(“GL_OES_compressed_ETC1_RGB8_texture”)!= string::npos);

    b. 判断是否支持DXT格式的压缩纹理

    return (extensions.find(“GL_EXT_texture_compression_dxt1”)!= string::npos ||

            extensions.find(“GL_EXT_texture_compression_s3tc”)!= string::npos);

    c. 判断是否支持PVRTC格式的压缩纹理

    return (extensions.find(“GL_IMG_texture_compression_pvrtc”)!= string::npos);

    d. 判断是否支持ATITC格式的压缩纹理

    return (extensions.find(“GL_AMD_compressed_ATC_texture”)!= string::npos ||

            extensions.find(“GL_ATI_texture_compression_atitc”)!= string::npos);

4) 填充压缩纹理数据

    void glCompressedTexImage2D (

         GLenum target,

         GLint level,

         GLenum internalformat,

         GLsizei width,

         GLsizei height,

         GLint border,

         GLsizei imageSize,

         const GLvoid * data);

    这里的参数不做详细解释,其中internalformat即是压缩纹理格式的类型。

5. 压缩纹理工具的使用
每种压缩纹理以及相应的厂商都提供了压缩纹理的工具,工具都分两个版本:
a. 可视化转换工具 (给美工或小白少量使用)
b. 命令行转换工具 (给程序批量使用)

下面对每个工具的用法进行说明。
1)Imagination Technologies PowerVR
工具下载地址
http://www.imgtec.com/powervr/insider/sdkdownloads/index.asp?installer=Windows%20Installer

可视化转换界面

    

命令行转换脚本
for %%i in (*.tga) do PVRTexTool.exe -f PVRTC4 -i %%i
(将本目录下的所有tga文件,转换成”PVRTC4″编码格式的pvr文件,不带mipmap)
详细使用说明:PvrTexTool.exe /?

2)Qualcomm Adreno
工具下载地址
https://developer.qualcomm.com/mobile-development/mobile-technologies/gaming-graphics-optimization-adreno/tools-and-resources

可视化转换界面

    

命令行转换脚本
for %%i in (*.tga) do QCompressCmd.exe %%i %%i.ktx “ATC RGBA Explicit” yes
(将本目录下的所有tga文件,转换成”ATC RGBA Explicit”编码格式的ktx文件,带mipmap)
详细使用说明:QCompressCmd.exe /?

3)ARM Mali
工具下载地址
http://malideveloper.arm.com/develop-for-mali/mali-gpu-texture-compression-tool/

可视化转换界面

    

命令行转换脚本
for %%i in (*.tga) do PVRTexTool.exe -f ETC -i %%i
(将本目录下的所有tga文件,转换成”ETC”编码格式的pvr文件,不带mipmap这里还是使用的PVRTexTool.exe,也可以使用QCompressCmd.exe)
详细使用说明:PVRTexTool.exe /?

4)nVIDIA Tegra
可以使用DirectX SDK中自带的DirectX Texture Tool进行转换
可视化转换界面

    

命令行转换脚本
for %%i in (*.tga) do texconv.exe -f DXT5 %%i
(将本目录下的所有tga文件,转换成”DXT5″编码格式的dds文件,不带mipmap)
详细使用说明:TexConv.exe /?

转载自: http://www.cnblogs.com/luming1979/archive/2013/02/04/2891421.html

一、最简单的方法,使用QT自带的命令:

macdeployqt appname.app/ -verbose=1 -dmg

二、

1、查看程序中依赖的库

终端中运行 otool -L appname.app/contents/MacOS/appname

2、拷贝非系统自带的库,如QtCore

cp -R /Library/Frameworks/QtCore.framework appname.app/Contents/Frameworks/

3、改变路径

install_name_tool -id @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore appname.app/Contents/Frameworks/QtCore.framework/Versions/4/QtCore

install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore appname.app/Contents/MacOS/appname
如果有些库还依赖其他库时,也要改变此库中的依赖库路径,不然运行时也有问题的
转自:http://blog.csdn.net/weiren2006/article/details/6547039

文章目录

使用了Submine Text的同学,有件事情可能困扰着你。如果Submine Text有新版更新,每次打开它的时候就会弹出一个框框,问你要不要更新。鉴于某种不齿的原因,很多同学不会去更新。我也是这样的同学,哈哈。

工具/原料

  • Submine Text

方法/步骤

  1. 1

    打开Submine Text,找到Preferences -> Settings-User

  2. 2

    打开后类似这样

  3. 3

    在最后的花括号(“}”)前添加一句:”update_check”:false。

    如果你的配置文件和我一样,有多条配置信息,你必须多加一个英文逗号(,)。

    像这样 ,”update_check”:false

  4. 4

    下次打开Submine Text,就不会再弹出更新提醒了。

    END

注意事项

  • 如果你的配置文件里面已经有其他配置信息,在”update_check”:false的上一句,应该加一个英文逗号(,)。(配置文件使用的json语法)

 转载自:http://jingyan.baidu.com/article/ca00d56c8988f1e99eebcf06.html

方法一:
解决方法很简单:
打开/Applications/Qt5.3.2/5.3/clang_64/mkspecs/qdevice.pri文件, 把下面的这句:
!host_build:QMAKE_MAC_SDK = macosx10.8
改成
!host_build:QMAKE_MAC_SDK = macosx10.9
就可以了。

方法二:
export SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk